rbbt-rest 1.6.3 → 1.6.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: adfb3bb568b61a43b82dab68a49bb59b059a5dec
4
- data.tar.gz: 88b212ef91fa81098b35268b365006aa7ffd2bab
3
+ metadata.gz: aed841136faa280e2bf8db43c2492601ab9672f1
4
+ data.tar.gz: 6ae31d8f2cc7daa05441de9806f86516810eee44
5
5
  SHA512:
6
- metadata.gz: 13ca0d58a8b9f7b07028699348e5a4f00a8e10e29a2ced1b3e986fb0b10629cc96843af1045c799a330d7af5278a983e2e5d6d8b523c7897188ea731db029fed
7
- data.tar.gz: 2e7d6741d5cd079dee1791739abdaaeb37fd766089faf6f5af07740de0ebf82c1d1d01a8431d38a7e0ffed54b53af16d66f787eb1addd5cbb3eae7617b3235f1
6
+ metadata.gz: 543608149f8869ffce73a5b831a40dbafbcf1196306348f22c063bd2f5c9b1bb929eea3b08c3c8ad87dcc52e4368ed869800f566c26934e3567fc6274913c58a
7
+ data.tar.gz: 36e89360ad4e3a4df1f1ba01af438d976858893644d6e59434c451c786c7265568fa1226754a9ca684d6fc4350857d9c70a2a11b59b6a94705f2a659ec8bc5ac
@@ -177,7 +177,18 @@ module Sinatra
177
177
  workflow_render('job_info', workflow, task, :info => job.info)
178
178
  when :json
179
179
  content_type "application/json"
180
- job.info.to_json
180
+ info_json = {}
181
+ job.info.each do |k,v|
182
+ info_json[k] = case v.to_s
183
+ when "NaN"
184
+ "NaN"
185
+ when "Infinity"
186
+ "Infinity"
187
+ else
188
+ v
189
+ end
190
+ end
191
+ halt 200, info_json.to_json
181
192
  else
182
193
  raise "Unsupported format specified: #{ format }"
183
194
  end
@@ -196,6 +196,9 @@ module WorkflowRESTHelpers
196
196
  job_url = to(File.join("/", workflow.to_s, task, job.name))
197
197
  job_url += "?_format=#{@format}" if @format
198
198
  if format == :jobname
199
+ while not File.exists? job.info_file
200
+ sleep 1
201
+ end
199
202
  content_type :text
200
203
  job.name
201
204
  else
@@ -1,5 +1,5 @@
1
- = link_js "http://cdnjs.cloudflare.com/ajax/libs/mithril/0.1.28/mithril.min.js"
2
1
  = serve_js
2
+
3
3
  :javascript
4
4
  var main_url = window.location.toString();
5
5
  var production = #{production? ? "true" : "false"};
@@ -9,6 +9,8 @@
9
9
  $(this).toggleClass('show')
10
10
  })
11
11
 
12
+ requirejs.config({baseUrl: '/js-find'})
13
+
12
14
  start_deferred()
13
15
 
14
16
  - if @reload_page
@@ -25,11 +25,12 @@
25
25
 
26
26
  // Third party frameworks
27
27
 
28
+ - record_js '/plugins/mithril/js/mithril.js'
29
+ - record_js "/plugins/requirejs/js/require.js"
28
30
  - record_js '/js/defer'
29
- - record_js "/plugins/underscore/js/underscore.js"
30
-
31
31
  = serve_js
32
32
 
33
+
33
34
  - %w(jquery-2.1.1 jquery.cookie jquery.form).each do |jquery_file|
34
35
  - record_js File.join('/plugins/jquery/js/', jquery_file)
35
36
 
