mithril_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/javascripts/JSXTransformer.js +12508 -0
  6. data/app/assets/javascripts/mithril.js +454 -0
  7. data/lib/mithril_rails.rb +2 -0
  8. data/lib/mithril_rails/msx.rb +31 -0
  9. data/lib/mithril_rails/msx/template.rb +17 -0
  10. data/lib/mithril_rails/rails.rb +2 -0
  11. data/lib/mithril_rails/rails/engine.rb +9 -0
  12. data/lib/mithril_rails/rails/railtie.rb +10 -0
  13. data/lib/mithril_rails/version.rb +3 -0
  14. data/test/dummy/README.rdoc +28 -0
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/javascripts/application.js +13 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  18. data/test/dummy/app/controllers/application_controller.rb +5 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/test/dummy/bin/bundle +3 -0
  22. data/test/dummy/bin/rails +4 -0
  23. data/test/dummy/bin/rake +4 -0
  24. data/test/dummy/config.ru +4 -0
  25. data/test/dummy/config/application.rb +23 -0
  26. data/test/dummy/config/boot.rb +5 -0
  27. data/test/dummy/config/database.yml +25 -0
  28. data/test/dummy/config/environment.rb +5 -0
  29. data/test/dummy/config/environments/development.rb +37 -0
  30. data/test/dummy/config/environments/production.rb +83 -0
  31. data/test/dummy/config/environments/test.rb +39 -0
  32. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  33. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  34. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  35. data/test/dummy/config/initializers/inflections.rb +16 -0
  36. data/test/dummy/config/initializers/mime_types.rb +4 -0
  37. data/test/dummy/config/initializers/session_store.rb +3 -0
  38. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  39. data/test/dummy/config/locales/en.yml +23 -0
  40. data/test/dummy/config/routes.rb +56 -0
  41. data/test/dummy/config/secrets.yml +22 -0
  42. data/test/dummy/public/404.html +67 -0
  43. data/test/dummy/public/422.html +67 -0
  44. data/test/dummy/public/500.html +66 -0
  45. data/test/dummy/public/favicon.ico +0 -0
  46. data/test/mithril_rails_test.rb +7 -0
  47. data/test/test_helper.rb +15 -0
  48. metadata +167 -0
