mithril_rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)