@@ -0,0 +1,1024 @@
1
+ var m = (function app(window, undefined) {
2
+ var OBJECT = "[object Object]", ARRAY = "[object Array]", STRING = "[object String]", FUNCTION = "function";
3
+ var type = {}.toString;
4
+ var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/;
5
+ var voidElements = /^(AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR)$/;
6
+
7
+ // caching commonly used variables
8
+ var $document, $location, $requestAnimationFrame, $cancelAnimationFrame;
9
+
10
+ // self invoking function needed because of the way mocks work
11
+ function initialize(window){
12
+ $document = window.document;
13
+ $location = window.location;
14
+ $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
15
+ $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;
16
+ }
17
+
18
+ initialize(window);
19
+
20
+
21
+ /**
22
+ * @typedef {String} Tag
23
+ * A string that looks like -> div.classname#id[param=one][param2=two]
24
+ * Which describes a DOM node
25
+ */
26
+
27
+ /**
28
+ *
29
+ * @param {Tag} The DOM node tag
30
+ * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs
31
+ * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array, or splat (optional)
32
+ *
33
+ */
34
+ function m() {
35
+ var args = [].slice.call(arguments);
36
+ var hasAttrs = args[1] != null && type.call(args[1]) === OBJECT && !("tag" in args[1]) && !("subtree" in args[1]);
37
+ var attrs = hasAttrs ? args[1] : {};
38
+ var classAttrName = "class" in attrs ? "class" : "className";
39
+ var cell = {tag: "div", attrs: {}};
40
+ var match, classes = [];
41
+ if (type.call(args[0]) != STRING) throw new Error("selector in m(selector, attrs, children) should be a string")
42
+ while (match = parser.exec(args[0])) {
43
+ if (match[1] === "" && match[2]) cell.tag = match[2];
44
+ else if (match[1] === "#") cell.attrs.id = match[2];
45
+ else if (match[1] === ".") classes.push(match[2]);
46
+ else if (match[3][0] === "[") {
47
+ var pair = attrParser.exec(match[3]);
48
+ cell.attrs[pair[1]] = pair[3] || (pair[2] ? "" :true)
49
+ }
50
+ }
51
+ if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ");
52
+
53
+
54
+ var children = hasAttrs ? args[2] : args[1];
55
+ if (type.call(children) === ARRAY) {
56
+ cell.children = children
57
+ }
58
+ else {
59
+ cell.children = hasAttrs ? args.slice(2) : args.slice(1)
60
+ }
61
+
62
+ for (var attrName in attrs) {
63
+ if (attrName === classAttrName) {
64
+ if (attrs[attrName] !== "") cell.attrs[attrName] = (cell.attrs[attrName] || "") + " " + attrs[attrName];
65
+ }
66
+ else cell.attrs[attrName] = attrs[attrName]
67
+ }
68
+ return cell
69
+ }
70
+ function build(parentElement, parentTag, parentCache, parentIndex, data, cached, shouldReattach, index, editable, namespace, configs) {
71
+ //`build` is a recursive function that manages creation/diffing/removal of DOM elements based on comparison between `data` and `cached`
72
+ //the diff algorithm can be summarized as this:
73
+ //1 - compare `data` and `cached`
74
+ //2 - if they are different, copy `data` to `cached` and update the DOM based on what the difference is
75
+ //3 - recursively apply this algorithm for every array and for the children of every virtual element
76
+
77
+ //the `cached` data structure is essentially the same as the previous redraw's `data` data structure, with a few additions:
78
+ //- `cached` always has a property called `nodes`, which is a list of DOM elements that correspond to the data represented by the respective virtual element
79
+ //- in order to support attaching `nodes` as a property of `cached`, `cached` is *always* a non-primitive object, i.e. if the data was a string, then cached is a String instance. If data was `null` or `undefined`, cached is `new String("")`
80
+ //- `cached also has a `configContext` property, which is the state storage object exposed by config(element, isInitialized, context)
81
+ //- when `cached` is an Object, it represents a virtual element; when it's an Array, it represents a list of elements; when it's a String, Number or Boolean, it represents a text node
82
+
83
+ //`parentElement` is a DOM element used for W3C DOM API calls
84
+ //`parentTag` is only used for handling a corner case for textarea values
85
+ //`parentCache` is used to remove nodes in some multi-node cases
86
+ //`parentIndex` and `index` are used to figure out the offset of nodes. They're artifacts from before arrays started being flattened and are likely refactorable
87
+ //`data` and `cached` are, respectively, the new and old nodes being diffed
88
+ //`shouldReattach` is a flag indicating whether a parent node was recreated (if so, and if this node is reused, then this node must reattach itself to the new parent)
89
+ //`editable` is a flag that indicates whether an ancestor is contenteditable
90
+ //`namespace` indicates the closest HTML namespace as it cascades down from an ancestor
91
+ //`configs` is a list of config functions to run after the topmost `build` call finishes running
92
+
93
+ //there's logic that relies on the assumption that null and undefined data are equivalent to empty strings
94
+ //- this prevents lifecycle surprises from procedural helpers that mix implicit and explicit return statements (e.g. function foo() {if (cond) return m("div")}
95
+ //- it simplifies diffing code
96
+ //data.toString() is null if data is the return value of Console.log in Firefox
97
+ if (data == null || data.toString() == null) data = "";
98
+ if (data.subtree === "retain") return cached;
99
+ var cachedType = type.call(cached), dataType = type.call(data);
100
+ if (cached == null || cachedType !== dataType) {
101
+ if (cached != null) {
102
+ if (parentCache && parentCache.nodes) {
103
+ var offset = index - parentIndex;
104
+ var end = offset + (dataType === ARRAY ? data : cached.nodes).length;
105
+ clear(parentCache.nodes.slice(offset, end), parentCache.slice(offset, end))
106
+ }
107
+ else if (cached.nodes) clear(cached.nodes, cached)
108
+ }
109
+ cached = new data.constructor;
110
+ if (cached.tag) cached = {}; //if constructor creates a virtual dom element, use a blank object as the base cached node instead of copying the virtual el (#277)
111
+ cached.nodes = []
112
+ }
113
+
114
+ if (dataType === ARRAY) {
115
+ //recursively flatten array
116
+ for (var i = 0, len = data.length; i < len; i++) {
117
+ if (type.call(data[i]) === ARRAY) {
118
+ data = data.concat.apply([], data);
119
+ i-- //check current index again and flatten until there are no more nested arrays at that index
120
+ }
121
+ }
122
+
123
+ var nodes = [], intact = cached.length === data.length, subArrayCount = 0;
124
+
125
+ //keys algorithm: sort elements without recreating them if keys are present
126
+ //1) create a map of all existing keys, and mark all for deletion
127
+ //2) add new keys to map and mark them for addition
128
+ //3) if key exists in new list, change action from deletion to a move
129
+ //4) for each key, handle its corresponding action as marked in previous steps
130
+ //5) copy unkeyed items into their respective gaps
131
+ var DELETION = 1, INSERTION = 2 , MOVE = 3;
132
+ var existing = {}, unkeyed = [], shouldMaintainIdentities = false;
133
+ for (var i = 0; i < cached.length; i++) {
134
+ if (cached[i] && cached[i].attrs && cached[i].attrs.key != null) {
135
+ shouldMaintainIdentities = true;
136
+ existing[cached[i].attrs.key] = {action: DELETION, index: i}
137
+ }
138
+ }
139
+ if (shouldMaintainIdentities) {
140
+ if (data.indexOf(null) > -1) data = data.filter(function(x) {return x != null})
141
+
142
+ var keysDiffer = false
143
+ if (data.length != cached.length) keysDiffer = true
144
+ else for (var i = 0, cachedCell, dataCell; cachedCell = cached[i], dataCell = data[i]; i++) {
145
+ if (cachedCell.attrs && dataCell.attrs && cachedCell.attrs.key != dataCell.attrs.key) {
146
+ keysDiffer = true
147
+ break
148
+ }
149
+ }
150
+
151
+ if (keysDiffer) {
152
+ for (var i = 0, len = data.length; i < len; i++) {
153
+ if (data[i] && data[i].attrs) {
154
+ if (data[i].attrs.key != null) {
155
+ var key = data[i].attrs.key;
156
+ if (!existing[key]) existing[key] = {action: INSERTION, index: i};
157
+ else existing[key] = {
158
+ action: MOVE,
159
+ index: i,
160
+ from: existing[key].index,
161
+ element: cached.nodes[existing[key].index] || $document.createElement("div")
162
+ }
163
+ }
164
+ else unkeyed.push({index: i, element: parentElement.childNodes[i] || $document.createElement("div")})
165
+ }
166
+ }
167
+ var actions = []
168
+ for (var prop in existing) actions.push(existing[prop])
169
+ var changes = actions.sort(sortChanges);
170
+ var newCached = new Array(cached.length)
171
+
172
+ for (var i = 0, change; change = changes[i]; i++) {
173
+ if (change.action === DELETION) {
174
+ clear(cached[change.index].nodes, cached[change.index]);
175
+ newCached.splice(change.index, 1)
176
+ }
177
+ if (change.action === INSERTION) {
178
+ var dummy = $document.createElement("div");
179
+ dummy.key = data[change.index].attrs.key;
180
+ parentElement.insertBefore(dummy, parentElement.childNodes[change.index] || null);
181
+ newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]})
182
+ }
183
+
184
+ if (change.action === MOVE) {
185
+ if (parentElement.childNodes[change.index] !== change.element && change.element !== null) {
186
+ parentElement.insertBefore(change.element, parentElement.childNodes[change.index] || null)
187
+ }
188
+ newCached[change.index] = cached[change.from]
189
+ }
190
+ }
191
+ for (var i = 0, len = unkeyed.length; i < len; i++) {
192
+ var change = unkeyed[i];
193
+ parentElement.insertBefore(change.element, parentElement.childNodes[change.index] || null);
194
+ newCached[change.index] = cached[change.index]
195
+ }
196
+ cached = newCached;
197
+ cached.nodes = new Array(parentElement.childNodes.length);
198
+ for (var i = 0, child; child = parentElement.childNodes[i]; i++) cached.nodes[i] = child
199
+ }
200
+ }
201
+ //end key algorithm
202
+
203
+ for (var i = 0, cacheCount = 0, len = data.length; i < len; i++) {
204
+ //diff each item in the array
205
+ var item = build(parentElement, parentTag, cached, index, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, editable, namespace, configs);
206
+ if (item === undefined) continue;
207
+ if (!item.nodes.intact) intact = false;
208
+ if (item.$trusted) {
209
+ //fix offset of next element if item was a trusted string w/ more than one html element
210
+ //the first clause in the regexp matches elements
211
+ //the second clause (after the pipe) matches text nodes
212
+ subArrayCount += (item.match(/<[^\/]|\>\s*[^<]/g) || []).length
213
+ }
214
+ else subArrayCount += type.call(item) === ARRAY ? item.length : 1;
215
+ cached[cacheCount++] = item
216
+ }
217
+ if (!intact) {
218
+ //diff the array itself
219
+
220
+ //update the list of DOM nodes by collecting the nodes from each item
221
+ for (var i = 0, len = data.length; i < len; i++) {
222
+ if (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes)
223
+ }
224
+ //remove items from the end of the array if the new array is shorter than the old one
225
+ //if errors ever happen here, the issue is most likely a bug in the construction of the `cached` data structure somewhere earlier in the program
226
+ for (var i = 0, node; node = cached.nodes[i]; i++) {
227
+ if (node.parentNode != null && nodes.indexOf(node) < 0) clear([node], [cached[i]])
228
+ }
229
+ if (data.length < cached.length) cached.length = data.length;
230
+ cached.nodes = nodes
231
+ }
232
+ }
233
+ else if (data != null && dataType === OBJECT) {
234
+ if (!data.attrs) data.attrs = {};
235
+ if (!cached.attrs) cached.attrs = {};
236
+
237
+ var dataAttrKeys = Object.keys(data.attrs)
238
+ var hasKeys = dataAttrKeys.length > ("key" in data.attrs ? 1 : 0)
239
+ //if an element is different enough from the one in cache, recreate it
240
+ if (data.tag != cached.tag || dataAttrKeys.join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) {
241
+ if (cached.nodes.length) clear(cached.nodes);
242
+ if (cached.configContext && typeof cached.configContext.onunload === FUNCTION) cached.configContext.onunload()
243
+ }
244
+ if (type.call(data.tag) != STRING) return;
245
+
246
+ var node, isNew = cached.nodes.length === 0;
247
+ if (data.attrs.xmlns) namespace = data.attrs.xmlns;
248
+ else if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg";
249
+ else if (data.tag === "math") namespace = "http://www.w3.org/1998/Math/MathML";
250
+ if (isNew) {
251
+ if (data.attrs.is) node = namespace === undefined ? $document.createElement(data.tag, data.attrs.is) : $document.createElementNS(namespace, data.tag, data.attrs.is);
252
+ else node = namespace === undefined ? $document.createElement(data.tag) : $document.createElementNS(namespace, data.tag);
253
+ cached = {
254
+ tag: data.tag,
255
+ //set attributes first, then create children
256
+ attrs: hasKeys ? setAttributes(node, data.tag, data.attrs, {}, namespace) : data.attrs,
257
+ children: data.children != null && data.children.length > 0 ?
258
+ build(node, data.tag, undefined, undefined, data.children, cached.children, true, 0, data.attrs.contenteditable ? node : editable, namespace, configs) :
259
+ data.children,
260
+ nodes: [node]
261
+ };
262
+ if (cached.children && !cached.children.nodes) cached.children.nodes = [];
263
+ //edge case: setting value on <select> doesn't work before children exist, so set it again after children have been created
264
+ if (data.tag === "select" && data.attrs.value) setAttributes(node, data.tag, {value: data.attrs.value}, {}, namespace);
265
+ parentElement.insertBefore(node, parentElement.childNodes[index] || null)
266
+ }
267
+ else {
268
+ node = cached.nodes[0];
269
+ if (hasKeys) setAttributes(node, data.tag, data.attrs, cached.attrs, namespace);
270
+ cached.children = build(node, data.tag, undefined, undefined, data.children, cached.children, false, 0, data.attrs.contenteditable ? node : editable, namespace, configs);
271
+ cached.nodes.intact = true;
272
+ if (shouldReattach === true && node != null) parentElement.insertBefore(node, parentElement.childNodes[index] || null)
273
+ }
274
+ //schedule configs to be called. They are called after `build` finishes running
275
+ if (typeof data.attrs["config"] === FUNCTION) {
276
+ var context = cached.configContext = cached.configContext || {};
277
+
278
+ // bind
279
+ var callback = function(data, args) {
280
+ return function() {
281
+ return data.attrs["config"].apply(data, args)
282
+ }
283
+ };
284
+ configs.push(callback(data, [node, !isNew, context, cached]))
285
+ }
286
+ }
287
+ else if (typeof dataType != FUNCTION) {
288
+ //handle text nodes
289
+ var nodes;
290
+ if (cached.nodes.length === 0) {
291
+ if (data.$trusted) {
292
+ nodes = injectHTML(parentElement, index, data)
293
+ }
294
+ else {
295
+ nodes = [$document.createTextNode(data)];
296
+ if (!parentElement.nodeName.match(voidElements)) parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null)
297
+ }
298
+ cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data;
299
+ cached.nodes = nodes
300
+ }
301
+ else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
302
+ nodes = cached.nodes;
303
+ if (!editable || editable !== $document.activeElement) {
304
+ if (data.$trusted) {
305
+ clear(nodes, cached);
306
+ nodes = injectHTML(parentElement, index, data)
307
+ }
308
+ else {
309
+ //corner case: replacing the nodeValue of a text node that is a child of a textarea/contenteditable doesn't work
310
+ //we need to update the value property of the parent textarea or the innerHTML of the contenteditable element instead
311
+ if (parentTag === "textarea") parentElement.value = data;
312
+ else if (editable) editable.innerHTML = data;
313
+ else {
314
+ if (nodes[0].nodeType === 1 || nodes.length > 1) { //was a trusted string
315
+ clear(cached.nodes, cached);
316
+ nodes = [$document.createTextNode(data)]
317
+ }
318
+ parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null);
319
+ nodes[0].nodeValue = data
320
+ }
321
+ }
322
+ }
323
+ cached = new data.constructor(data);
324
+ cached.nodes = nodes
325
+ }
326
+ else cached.nodes.intact = true
327
+ }
328
+
329
+ return cached
330
+ }
331
+ function sortChanges(a, b) {return a.action - b.action || a.index - b.index}
332
+ function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {
333
+ for (var attrName in dataAttrs) {
334
+ var dataAttr = dataAttrs[attrName];
335
+ var cachedAttr = cachedAttrs[attrName];
336
+ if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr)) {
337
+ cachedAttrs[attrName] = dataAttr;
338
+ try {
339
+ //`config` isn't a real attributes, so ignore it
340
+ if (attrName === "config" || attrName == "key") continue;
341
+ //hook event handlers to the auto-redrawing system
342
+ else if (typeof dataAttr === FUNCTION && attrName.indexOf("on") === 0) {
343
+ node[attrName] = autoredraw(dataAttr, node)
344
+ }
345
+ //handle `style: {...}`
346
+ else if (attrName === "style" && dataAttr != null && type.call(dataAttr) === OBJECT) {
347
+ for (var rule in dataAttr) {
348
+ if (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]
349
+ }
350
+ for (var rule in cachedAttr) {
351
+ if (!(rule in dataAttr)) node.style[rule] = ""
352
+ }
353
+ }
354
+ //handle SVG
355
+ else if (namespace != null) {
356
+ if (attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr);
357
+ else if (attrName === "className") node.setAttribute("class", dataAttr);
358
+ else node.setAttribute(attrName, dataAttr)
359
+ }
360
+ //handle cases that are properties (but ignore cases where we should use setAttribute instead)
361
+ //- list and form are typically used as strings, but are DOM element references in js
362
+ //- when using CSS selectors (e.g. `m("[style='']")`), style is used as a string, but it's an object in js
363
+ else if (attrName in node && !(attrName === "list" || attrName === "style" || attrName === "form" || attrName === "type")) {
364
+ //#348 don't set the value if not needed otherwise cursor placement breaks in Chrome
365
+ if (tag !== "input" || node[attrName] !== dataAttr) node[attrName] = dataAttr
366
+ }
367
+ else node.setAttribute(attrName, dataAttr)
368
+ }
369
+ catch (e) {
370
+ //swallow IE's invalid argument errors to mimic HTML's fallback-to-doing-nothing-on-invalid-attributes behavior
371
+ if (e.message.indexOf("Invalid argument") < 0) throw e
372
+ }
373
+ }
374
+ //#348 dataAttr may not be a string, so use loose comparison (double equal) instead of strict (triple equal)
375
+ else if (attrName === "value" && tag === "input" && node.value != dataAttr) {
376
+ node.value = dataAttr
377
+ }
378
+ }
379
+ return cachedAttrs
380
+ }
381
+ function clear(nodes, cached) {
382
+ for (var i = nodes.length - 1; i > -1; i--) {
383
+ if (nodes[i] && nodes[i].parentNode) {
384
+ try {nodes[i].parentNode.removeChild(nodes[i])}
385
+ catch (e) {} //ignore if this fails due to order of events (see http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node)
386
+ cached = [].concat(cached);
387
+ if (cached[i]) unload(cached[i])
388
+ }
389
+ }
390
+ if (nodes.length != 0) nodes.length = 0
391
+ }
392
+ function unload(cached) {
393
+ if (cached.configContext && typeof cached.configContext.onunload === FUNCTION) cached.configContext.onunload();
394
+ if (cached.children) {
395
+ if (type.call(cached.children) === ARRAY) {
396
+ for (var i = 0, child; child = cached.children[i]; i++) unload(child)
397
+ }
398
+ else if (cached.children.tag) unload(cached.children)
399
+ }
400
+ }
401
+ function injectHTML(parentElement, index, data) {
402
+ var nextSibling = parentElement.childNodes[index];
403
+ if (nextSibling) {
404
+ var isElement = nextSibling.nodeType != 1;
405
+ var placeholder = $document.createElement("span");
406
+ if (isElement) {
407
+ parentElement.insertBefore(placeholder, nextSibling || null);
408
+ placeholder.insertAdjacentHTML("beforebegin", data);
409
+ parentElement.removeChild(placeholder)
410
+ }
411
+ else nextSibling.insertAdjacentHTML("beforebegin", data)
412
+ }
413
+ else parentElement.insertAdjacentHTML("beforeend", data);
414
+ var nodes = [];
415
+ while (parentElement.childNodes[index] !== nextSibling) {
416
+ nodes.push(parentElement.childNodes[index]);
417
+ index++
418
+ }
419
+ return nodes
420
+ }
421
+ function autoredraw(callback, object) {
422
+ return function(e) {
423
+ e = e || event;
424
+ m.redraw.strategy("diff");
425
+ m.startComputation();
426
+ try {return callback.call(object, e)}
427
+ finally {
428
+ endFirstComputation()
429
+ }
430
+ }
431
+ }
432
+
433
+ var html;
434
+ var documentNode = {
435
+ appendChild: function(node) {
436
+ if (html === undefined) html = $document.createElement("html");
437
+ if ($document.documentElement && $document.documentElement !== node) {
438
+ $document.replaceChild(node, $document.documentElement)
439
+ }
440
+ else $document.appendChild(node);
441
+ this.childNodes = $document.childNodes
442
+ },
443
+ insertBefore: function(node) {
444
+ this.appendChild(node)
445
+ },
446
+ childNodes: []
447
+ };
448
+ var nodeCache = [], cellCache = {};
449
+ m.render = function(root, cell, forceRecreation) {
450
+ var configs = [];
451
+ if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
452
+ var id = getCellCacheKey(root);
453
+ var isDocumentRoot = root === $document;
454
+ var node = isDocumentRoot || root === $document.documentElement ? documentNode : root;
455
+ if (isDocumentRoot && cell.tag != "html") cell = {tag: "html", attrs: {}, children: cell};
456
+ if (cellCache[id] === undefined) clear(node.childNodes);
457
+ if (forceRecreation === true) reset(root);
458
+ cellCache[id] = build(node, null, undefined, undefined, cell, cellCache[id], false, 0, null, undefined, configs);
459
+ for (var i = 0, len = configs.length; i < len; i++) configs[i]()
460
+ };
461
+ function getCellCacheKey(element) {
462
+ var index = nodeCache.indexOf(element);
463
+ return index < 0 ? nodeCache.push(element) - 1 : index
464
+ }
465
+
466
+ m.trust = function(value) {
467
+ value = new String(value);
468
+ value.$trusted = true;
469
+ return value
470
+ };
471
+
472
+ function gettersetter(store) {
473
+ var prop = function() {
474
+ if (arguments.length) store = arguments[0];
475
+ return store
476
+ };
477
+
478
+ prop.toJSON = function() {
479
+ return store
480
+ };
481
+
482
+ return prop
483
+ }
484
+
485
+ m.prop = function (store) {
486
+ //note: using non-strict equality check here because we're checking if store is null OR undefined
487
+ if (((store != null && type.call(store) === OBJECT) || typeof store === FUNCTION) && typeof store.then === FUNCTION) {
488
+ return propify(store)
489
+ }
490
+
491
+ return gettersetter(store)
492
+ };
493
+
494
+ var roots = [], modules = [], controllers = [], lastRedrawId = null, lastRedrawCallTime = 0, computePostRedrawHook = null, prevented = false, topModule;
495
+ var FRAME_BUDGET = 16; //60 frames per second = 1 call per 16 ms
496
+ m.module = function(root, module) {
497
+ if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
498
+ var index = roots.indexOf(root);
499
+ if (index < 0) index = roots.length;
500
+ var isPrevented = false;
501
+ if (controllers[index] && typeof controllers[index].onunload === FUNCTION) {
502
+ var event = {
503
+ preventDefault: function() {isPrevented = true}
504
+ };
505
+ controllers[index].onunload(event)
506
+ }
507
+ if (!isPrevented) {
508
+ m.redraw.strategy("all");
509
+ m.startComputation();
510
+ roots[index] = root;
511
+ var currentModule = topModule = module = module || {};
512
+ var controller = new (module.controller || function() {});
513
+ //controllers may call m.module recursively (via m.route redirects, for example)
514
+ //this conditional ensures only the last recursive m.module call is applied
515
+ if (currentModule === topModule) {
516
+ controllers[index] = controller;
517
+ modules[index] = module
518
+ }
519
+ endFirstComputation();
520
+ return controllers[index]
521
+ }
522
+ };
523
+ m.redraw = function(force) {
524
+ //lastRedrawId is a positive number if a second redraw is requested before the next animation frame
525
+ //lastRedrawID is null if it's the first redraw and not an event handler
526
+ if (lastRedrawId && force !== true) {
527
+ //when setTimeout: only reschedule redraw if time between now and previous redraw is bigger than a frame, otherwise keep currently scheduled timeout
528
+ //when rAF: always reschedule redraw
529
+ if (new Date - lastRedrawCallTime > FRAME_BUDGET || $requestAnimationFrame === window.requestAnimationFrame) {
530
+ if (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId);
531
+ lastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET)
532
+ }
533
+ }
534
+ else {
535
+ redraw();
536
+ lastRedrawId = $requestAnimationFrame(function() {lastRedrawId = null}, FRAME_BUDGET)
537
+ }
538
+ };
539
+ m.redraw.strategy = m.prop();
540
+ var blank = function() {return ""}
541
+ function redraw() {
542
+ var forceRedraw = m.redraw.strategy() === "all";
543
+ for (var i = 0, root; root = roots[i]; i++) {
544
+ if (controllers[i]) {
545
+ m.render(root, modules[i].view ? modules[i].view(controllers[i]) : blank(), forceRedraw)
546
+ }
547
+ }
548
+ //after rendering within a routed context, we need to scroll back to the top, and fetch the document title for history.pushState
549
+ if (computePostRedrawHook) {
550
+ computePostRedrawHook();
551
+ computePostRedrawHook = null
552
+ }
553
+ lastRedrawId = null;
554
+ lastRedrawCallTime = new Date;
555
+ m.redraw.strategy("diff")
556
+ }
557
+
558
+ var pendingRequests = 0;
559
+ m.startComputation = function() {pendingRequests++};
560
+ m.endComputation = function() {
561
+ pendingRequests = Math.max(pendingRequests - 1, 0);
562
+ if (pendingRequests === 0) m.redraw()
563
+ };
564
+ var endFirstComputation = function() {
565
+ if (m.redraw.strategy() == "none") {
566
+ pendingRequests--
567
+ m.redraw.strategy("diff")
568
+ }
569
+ else m.endComputation();
570
+ }
571
+
572
+ m.withAttr = function(prop, withAttrCallback) {
573
+ return function(e) {
574
+ e = e || event;
575
+ var currentTarget = e.currentTarget || this;
576
+ withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop))
577
+ }
578
+ };
579
+
580
+ //routing
581
+ var modes = {pathname: "", hash: "#", search: "?"};
582
+ var redirect = function() {}, routeParams, currentRoute;
583
+ m.route = function() {
584
+ //m.route()
585
+ if (arguments.length === 0) return currentRoute;
586
+ //m.route(el, defaultRoute, routes)
587
+ else if (arguments.length === 3 && type.call(arguments[1]) === STRING) {
588
+ var root = arguments[0], defaultRoute = arguments[1], router = arguments[2];
589
+ redirect = function(source) {
590
+ var path = currentRoute = normalizeRoute(source);
591
+ if (!routeByValue(root, router, path)) {
592
+ m.route(defaultRoute, true)
593
+ }
594
+ };
595
+ var listener = m.route.mode === "hash" ? "onhashchange" : "onpopstate";
596
+ window[listener] = function() {
597
+ var path = $location[m.route.mode]
598
+ if (m.route.mode === "pathname") path += $location.search
599
+ if (currentRoute != normalizeRoute(path)) {
600
+ redirect(path)
601
+ }
602
+ };
603
+ computePostRedrawHook = setScroll;
604
+ window[listener]()
605
+ }
606
+ //config: m.route
607
+ else if (arguments[0].addEventListener) {
608
+ var element = arguments[0];
609
+ var isInitialized = arguments[1];
610
+ var context = arguments[2];
611
+ element.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + this.attrs.href;
612
+ element.removeEventListener("click", routeUnobtrusive);
613
+ element.addEventListener("click", routeUnobtrusive)
614
+ }
615
+ //m.route(route, params)
616
+ else if (type.call(arguments[0]) === STRING) {
617
+ var oldRoute = currentRoute;
618
+ currentRoute = arguments[0];
619
+ var args = arguments[1] || {}
620
+ var queryIndex = currentRoute.indexOf("?")
621
+ var params = queryIndex > -1 ? parseQueryString(currentRoute.slice(queryIndex + 1)) : {}
622
+ for (var i in args) params[i] = args[i]
623
+ var querystring = buildQueryString(params)
624
+ var currentPath = queryIndex > -1 ? currentRoute.slice(0, queryIndex) : currentRoute
625
+ if (querystring) currentRoute = currentPath + (currentPath.indexOf("?") === -1 ? "?" : "&") + querystring;
626
+
627
+ var shouldReplaceHistoryEntry = (arguments.length === 3 ? arguments[2] : arguments[1]) === true || oldRoute === arguments[0];
628
+
629
+ if (window.history.pushState) {
630
+ computePostRedrawHook = function() {
631
+ window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, $document.title, modes[m.route.mode] + currentRoute);
632
+ setScroll()
633
+ };
634
+ redirect(modes[m.route.mode] + currentRoute)
635
+ }
636
+ else $location[m.route.mode] = currentRoute
637
+ }
638
+ };
639
+ m.route.param = function(key) {
640
+ if (!routeParams) throw new Error("You must call m.route(element, defaultRoute, routes) before calling m.route.param()")
641
+ return routeParams[key]
642
+ };
643
+ m.route.mode = "search";
644
+ function normalizeRoute(route) {
645
+ return route.slice(modes[m.route.mode].length)
646
+ }
647
+ function routeByValue(root, router, path) {
648
+ routeParams = {};
649
+
650
+ var queryStart = path.indexOf("?");
651
+ if (queryStart !== -1) {
652
+ routeParams = parseQueryString(path.substr(queryStart + 1, path.length));
653
+ path = path.substr(0, queryStart)
654
+ }
655
+
656
+ for (var route in router) {
657
+ if (route === path) {
658
+ m.module(root, router[route]);
659
+ return true
660
+ }
661
+
662
+ var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$");
663
+
664
+ if (matcher.test(path)) {
665
+ path.replace(matcher, function() {
666
+ var keys = route.match(/:[^\/]+/g) || [];
667
+ var values = [].slice.call(arguments, 1, -2);
668
+ for (var i = 0, len = keys.length; i < len; i++) routeParams[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
669
+ m.module(root, router[route])
670
+ });
671
+ return true
672
+ }
673
+ }
674
+ }
675
+ function routeUnobtrusive(e) {
676
+ e = e || event;
677
+ if (e.ctrlKey || e.metaKey || e.which === 2) return;
678
+ if (e.preventDefault) e.preventDefault();
679
+ else e.returnValue = false;
680
+ var currentTarget = e.currentTarget || this;
681
+ var args = m.route.mode === "pathname" && currentTarget.search ? parseQueryString(currentTarget.search.slice(1)) : {};
682
+ m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args)
683
+ }
684
+ function setScroll() {
685
+ if (m.route.mode != "hash" && $location.hash) $location.hash = $location.hash;
686
+ else window.scrollTo(0, 0)
687
+ }
688
+ function buildQueryString(object, prefix) {
689
+ var str = [];
690
+ for(var prop in object) {
691
+ var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop];
692
+ var valueType = type.call(value)
693
+ var pair = value != null && (valueType === OBJECT) ?
694
+ buildQueryString(value, key) :
695
+ valueType === ARRAY ?
696
+ value.map(function(item) {return encodeURIComponent(key + "[]") + "=" + encodeURIComponent(item)}).join("&") :
697
+ encodeURIComponent(key) + "=" + encodeURIComponent(value)
698
+ str.push(pair)
699
+ }
700
+ return str.join("&")
701
+ }
702
+
703
+ function parseQueryString(str) {
704
+ var pairs = str.split("&"), params = {};
705
+ for (var i = 0, len = pairs.length; i < len; i++) {
706
+ var pair = pairs[i].split("=");
707
+ params[decodeURIComponent(pair[0])] = pair[1] ? decodeURIComponent(pair[1]) : ""
708
+ }
709
+ return params
710
+ }
711
+ function reset(root) {
712
+ var cacheKey = getCellCacheKey(root);
713
+ clear(root.childNodes, cellCache[cacheKey]);
714
+ cellCache[cacheKey] = undefined
715
+ }
716
+
717
+ m.deferred = function () {
718
+ var deferred = new Deferred();
719
+ deferred.promise = propify(deferred.promise);
720
+ return deferred
721
+ };
722
+ function propify(promise) {
723
+ var prop = m.prop();
724
+ promise.then(prop);
725
+ prop.then = function(resolve, reject) {
726
+ return propify(promise.then(resolve, reject))
727
+ };
728
+ return prop
729
+ }
730
+ //Promiz.mithril.js | Zolmeister | MIT
731
+ //a modified version of Promiz.js, which does not conform to Promises/A+ for two reasons:
732
+ //1) `then` callbacks are called synchronously (because setTimeout is too slow, and the setImmediate polyfill is too big
733
+ //2) throwing subclasses of Error cause the error to be bubbled up instead of triggering rejection (because the spec does not account for the important use case of default browser error handling, i.e. message w/ line number)
734
+ function Deferred(successCallback, failureCallback) {
735
+ var RESOLVING = 1, REJECTING = 2, RESOLVED = 3, REJECTED = 4;
736
+ var self = this, state = 0, promiseValue = 0, next = [];
737
+
738
+ self["promise"] = {};
739
+
740
+ self["resolve"] = function(value) {
741
+ if (!state) {
742
+ promiseValue = value;
743
+ state = RESOLVING;
744
+
745
+ fire()
746
+ }
747
+ return this
748
+ };
749
+
750
+ self["reject"] = function(value) {
751
+ if (!state) {
752
+ promiseValue = value;
753
+ state = REJECTING;
754
+
755
+ fire()
756
+ }
757
+ return this
758
+ };
759
+
760
+ self.promise["then"] = function(successCallback, failureCallback) {
761
+ var deferred = new Deferred(successCallback, failureCallback);
762
+ if (state === RESOLVED) {
763
+ deferred.resolve(promiseValue)
764
+ }
765
+ else if (state === REJECTED) {
766
+ deferred.reject(promiseValue)
767
+ }
768
+ else {
769
+ next.push(deferred)
770
+ }
771
+ return deferred.promise
772
+ };
773
+
774
+ function finish(type) {
775
+ state = type || REJECTED;
776
+ next.map(function(deferred) {
777
+ state === RESOLVED && deferred.resolve(promiseValue) || deferred.reject(promiseValue)
778
+ })
779
+ }
780
+
781
+ function thennable(then, successCallback, failureCallback, notThennableCallback) {
782
+ if (((promiseValue != null && type.call(promiseValue) === OBJECT) || typeof promiseValue === FUNCTION) && typeof then === FUNCTION) {
783
+ try {
784
+ // count protects against abuse calls from spec checker
785
+ var count = 0;
786
+ then.call(promiseValue, function(value) {
787
+ if (count++) return;
788
+ promiseValue = value;
789
+ successCallback()
790
+ }, function (value) {
791
+ if (count++) return;
792
+ promiseValue = value;
793
+ failureCallback()
794
+ })
795
+ }
796
+ catch (e) {
797
+ m.deferred.onerror(e);
798
+ promiseValue = e;
799
+ failureCallback()
800
+ }
801
+ } else {
802
+ notThennableCallback()
803
+ }
804
+ }
805
+
806
+ function fire() {
807
+ // check if it's a thenable
808
+ var then;
809
+ try {
810
+ then = promiseValue && promiseValue.then
811
+ }
812
+ catch (e) {
813
+ m.deferred.onerror(e);
814
+ promiseValue = e;
815
+ state = REJECTING;
816
+ return fire()
817
+ }
818
+ thennable(then, function() {
819
+ state = RESOLVING;
820
+ fire()
821
+ }, function() {
822
+ state = REJECTING;
823
+ fire()
824
+ }, function() {
825
+ try {
826
+ if (state === RESOLVING && typeof successCallback === FUNCTION) {
827
+ promiseValue = successCallback(promiseValue)
828
+ }
829
+ else if (state === REJECTING && typeof failureCallback === "function") {
830
+ promiseValue = failureCallback(promiseValue);
831
+ state = RESOLVING
832
+ }
833
+ }
834
+ catch (e) {
835
+ m.deferred.onerror(e);
836
+ promiseValue = e;
837
+ return finish()
838
+ }
839
+
840
+ if (promiseValue === self) {
841
+ promiseValue = TypeError();
842
+ finish()
843
+ }
844
+ else {
845
+ thennable(then, function () {
846
+ finish(RESOLVED)
847
+ }, finish, function () {
848
+ finish(state === RESOLVING && RESOLVED)
849
+ })
850
+ }
851
+ })
852
+ }
853
+ }
854
+ m.deferred.onerror = function(e) {
855
+ if (type.call(e) === "[object Error]" && !e.constructor.toString().match(/ Error/)) throw e
856
+ };
857
+
858
+ m.sync = function(args) {
859
+ var method = "resolve";
860
+ function synchronizer(pos, resolved) {
861
+ return function(value) {
862
+ results[pos] = value;
863
+ if (!resolved) method = "reject";
864
+ if (--outstanding === 0) {
865
+ deferred.promise(results);
866
+ deferred[method](results)
867
+ }
868
+ return value
869
+ }
870
+ }
871
+
872
+ var deferred = m.deferred();
873
+ var outstanding = args.length;
874
+ var results = new Array(outstanding);
875
+ if (args.length > 0) {
876
+ for (var i = 0; i < args.length; i++) {
877
+ args[i].then(synchronizer(i, true), synchronizer(i, false))
878
+ }
879
+ }
880
+ else deferred.resolve([]);
881
+
882
+ return deferred.promise
883
+ };
884
+ function identity(value) {return value}
885
+
886
+ function ajax(options) {
887
+ if (options.dataType && options.dataType.toLowerCase() === "jsonp") {
888
+ var callbackKey = "mithril_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36);
889
+ var script = $document.createElement("script");
890
+
891
+ window[callbackKey] = function(resp) {
892
+ script.parentNode.removeChild(script);
893
+ options.onload({
894
+ type: "load",
895
+ target: {
896
+ responseText: resp
897
+ }
898
+ });
899
+ window[callbackKey] = undefined
900
+ };
901
+
902
+ script.onerror = function(e) {
903
+ script.parentNode.removeChild(script);
904
+
905
+ options.onerror({
906
+ type: "error",
907
+ target: {
908
+ status: 500,
909
+ responseText: JSON.stringify({error: "Error making jsonp request"})
910
+ }
911
+ });
912
+ window[callbackKey] = undefined;
913
+
914
+ return false
915
+ };
916
+
917
+ script.onload = function(e) {
918
+ return false
919
+ };
920
+
921
+ script.src = options.url
922
+ + (options.url.indexOf("?") > 0 ? "&" : "?")
923
+ + (options.callbackKey ? options.callbackKey : "callback")
924
+ + "=" + callbackKey
925
+ + "&" + buildQueryString(options.data || {});
926
+ $document.body.appendChild(script)
927
+ }
928
+ else {
929
+ var xhr = new window.XMLHttpRequest;
930
+ xhr.open(options.method, options.url, true, options.user, options.password);
931
+ xhr.onreadystatechange = function() {
932
+ if (xhr.readyState === 4) {
933
+ if (xhr.status >= 200 && xhr.status < 300) options.onload({type: "load", target: xhr});
934
+ else options.onerror({type: "error", target: xhr})
935
+ }
936
+ };
937
+ if (options.serialize === JSON.stringify && options.data && options.method !== "GET") {
938
+ xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8")
939
+ }
940
+ if (options.deserialize === JSON.parse) {
941
+ xhr.setRequestHeader("Accept", "application/json, text/*");
942
+ }
943
+ if (typeof options.config === FUNCTION) {
944
+ var maybeXhr = options.config(xhr, options);
945
+ if (maybeXhr != null) xhr = maybeXhr
946
+ }
947
+
948
+ var data = options.method === "GET" || !options.data ? "" : options.data
949
+ if (data && (type.call(data) != STRING && data.constructor != window.FormData)) {
950
+ throw "Request data should be either be a string or FormData. Check the `serialize` option in `m.request`";
951
+ }
952
+ xhr.send(data);
953
+ return xhr
954
+ }
955
+ }
956
+ function bindData(xhrOptions, data, serialize) {
957
+ if (xhrOptions.method === "GET" && xhrOptions.dataType != "jsonp") {
958
+ var prefix = xhrOptions.url.indexOf("?") < 0 ? "?" : "&";
959
+ var querystring = buildQueryString(data);
960
+ xhrOptions.url = xhrOptions.url + (querystring ? prefix + querystring : "")
961
+ }
962
+ else xhrOptions.data = serialize(data);
963
+ return xhrOptions
964
+ }
965
+ function parameterizeUrl(url, data) {
966
+ var tokens = url.match(/:[a-z]\w+/gi);
967
+ if (tokens && data) {
968
+ for (var i = 0; i < tokens.length; i++) {
969
+ var key = tokens[i].slice(1);
970
+ url = url.replace(tokens[i], data[key]);
971
+ delete data[key]
972
+ }
973
+ }
974
+ return url
975
+ }
976
+
977
+ m.request = function(xhrOptions) {
978
+ if (xhrOptions.background !== true) m.startComputation();
979
+ var deferred = m.deferred();
980
+ var isJSONP = xhrOptions.dataType && xhrOptions.dataType.toLowerCase() === "jsonp";
981
+ var serialize = xhrOptions.serialize = isJSONP ? identity : xhrOptions.serialize || JSON.stringify;
982
+ var deserialize = xhrOptions.deserialize = isJSONP ? identity : xhrOptions.deserialize || JSON.parse;
983
+ var extract = xhrOptions.extract || function(xhr) {
984
+ return xhr.responseText.length === 0 && deserialize === JSON.parse ? null : xhr.responseText
985
+ };
986
+ xhrOptions.url = parameterizeUrl(xhrOptions.url, xhrOptions.data);
987
+ xhrOptions = bindData(xhrOptions, xhrOptions.data, serialize);
988
+ xhrOptions.onload = xhrOptions.onerror = function(e) {
989
+ try {
990
+ e = e || event;
991
+ var unwrap = (e.type === "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity;
992
+ var response = unwrap(deserialize(extract(e.target, xhrOptions)));
993
+ if (e.type === "load") {
994
+ if (type.call(response) === ARRAY && xhrOptions.type) {
995
+ for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
996
+ }
997
+ else if (xhrOptions.type) response = new xhrOptions.type(response)
998
+ }
999
+ deferred[e.type === "load" ? "resolve" : "reject"](response)
1000
+ }
1001
+ catch (e) {
1002
+ m.deferred.onerror(e);
1003
+ deferred.reject(e)
1004
+ }
1005
+ if (xhrOptions.background !== true) m.endComputation()
1006
+ };
1007
+ ajax(xhrOptions);
1008
+ deferred.promise(xhrOptions.initialValue);
1009
+ return deferred.promise
1010
+ };
1011
+
1012
+ //testing API
1013
+ m.deps = function(mock) {
1014
+ initialize(window = mock || window);
1015
+ return window;
1016
+ };
1017
+ //for internal testing only, do not use `m.deps.factory`
1018
+ m.deps.factory = app;
1019
+
1020
+ return m
1021
+ })(typeof window != "undefined" ? window : {});
1022
+
1023
+ if (typeof module != "undefined" && module !== null && module.exports) module.exports = m;
1024
+ else if (typeof define === "function" && define.amd) define(function() {return m});