@@ -0,0 +1,454 @@
1
+ new function(window) {
2
+ var selectorCache = {}
3
+ var type = {}.toString
4
+ var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.+?)\2)?\]/
5
+
6
+ Mithril = m = function() {
7
+ var args = arguments
8
+ var hasAttrs = type.call(args[1]) == "[object Object]"
9
+ var attrs = hasAttrs ? args[1] : {}
10
+ var classAttrName = "class" in attrs ? "class" : "className"
11
+ var cell = selectorCache[args[0]]
12
+ if (cell === undefined) {
13
+ selectorCache[args[0]] = cell = {tag: "div", attrs: {}}
14
+ var match, classes = []
15
+ while (match = parser.exec(args[0])) {
16
+ if (match[1] == "") cell.tag = match[2]
17
+ else if (match[1] == "#") cell.attrs.id = match[2]
18
+ else if (match[1] == ".") classes.push(match[2])
19
+ else if (match[3][0] == "[") {
20
+ var pair = attrParser.exec(match[3])
21
+ cell.attrs[pair[1]] = pair[3] || true
22
+ }
23
+ }
24
+ if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ")
25
+ }
26
+ cell = clone(cell)
27
+ cell.attrs = clone(cell.attrs)
28
+ cell.children = hasAttrs ? args[2] : args[1]
29
+ for (var attrName in attrs) {
30
+ if (attrName == classAttrName) cell.attrs[attrName] = (cell.attrs[attrName] || "") + " " + attrs[attrName]
31
+ else cell.attrs[attrName] = attrs[attrName]
32
+ }
33
+ return cell
34
+ }
35
+ function build(parent, data, cached, shouldReattach, index, namespace) {
36
+ if (data === null || data === undefined) {
37
+ if (cached) clear(cached.nodes)
38
+ return
39
+ }
40
+ if (data.subtree === "retain") return
41
+
42
+ var cachedType = type.call(cached), dataType = type.call(data)
43
+ if (cachedType != dataType) {
44
+ if (cached !== null && cached !== undefined) clear(cached.nodes)
45
+ cached = new data.constructor
46
+ cached.nodes = []
47
+ }
48
+
49
+ if (dataType == "[object Array]") {
50
+ var nodes = [], intact = cached.length === data.length, subArrayCount = 0
51
+ for (var i = 0; i < data.length; i++) {
52
+ var item = build(parent, data[i], cached[i], shouldReattach, index + subArrayCount || subArrayCount, namespace)
53
+ if (item === undefined) continue
54
+ if (!item.nodes.intact) intact = false
55
+ subArrayCount += item instanceof Array ? item.length : 1
56
+ cached[i] = item
57
+ }
58
+ if (!intact) {
59
+ for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
60
+ for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
61
+ for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node)
62
+ cached.length = data.length
63
+ cached.nodes = nodes
64
+ }
65
+ }
66
+ else if (dataType == "[object Object]") {
67
+ if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join()) clear(cached.nodes)
68
+ if (typeof data.tag != "string") return
69
+
70
+ var node, isNew = cached.nodes.length === 0
71
+ if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg"
72
+ if (isNew) {
73
+ node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag)
74
+ cached = {
75
+ tag: data.tag,
76
+ attrs: setAttributes(node, data.attrs, {}, namespace),
77
+ children: build(node, data.children, cached.children, true, index, namespace),
78
+ nodes: [node]
79
+ }
80
+ parent.insertBefore(node, index !== undefined ? parent.childNodes[index] : null)
81
+ }
82
+ else {
83
+ node = cached.nodes[0]
84
+ setAttributes(node, data.attrs, cached.attrs, namespace)
85
+ cached.children = build(node, data.children, cached.children, false, index, namespace)
86
+ cached.nodes.intact = true
87
+ if (shouldReattach === true) parent.insertBefore(node, index !== undefined ? parent.childNodes[index] : null)
88
+ }
89
+ if (type.call(data.attrs["config"]) == "[object Function]") data.attrs["config"](node, !isNew)
90
+ }
91
+ else {
92
+ var node
93
+ if (cached.nodes.length === 0) {
94
+ if (data.$trusted) {
95
+ var lastChild = parent.lastChild
96
+ parent.insertAdjacentHTML("beforeend", data)
97
+ node = lastChild ? lastChild.nextSibling : parent.firstChild
98
+ }
99
+ else {
100
+ node = window.document.createTextNode(data)
101
+ parent.insertBefore(node, index !== undefined ? parent.childNodes[index] : null)
102
+ }
103
+ cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data
104
+ cached.nodes = [node]
105
+ }
106
+ else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
107
+ if (data.$trusted) {
108
+ var current = cached.nodes[0], nodes = [current]
109
+ if (current) {
110
+ while (current = current.nextSibling) nodes.push(current)
111
+ clear(nodes)
112
+ var lastChild = parent.lastChild
113
+ parent.insertAdjacentHTML("beforeend", data)
114
+ node = lastChild ? lastChild.nextSibling : parent.firstChild
115
+ }
116
+ else parent.innerHTML = data
117
+ }
118
+ else {
119
+ node = cached.nodes[0]
120
+ parent.insertBefore(node, index !== undefined ? parent.childNodes[index] : null)
121
+ node.nodeValue = data
122
+ }
123
+ cached = new data.constructor(data)
124
+ cached.nodes = [node]
125
+ }
126
+ else cached.nodes.intact = true
127
+ }
128
+
129
+ return cached
130
+ }
131
+ function setAttributes(node, dataAttrs, cachedAttrs, namespace) {
132
+ for (var attrName in dataAttrs) {
133
+ var dataAttr = dataAttrs[attrName]
134
+ var cachedAttr = cachedAttrs[attrName]
135
+ if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || node === window.document.activeElement) {
136
+ cachedAttrs[attrName] = dataAttr
137
+ if (attrName === "config") continue
138
+ else if (typeof dataAttr == "function" && attrName.indexOf("on") == 0) {
139
+ node[attrName] = autoredraw(dataAttr, node)
140
+ }
141
+ else if (attrName === "style") {
142
+ for (var rule in dataAttr) {
143
+ if (cachedAttr === undefined || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]
144
+ }
145
+ }
146
+ else if (namespace !== undefined) {
147
+ if (attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr)
148
+ else if (attrName === "className") node.setAttribute("class", dataAttr)
149
+ else node.setAttribute(attrName, dataAttr)
150
+ }
151
+ else if (attrName in node) node[attrName] = dataAttr
152
+ else node.setAttribute(attrName, dataAttr)
153
+ }
154
+ }
155
+ return cachedAttrs
156
+ }
157
+ function clear(nodes) {
158
+ for (var i = 0; i < nodes.length; i++) nodes[i].parentNode.removeChild(nodes[i])
159
+ nodes.length = 0
160
+ }
161
+ function clone(object) {
162
+ var result = {}
163
+ for (var prop in object) result[prop] = object[prop]
164
+ return result
165
+ }
166
+ function autoredraw(callback, object) {
167
+ return function(e) {
168
+ m.startComputation()
169
+ var output = callback.call(object, e)
170
+ m.endComputation()
171
+ return output
172
+ }
173
+ }
174
+
175
+ var html
176
+ var documentNode = {
177
+ insertAdjacentHTML: function(_, data) {
178
+ window.document.write(data)
179
+ window.document.close()
180
+ },
181
+ appendChild: function(node) {
182
+ if (html === undefined) html = window.document.createElement("html")
183
+ if (node.nodeName == "HTML") html = node
184
+ else html.appendChild(node)
185
+ if (window.document.documentElement !== html) {
186
+ window.document.replaceChild(html, window.document.documentElement)
187
+ }
188
+ },
189
+ insertBefore: function(node, reference) {
190
+ this.appendChild(node)
191
+ },
192
+ childNodes: []
193
+ }
194
+ var nodeCache = [], cellCache = {}
195
+ m.render = function(root, cell) {
196
+ var index = nodeCache.indexOf(root)
197
+ var id = index < 0 ? nodeCache.push(root) - 1 : index
198
+ var node = root == window.document || root == window.document.documentElement ? documentNode : root
199
+ cellCache[id] = build(node, cell, cellCache[id], false, 0)
200
+ }
201
+
202
+ m.trust = function(value) {
203
+ value = new String(value)
204
+ value.$trusted = true
205
+ return value
206
+ }
207
+
208
+ var currentRoot, currentModule = {view: function() {}}, currentController = {}, now = 0, lastRedraw = 0, lastRedrawId = 0
209
+ m.module = function(root, module) {
210
+ m.startComputation()
211
+ currentRoot = root
212
+ currentModule = module
213
+ currentController = new module.controller
214
+ m.endComputation()
215
+ }
216
+ m.redraw = function() {
217
+ m.render(currentRoot, currentModule.view(currentController))
218
+ lastRedraw = now
219
+ }
220
+ function redraw() {
221
+ now = window.performance && window.performance.now ? window.performance.now() : new window.Date().getTime()
222
+ if (now - lastRedraw > 16) m.redraw()
223
+ else {
224
+ var cancel = window.cancelAnimationFrame || window.clearTimeout
225
+ var defer = window.requestAnimationFrame || window.setTimeout
226
+ cancel(lastRedrawId)
227
+ lastRedrawId = defer(m.redraw, 0)
228
+ }
229
+ }
230
+
231
+ var pendingRequests = 0, computePostRedrawHook = null
232
+ m.startComputation = function() {pendingRequests++}
233
+ m.endComputation = function() {
234
+ pendingRequests = Math.max(pendingRequests - 1, 0)
235
+ if (pendingRequests == 0) {
236
+ redraw()
237
+ if (computePostRedrawHook) {
238
+ computePostRedrawHook()
239
+ computePostRedrawHook = null
240
+ }
241
+ }
242
+ }
243
+
244
+ m.withAttr = function(prop, withAttrCallback) {
245
+ return function(e) {withAttrCallback(prop in e.currentTarget ? e.currentTarget[prop] : e.currentTarget.getAttribute(prop))}
246
+ }
247
+
248
+ //routing
249
+ var modes = {pathname: "", hash: "#", search: "?"}
250
+ var redirect = function() {}, routeParams = {}
251
+ m.route = function() {
252
+ if (arguments.length == 3) {
253
+ var root = arguments[0], defaultRoute = arguments[1], router = arguments[2]
254
+ redirect = function(source) {
255
+ var path = source.slice(modes[m.route.mode].length)
256
+ if (!routeByValue(root, router, path)) {
257
+ m.route(defaultRoute, true)
258
+ }
259
+ }
260
+ var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate"
261
+ window[listener] = function() {
262
+ redirect(window.location[m.route.mode])
263
+ }
264
+ computePostRedrawHook = scrollToHash
265
+ window[listener]()
266
+ }
267
+ else if (arguments[0].addEventListener) {
268
+ var element = arguments[0]
269
+ var isInitialized = arguments[1]
270
+ if (!isInitialized) {
271
+ element.removeEventListener("click", routeUnobtrusive)
272
+ element.addEventListener("click", routeUnobtrusive)
273
+ }
274
+ }
275
+ else if (typeof arguments[0] == "string") {
276
+ var route = arguments[0]
277
+ var shouldReplaceHistoryEntry = arguments[1] === true
278
+ if (window.history.pushState) {
279
+ computePostRedrawHook = function() {
280
+ window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + route)
281
+ scrollToHash()
282
+ }
283
+ redirect(modes[m.route.mode] + route)
284
+ }
285
+ else window.location[m.route.mode] = route
286
+ }
287
+ }
288
+ m.route.param = function(key) {return routeParams[key]}
289
+ m.route.mode = "search"
290
+ function routeByValue(root, router, path) {
291
+ routeParams = {}
292
+ for (var route in router) {
293
+ if (route == path) return !void m.module(root, router[route])
294
+
295
+ var matcher = new RegExp("^" + route.replace(/:[^\/]+/g, "([^\\/]+)") + "$")
296
+ if (matcher.test(path)) {
297
+ return !void path.replace(matcher, function() {
298
+ var keys = route.match(/:[^\/]+/g)
299
+ var values = [].slice.call(arguments, 1, -2)
300
+ for (var i = 0; i < keys.length; i++) routeParams[keys[i].slice(1)] = values[i]
301
+ m.module(root, router[route])
302
+ })
303
+ }
304
+ }
305
+ }
306
+ function routeUnobtrusive(e) {
307
+ e.preventDefault()
308
+ m.route(e.currentTarget.getAttribute("href"))
309
+ }
310
+ function scrollToHash() {
311
+ if (m.route.mode != "hash" && window.location.hash) window.location.hash = window.location.hash
312
+ }
313
+
314
+ //model
315
+ m.prop = function(store) {
316
+ return function() {
317
+ if (arguments.length) store = arguments[0]
318
+ return store
319
+ }
320
+ }
321
+
322
+ m.deferred = function() {
323
+ var resolvers = [], rejecters = []
324
+ var object = {
325
+ resolve: function(value) {
326
+ for (var i = 0; i < resolvers.length; i++) resolvers[i](value)
327
+ },
328
+ reject: function(value) {
329
+ for (var i = 0; i < rejecters.length; i++) rejecters[i](value)
330
+ },
331
+ promise: m.prop()
332
+ }
333
+ object.promise.resolvers = resolvers
334
+ object.promise.then = function(success, error) {
335
+ var next = m.deferred()
336
+ if (!success) success = identity
337
+ if (!error) error = identity
338
+ function push(list, method, callback) {
339
+ list.push(function(value) {
340
+ try {
341
+ var result = callback(value)
342
+ if (result && typeof result.then == "function") result.then(next[method], error)
343
+ else next[method](result !== undefined ? result : value)
344
+ }
345
+ catch (e) {
346
+ if (e instanceof Error && e.constructor !== Error) throw e
347
+ else next.reject(e)
348
+ }
349
+ })
350
+ }
351
+ push(resolvers, "resolve", success)
352
+ push(rejecters, "reject", error)
353
+ return next.promise
354
+ }
355
+ return object
356
+ }
357
+ m.sync = function(args) {
358
+ var method = "resolve"
359
+ function synchronizer(resolved) {
360
+ return function(value) {
361
+ results.push(value)
362
+ if (!resolved) method = "reject"
363
+ if (results.length == args.length) {
364
+ deferred.promise(results)
365
+ deferred[method](results)
366
+ }
367
+ return value
368
+ }
369
+ }
370
+
371
+ var deferred = m.deferred()
372
+ var results = []
373
+ for (var i = 0; i < args.length; i++) {
374
+ args[i].then(synchronizer(true), synchronizer(false))
375
+ }
376
+ return deferred.promise
377
+ }
378
+ function identity(value) {return value}
379
+
380
+ function ajax(options) {
381
+ var xhr = window.XDomainRequest ? new window.XDomainRequest : new window.XMLHttpRequest
382
+ xhr.open(options.method, options.url, true, options.user, options.password)
383
+ xhr.onload = typeof options.onload == "function" ? options.onload : function() {}
384
+ xhr.onerror = typeof options.onerror == "function" ? options.onerror : function() {}
385
+ if (typeof options.config == "function") options.config(xhr, options)
386
+ xhr.send(options.data)
387
+ return xhr
388
+ }
389
+ function querystring(object, prefix) {
390
+ var str = []
391
+ for(var prop in object) {
392
+ var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop]
393
+ str.push(typeof value == "object" ? querystring(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
394
+ }
395
+ return str.join("&")
396
+ }
397
+ function bindData(xhrOptions, data, serialize) {
398
+ if (data && Object.keys(data).length > 0) {
399
+ if (xhrOptions.method == "GET") {
400
+ xhrOptions.url = xhrOptions.url + (xhrOptions.url.indexOf("?") < 0 ? "?" : "&") + querystring(data)
401
+ }
402
+ else xhrOptions.data = serialize(data)
403
+ }
404
+ return xhrOptions
405
+ }
406
+ function parameterizeUrl(url, data) {
407
+ var tokens = url.match(/:[a-z]\w+/gi)
408
+ if (tokens && data) {
409
+ for (var i = 0; i < tokens.length; i++) {
410
+ var key = tokens[i].slice(1)
411
+ url = url.replace(tokens[i], data[key])
412
+ delete data[key]
413
+ }
414
+ }
415
+ return url
416
+ }
417
+
418
+ m.request = function(xhrOptions) {
419
+ m.startComputation()
420
+ var deferred = m.deferred()
421
+ var serialize = xhrOptions.serialize || JSON.stringify
422
+ var deserialize = xhrOptions.deserialize || JSON.parse
423
+ xhrOptions.url = parameterizeUrl(xhrOptions.url, xhrOptions.data)
424
+ xhrOptions = bindData(xhrOptions, xhrOptions.data, serialize)
425
+ xhrOptions.onload = xhrOptions.onerror = function(e) {
426
+ var unwrap = (e.type == "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity
427
+ var response = unwrap(deserialize(e.target.responseText))
428
+ if (response instanceof Array && xhrOptions.type) {
429
+ for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
430
+ }
431
+ else if (xhrOptions.type) response = new xhrOptions.type(response)
432
+ deferred.promise(response)
433
+ deferred[e.type == "load" ? "resolve" : "reject"](response)
434
+ m.endComputation()
435
+ }
436
+ ajax(xhrOptions)
437
+ deferred.promise.then = propBinder(deferred.promise)
438
+ return deferred.promise
439
+ }
440
+ function propBinder(promise) {
441
+ var bind = promise.then
442
+ return function(success, error) {
443
+ var next = bind(function(value) {return next(success(value))}, function(value) {return next(error(value))})
444
+ next.then = propBinder(next)
445
+ return next
446
+ }
447
+ }
448
+
449
+ if (typeof module != "undefined" && module !== null) module.exports = m
450
+ if (typeof define == "function" && define.amd) define(function() {return m})
451
+
452
+ //testing API
453
+ m.deps = function(mock) {return window = mock}
454
+ }(this)