PageSourceSearch

https://app.voxingpro.com/packages/blaze.js?hash=cbd85c3fe14949f2d2b9a3b76334f5f0e96d553c

js voxingpro.com collected 2026-10-02 14:38:55 UTC 134,649 bytes, 3,937 lines download raw bytes

1//////////////////////////////////////////////////////////////////////////
2//                                                                      //
3// This is a generated file. You can view the original                  //
4// source in your browser if your browser supports source maps.         //
5// Source maps are supported by all recent versions of Chrome, Safari,  //
6// and Firefox, and by Internet Explorer 11.                            //
7//                                                                      //
8//////////////////////////////////////////////////////////////////////////
9
10
11(function () {
12
13/* Imports */
14var Meteor = Package.meteor.Meteor;
15var global = Package.meteor.global;
16var meteorEnv = Package.meteor.meteorEnv;
17var $ = Package.jquery.$;
18var jQuery = Package.jquery.jQuery;
19var Tracker = Package.tracker.Tracker;
20var Deps = Package.tracker.Deps;
21var check = Package.check.check;
22var Match = Package.check.Match;
23var _ = Package.underscore._;
24var ObserveSequence = Package['observe-sequence'].ObserveSequence;
25var ReactiveVar = Package['reactive-var'].ReactiveVar;
26var OrderedDict = Package['ordered-dict'].OrderedDict;
27var HTML = Package.htmljs.HTML;
28
29/* Package-scope variables */
30var Blaze, AttributeHandler, ElementAttributesUpdater, UI, Handlebars;
31
32(function(){
33
34/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
35//                                                                                                                     //
36// packages/blaze/preamble.js                                                                                          //
37//                                                                                                                     //
38/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
39                                                                                                                       //
40/**
41 * @namespace Blaze
42 * @summary The namespace for all Blaze-related methods and classes.
43 */
44Blaze = {};
45
46// Utility to HTML-escape a string.  Included for legacy reasons.
47// TODO: Should be replaced with _.escape once underscore is upgraded to a newer
48//       version which escapes ` (backtick) as well. Underscore 1.5.2 does not.
49Blaze._escape = (function() {
50  var escape_map = {
51    "<": "&lt;",
52    ">": "&gt;",
53    '"': "&quot;",
54    "'": "&#x27;",
55    "/": "&#x2F;",
56    "`": "&#x60;", /* IE allows backtick-delimited attributes?? */
57    "&": "&amp;"
58  };
59  var escape_one = function(c) {
60    return escape_map[c];
61  };
62
63  return function (x) {
64    return x.replace(/[&<>"'`]/g, escape_one);
65  };
66})();
67
68Blaze._warn = function (msg) {
69  msg = 'Warning: ' + msg;
70
71  if ((typeof console !== 'undefined') && console.warn) {
72    console.warn(msg);
73  }
74};
75
76var nativeBind = Function.prototype.bind;
77
78// An implementation of _.bind which allows better optimization.
79// See: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
80if (nativeBind) {
81  Blaze._bind = function (func, obj) {
82    if (arguments.length === 2) {
83      return nativeBind.call(func, obj);
84    }
85
86    // Copy the arguments so this function can be optimized.
87    var args = new Array(arguments.length);
88    for (var i = 0; i < args.length; i++) {
89      args[i] = arguments[i];
90    }
91
92    return nativeBind.apply(func, args.slice(1));
93  };
94}
95else {
96  // A slower but backwards compatible version.
97  Blaze._bind = _.bind;
98}
99
100/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
101
102}).call(this);
103
104
105
106
107
108
109(function(){
110
111/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112//                                                                                                                     //
113// packages/blaze/dombackend.js                                                                                        //
114//                                                                                                                     //
115/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
116                                                                                                                       //
117var DOMBackend = {};
118Blaze._DOMBackend = DOMBackend;
119
120var $jq = (typeof jQuery !== 'undefined' ? jQuery :
121           (typeof Package !== 'undefined' ?
122            Package.jquery && Package.jquery.jQuery : null));
123if (! $jq)
124  throw new Error("jQuery not found");
125
126DOMBackend._$jq = $jq;
127
128DOMBackend.parseHTML = function (html) {
129  // Return an array of nodes.
130  //
131  // jQuery does fancy stuff like creating an appropriate
132  // container element and setting innerHTML on it, as well
133  // as working around various IE quirks.
134  return $jq.parseHTML(html) || [];
135};
136
137DOMBackend.Events = {
138  // `selector` is non-null.  `type` is one type (but
139  // may be in backend-specific form, e.g. have namespaces).
140  // Order fired must be order bound.
141  delegateEvents: function (elem, type, selector, handler) {
142    $jq(elem).on(type, selector, handler);
143  },
144
145  undelegateEvents: function (elem, type, handler) {
146    $jq(elem).off(type, '**', handler);
147  },
148
149  bindEventCapturer: function (elem, type, selector, handler) {
150    var $elem = $jq(elem);
151
152    var wrapper = function (event) {
153      event = $jq.event.fix(event);
154      event.currentTarget = event.target;
155
156      // Note: It might improve jQuery interop if we called into jQuery
157      // here somehow.  Since we don't use jQuery to dispatch the event,
158      // we don't fire any of jQuery's event hooks or anything.  However,
159      // since jQuery can't bind capturing handlers, it's not clear
160      // where we would hook in.  Internal jQuery functions like `dispatch`
161      // are too high-level.
162      var $target = $jq(event.currentTarget);
163      if ($target.is($elem.find(selector)))
164        handler.call(elem, event);
165    };
166
167    handler._meteorui_wrapper = wrapper;
168
169    type = DOMBackend.Events.parseEventType(type);
170    // add *capturing* event listener
171    elem.addEventListener(type, wrapper, true);
172  },
173
174  unbindEventCapturer: function (elem, type, handler) {
175    type = DOMBackend.Events.parseEventType(type);
176    elem.removeEventListener(type, handler._meteorui_wrapper, true);
177  },
178
179  parseEventType: function (type) {
180    // strip off namespaces
181    var dotLoc = type.indexOf('.');
182    if (dotLoc >= 0)
183      return type.slice(0, dotLoc);
184    return type;
185  }
186};
187
188
189///// Removal detection and interoperability.
190
191// For an explanation of this technique, see:
192// http://bugs.jquery.com/ticket/12213#comment:23 .
193//
194// In short, an element is considered "removed" when jQuery
195// cleans up its *private* userdata on the element,
196// which we can detect using a custom event with a teardown
197// hook.
198
199var NOOP = function () {};
200
201// Circular doubly-linked list
202var TeardownCallback = function (func) {
203  this.next = this;
204  this.prev = this;
205  this.func = func;
206};
207
208// Insert newElt before oldElt in the circular list
209TeardownCallback.prototype.linkBefore = function(oldElt) {
210  this.prev = oldElt.prev;
211  this.next = oldElt;
212  oldElt.prev.next = this;
213  oldElt.prev = this;
214};
215
216TeardownCallback.prototype.unlink = function () {
217  this.prev.next = this.next;
218  this.next.prev = this.prev;
219};
220
221TeardownCallback.prototype.go = function () {
222  var func = this.func;
223  func && func();
224};
225
226TeardownCallback.prototype.stop = TeardownCallback.prototype.unlink;
227
228DOMBackend.Teardown = {
229  _JQUERY_EVENT_NAME: 'blaze_teardown_watcher',
230  _CB_PROP: '$blaze_teardown_callbacks',
231  // Registers a callback function to be called when the given element or
232  // one of its ancestors is removed from the DOM via the backend library.
233  // The callback function is called at most once, and it receives the element
234  // in question as an argument.
235  onElementTeardown: function (elem, func) {
236    var elt = new TeardownCallback(func);
237
238    var propName = DOMBackend.Teardown._CB_PROP;
239    if (! elem[propName]) {
240      // create an empty node that is never unlinked
241      elem[propName] = new TeardownCallback;
242
243      // Set up the event, only the first time.
244      $jq(elem).on(DOMBackend.Teardown._JQUERY_EVENT_NAME, NOOP);
245    }
246
247    elt.linkBefore(elem[propName]);
248
249    return elt; // so caller can call stop()
250  },
251  // Recursively call all teardown hooks, in the backend and registered
252  // through DOMBackend.onElementTeardown.
253  tearDownElement: function (elem) {
254    var elems = [];
255    // Array.prototype.slice.call doesn't work when given a NodeList in
256    // IE8 ("JScript object expected").
257    var nodeList = elem.getElementsByTagName('*');
258    for (var i = 0; i < nodeList.length; i++) {
259      elems.push(nodeList[i]);
260    }
261    elems.push(elem);
262    $jq.cleanData(elems);
263  }
264};
265
266$jq.event.special[DOMBackend.Teardown._JQUERY_EVENT_NAME] = {
267  setup: function () {
268    // This "setup" callback is important even though it is empty!
269    // Without it, jQuery will call addEventListener, which is a
270    // performance hit, especially with Chrome's async stack trace
271    // feature enabled.
272  },
273  teardown: function() {
274    var elem = this;
275    var callbacks = elem[DOMBackend.Teardown._CB_PROP];
276    if (callbacks) {
277      var elt = callbacks.next;
278      while (elt !== callbacks) {
279        elt.go();
280        elt = elt.next;
281      }
282      callbacks.go();
283
284      elem[DOMBackend.Teardown._CB_PROP] = null;
285    }
286  }
287};
288
289
290// Must use jQuery semantics for `context`, not
291// querySelectorAll's.  In other words, all the parts
292// of `selector` must be found under `context`.
293DOMBackend.findBySelector = function (selector, context) {
294  return $jq(selector, context);
295};
296
297/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
298
299}).call(this);
300
301
302
303
304
305
306(function(){
307
308/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
309//                                                                                                                     //
310// packages/blaze/domrange.js                                                                                          //
311//                                                                                                                     //
312/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
313                                                                                                                       //
314
315// A constant empty array (frozen if the JS engine supports it).
316var _emptyArray = Object.freeze ? Object.freeze([]) : [];
317
318// `[new] Blaze._DOMRange([nodeAndRangeArray])`
319//
320// A DOMRange consists of an array of consecutive nodes and DOMRanges,
321// which may be replaced at any time with a new array.  If the DOMRange
322// has been attached to the DOM at some location, then updating
323// the array will cause the DOM to be updated at that location.
324Blaze._DOMRange = function (nodeAndRangeArray) {
325  if (! (this instanceof DOMRange))
326    // called without `new`
327    return new DOMRange(nodeAndRangeArray);
328
329  var members = (nodeAndRangeArray || _emptyArray);
330  if (! (members && (typeof members.length) === 'number'))
331    throw new Error("Expected array");
332
333  for (var i = 0; i < members.length; i++)
334    this._memberIn(members[i]);
335
336  this.members = members;
337  this.emptyRangePlaceholder = null;
338  this.attached = false;
339  this.parentElement = null;
340  this.parentRange = null;
341  this.attachedCallbacks = _emptyArray;
342};
343var DOMRange = Blaze._DOMRange;
344
345// In IE 8, don't use empty text nodes as placeholders
346// in empty DOMRanges, use comment nodes instead.  Using
347// empty text nodes in modern browsers is great because
348// it doesn't clutter the web inspector.  In IE 8, however,
349// it seems to lead in some roundabout way to the OAuth
350// pop-up crashing the browser completely.  In the past,
351// we didn't use empty text nodes on IE 8 because they
352// don't accept JS properties, so just use the same logic
353// even though we don't need to set properties on the
354// placeholder anymore.
355DOMRange._USE_COMMENT_PLACEHOLDERS = (function () {
356  var result = false;
357  var textNode = document.createTextNode("");
358  try {
359    textNode.someProp = true;
360  } catch (e) {
361    // IE 8
362    result = true;
363  }
364  return result;
365})();
366
367// static methods
368DOMRange._insert = function (rangeOrNode, parentElement, nextNode, _isMove) {
369  var m = rangeOrNode;
370  if (m instanceof DOMRange) {
371    m.attach(parentElement, nextNode, _isMove);
372  } else {
373    if (_isMove)
374      DOMRange._moveNodeWithHooks(m, parentElement, nextNode);
375    else
376      DOMRange._insertNodeWithHooks(m, parentElement, nextNode);
377  }
378};
379
380DOMRange._remove = function (rangeOrNode) {
381  var m = rangeOrNode;
382  if (m instanceof DOMRange) {
383    m.detach();
384  } else {
385    DOMRange._removeNodeWithHooks(m);
386  }
387};
388
389DOMRange._removeNodeWithHooks = function (n) {
390  if (! n.parentNode)
391    return;
392  if (n.nodeType === 1 &&
393      n.parentNode._uihooks && n.parentNode._uihooks.removeElement) {
394    n.parentNode._uihooks.removeElement(n);
395  } else {
396    n.parentNode.removeChild(n);
397  }
398};
399
400DOMRange._insertNodeWithHooks = function (n, parent, next) {
401  // `|| null` because IE throws an error if 'next' is undefined
402  next = next || null;
403  if (n.nodeType === 1 &&
404      parent._uihooks && parent._uihooks.insertElement) {
405    parent._uihooks.insertElement(n, next);
406  } else {
407    parent.insertBefore(n, next);
408  }
409};
410
411DOMRange._moveNodeWithHooks = function (n, parent, next) {
412  if (n.parentNode !== parent)
413    return;
414  // `|| null` because IE throws an error if 'next' is undefined
415  next = next || null;
416  if (n.nodeType === 1 &&
417      parent._uihooks && parent._uihooks.moveElement) {
418    parent._uihooks.moveElement(n, next);
419  } else {
420    parent.insertBefore(n, next);
421  }
422};
423
424DOMRange.forElement = function (elem) {
425  if (elem.nodeType !== 1)
426    throw new Error("Expected element, found: " + elem);
427  var range = null;
428  while (elem && ! range) {
429    range = (elem.$blaze_range || null);
430    if (! range)
431      elem = elem.parentNode;
432  }
433  return range;
434};
435
436DOMRange.prototype.attach = function (parentElement, nextNode, _isMove, _isReplace) {
437  // This method is called to insert the DOMRange into the DOM for
438  // the first time, but it's also used internally when
439  // updating the DOM.
440  //
441  // If _isMove is true, move this attached range to a different
442  // location under the same parentElement.
443  if (_isMove || _isReplace) {
444    if (! (this.parentElement === parentElement &&
445           this.attached))
446      throw new Error("Can only move or replace an attached DOMRange, and only under the same parent element");
447  }
448
449  var members = this.members;
450  if (members.length) {
451    this.emptyRangePlaceholder = null;
452    for (var i = 0; i < members.length; i++) {
453      DOMRange._insert(members[i], parentElement, nextNode, _isMove);
454    }
455  } else {
456    var placeholder = (
457      DOMRange._USE_COMMENT_PLACEHOLDERS ?
458        document.createComment("") :
459        document.createTextNode(""));
460    this.emptyRangePlaceholder = placeholder;
461    parentElement.insertBefore(placeholder, nextNode || null);
462  }
463  this.attached = true;
464  this.parentElement = parentElement;
465
466  if (! (_isMove || _isReplace)) {
467    for(var i = 0; i < this.attachedCallbacks.length; i++) {
468      var obj = this.attachedCallbacks[i];
469      obj.attached && obj.attached(this, parentElement);
470    }
471  }
472};
473
474DOMRange.prototype.setMembers = function (newNodeAndRangeArray) {
475  var newMembers = newNodeAndRangeArray;
476  if (! (newMembers && (typeof newMembers.length) === 'number'))
477    throw new Error("Expected array");
478
479  var oldMembers = this.members;
480
481  for (var i = 0; i < oldMembers.length; i++)
482    this._memberOut(oldMembers[i]);
483  for (var i = 0; i < newMembers.length; i++)
484    this._memberIn(newMembers[i]);
485
486  if (! this.attached) {
487    this.members = newMembers;
488  } else {
489    // don't do anything if we're going from empty to empty
490    if (newMembers.length || oldMembers.length) {
491      // detach the old members and insert the new members
492      var nextNode = this.lastNode().nextSibling;
493      var parentElement = this.parentElement;
494      // Use detach/attach, but don't fire attached/detached hooks
495      this.detach(true /*_isReplace*/);
496      this.members = newMembers;
497      this.attach(parentElement, nextNode, false, true /*_isReplace*/);
498    }
499  }
500};
501
502DOMRange.prototype.firstNode = function () {
503  if (! this.attached)
504    throw new Error("Must be attached");
505
506  if (! this.members.length)
507    return this.emptyRangePlaceholder;
508
509  var m = this.members[0];
510  return (m instanceof DOMRange) ? m.firstNode() : m;
511};
512
513DOMRange.prototype.lastNode = function () {
514  if (! this.attached)
515    throw new Error("Must be attached");
516
517  if (! this.members.length)
518    return this.emptyRangePlaceholder;
519
520  var m = this.members[this.members.length - 1];
521  return (m instanceof DOMRange) ? m.lastNode() : m;
522};
523
524DOMRange.prototype.detach = function (_isReplace) {
525  if (! this.attached)
526    throw new Error("Must be attached");
527
528  var oldParentElement = this.parentElement;
529  var members = this.members;
530  if (members.length) {
531    for (var i = 0; i < members.length; i++) {
532      DOMRange._remove(members[i]);
533    }
534  } else {
535    var placeholder = this.emptyRangePlaceholder;
536    this.parentElement.removeChild(placeholder);
537    this.emptyRangePlaceholder = null;
538  }
539
540  if (! _isReplace) {
541    this.attached = false;
542    this.parentElement = null;
543
544    for(var i = 0; i < this.attachedCallbacks.length; i++) {
545      var obj = this.attachedCallbacks[i];
546      obj.detached && obj.detached(this, oldParentElement);
547    }
548  }
549};
550
551DOMRange.prototype.addMember = function (newMember, atIndex, _isMove) {
552  var members = this.members;
553  if (! (atIndex >= 0 && atIndex <= members.length))
554    throw new Error("Bad index in range.addMember: " + atIndex);
555
556  if (! _isMove)
557    this._memberIn(newMember);
558
559  if (! this.attached) {
560    // currently detached; just updated members
561    members.splice(atIndex, 0, newMember);
562  } else if (members.length === 0) {
563    // empty; use the empty-to-nonempty handling of setMembers
564    this.setMembers([newMember]);
565  } else {
566    var nextNode;
567    if (atIndex === members.length) {
568      // insert at end
569      nextNode = this.lastNode().nextSibling;
570    } else {
571      var m = members[atIndex];
572      nextNode = (m instanceof DOMRange) ? m.firstNode() : m;
573    }
574    members.splice(atIndex, 0, newMember);
575    DOMRange._insert(newMember, this.parentElement, nextNode, _isMove);
576  }
577};
578
579DOMRange.prototype.removeMember = function (atIndex, _isMove) {
580  var members = this.members;
581  if (! (atIndex >= 0 && atIndex < members.length))
582    throw new Error("Bad index in range.removeMember: " + atIndex);
583
584  if (_isMove) {
585    members.splice(atIndex, 1);
586  } else {
587    var oldMember = members[atIndex];
588    this._memberOut(oldMember);
589
590    if (members.length === 1) {
591      // becoming empty; use the logic in setMembers
592      this.setMembers(_emptyArray);
593    } else {
594      members.splice(atIndex, 1);
595      if (this.attached)
596        DOMRange._remove(oldMember);
597    }
598  }
599};
600
601DOMRange.prototype.moveMember = function (oldIndex, newIndex) {
602  var member = this.members[oldIndex];
603  this.removeMember(oldIndex, true /*_isMove*/);
604  this.addMember(member, newIndex, true /*_isMove*/);
605};
606
607DOMRange.prototype.getMember = function (atIndex) {
608  var members = this.members;
609  if (! (atIndex >= 0 && atIndex < members.length))
610    throw new Error("Bad index in range.getMember: " + atIndex);
611  return this.members[atIndex];
612};
613
614DOMRange.prototype._memberIn = function (m) {
615  if (m instanceof DOMRange)
616    m.parentRange = this;
617  else if (m.nodeType === 1) // DOM Element
618    m.$blaze_range = this;
619};
620
621DOMRange._destroy = function (m, _skipNodes) {
622  if (m instanceof DOMRange) {
623    if (m.view)
624      Blaze._destroyView(m.view, _skipNodes);
625  } else if ((! _skipNodes) && m.nodeType === 1) {
626    // DOM Element
627    if (m.$blaze_range) {
628      Blaze._destroyNode(m);
629      m.$blaze_range = null;
630    }
631  }
632};
633
634DOMRange.prototype._memberOut = DOMRange._destroy;
635
636// Tear down, but don't remove, the members.  Used when chunks
637// of DOM are being torn down or replaced.
638DOMRange.prototype.destroyMembers = function (_skipNodes) {
639  var members = this.members;
640  for (var i = 0; i < members.length; i++)
641    this._memberOut(members[i], _skipNodes);
642};
643
644DOMRange.prototype.destroy = function (_skipNodes) {
645  DOMRange._destroy(this, _skipNodes);
646};
647
648DOMRange.prototype.containsElement = function (elem) {
649  if (! this.attached)
650    throw new Error("Must be attached");
651
652  // An element is contained in this DOMRange if it's possible to
653  // reach it by walking parent pointers, first through the DOM and
654  // then parentRange pointers.  In other words, the element or some
655  // ancestor of it is at our level of the DOM (a child of our
656  // parentElement), and this element is one of our members or
657  // is a member of a descendant Range.
658
659  // First check that elem is a descendant of this.parentElement,
660  // according to the DOM.
661  if (! Blaze._elementContains(this.parentElement, elem))
662    return false;
663
664  // If elem is not an immediate child of this.parentElement,
665  // walk up to its ancestor that is.
666  while (elem.parentNode !== this.parentElement)
667    elem = elem.parentNode;
668
669  var range = elem.$blaze_range;
670  while (range && range !== this)
671    range = range.parentRange;
672
673  return range === this;
674};
675
676DOMRange.prototype.containsRange = function (range) {
677  if (! this.attached)
678    throw new Error("Must be attached");
679
680  if (! range.attached)
681    return false;
682
683  // A DOMRange is contained in this DOMRange if it's possible
684  // to reach this range by following parent pointers.  If the
685  // DOMRange has the same parentElement, then it should be
686  // a member, or a member of a member etc.  Otherwise, we must
687  // contain its parentElement.
688
689  if (range.parentElement !== this.parentElement)
690    return this.containsElement(range.parentElement);
691
692  if (range === this)
693    return false; // don't contain self
694
695  while (range && range !== this)
696    range = range.parentRange;
697
698  return range === this;
699};
700
701DOMRange.prototype.onAttached = function (attached) {
702  this.onAttachedDetached({ attached: attached });
703};
704
705// callbacks are `attached(range, element)` and
706// `detached(range, element)`, and they may
707// access the `callbacks` object in `this`.
708// The arguments to `detached` are the same
709// range and element that were passed to `attached`.
710DOMRange.prototype.onAttachedDetached = function (callbacks) {
711  if (this.attachedCallbacks === _emptyArray)
712    this.attachedCallbacks = [];
713  this.attachedCallbacks.push(callbacks);
714};
715
716DOMRange.prototype.$ = function (selector) {
717  var self = this;
718
719  var parentNode = this.parentElement;
720  if (! parentNode)
721    throw new Error("Can't select in removed DomRange");
722
723  // Strategy: Find all selector matches under parentNode,
724  // then filter out the ones that aren't in this DomRange
725  // using `DOMRange#containsElement`.  This is
726  // asymptotically slow in the presence of O(N) sibling
727  // content that is under parentNode but not in our range,
728  // so if performance is an issue, the selector should be
729  // run on a child element.
730
731  // Since jQuery can't run selectors on a DocumentFragment,
732  // we don't expect findBySelector to work.
733  if (parentNode.nodeType === 11 /* DocumentFragment */)
734    throw new Error("Can't use $ on an offscreen range");
735
736  var results = Blaze._DOMBackend.findBySelector(selector, parentNode);
737
738  // We don't assume `results` has jQuery API; a plain array
739  // should do just as well.  However, if we do have a jQuery
740  // array, we want to end up with one also, so we use
741  // `.filter`.
742
743  // Function that selects only elements that are actually
744  // in this DomRange, rather than simply descending from
745  // `parentNode`.
746  var filterFunc = function (elem) {
747    // handle jQuery's arguments to filter, where the node
748    // is in `this` and the index is the first argument.
749    if (typeof elem === 'number')
750      elem = this;
751
752    return self.containsElement(elem);
753  };
754
755  if (! results.filter) {
756    // not a jQuery array, and not a browser with
757    // Array.prototype.filter (e.g. IE <9)
758    var newResults = [];
759    for (var i = 0; i < results.length; i++) {
760      var x = results[i];
761      if (filterFunc(x))
762        newResults.push(x);
763    }
764    results = newResults;
765  } else {
766    // `results.filter` is either jQuery's or ECMAScript's `filter`
767    results = results.filter(filterFunc);
768  }
769
770  return results;
771};
772
773// Returns true if element a contains node b and is not node b.
774//
775// The restriction that `a` be an element (not a document fragment,
776// say) is based on what's easy to implement cross-browser.
777Blaze._elementContains = function (a, b) {
778  if (a.nodeType !== 1) // ELEMENT
779    return false;
780  if (a === b)
781    return false;
782
783  if (a.compareDocumentPosition) {
784    return a.compareDocumentPosition(b) & 0x10;
785  } else {
786    // Should be only old IE and maybe other old browsers here.
787    // Modern Safari has both functions but seems to get contains() wrong.
788    // IE can't handle b being a text node.  We work around this
789    // by doing a direct parent test now.
790    b = b.parentNode;
791    if (! (b && b.nodeType === 1)) // ELEMENT
792      return false;
793    if (a === b)
794      return true;
795
796    return a.contains(b);
797  }
798};
799
800/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
801
802}).call(this);
803
804
805
806
807
808
809(function(){
810
811/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
812//                                                                                                                     //
813// packages/blaze/events.js                                                                                            //
814//                                                                                                                     //
815/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
816                                                                                                                       //
817var EventSupport = Blaze._EventSupport = {};
818
819var DOMBackend = Blaze._DOMBackend;
820
821// List of events to always delegate, never capture.
822// Since jQuery fakes bubbling for certain events in
823// certain browsers (like `submit`), we don't want to
824// get in its way.
825//
826// We could list all known bubbling
827// events here to avoid creating speculative capturers
828// for them, but it would only be an optimization.
829var eventsToDelegate = EventSupport.eventsToDelegate = {
830  blur: 1, change: 1, click: 1, focus: 1, focusin: 1,
831  focusout: 1, reset: 1, submit: 1
832};
833
834var EVENT_MODE = EventSupport.EVENT_MODE = {
835  TBD: 0,
836  BUBBLING: 1,
837  CAPTURING: 2
838};
839
840var NEXT_HANDLERREC_ID = 1;
841
842var HandlerRec = function (elem, type, selector, handler, recipient) {
843  this.elem = elem;
844  this.type = type;
845  this.selector = selector;
846  this.handler = handler;
847  this.recipient = recipient;
848  this.id = (NEXT_HANDLERREC_ID++);
849
850  this.mode = EVENT_MODE.TBD;
851
852  // It's important that delegatedHandler be a different
853  // instance for each handlerRecord, because its identity
854  // is used to remove it.
855  //
856  // It's also important that the closure have access to
857  // `this` when it is not called with it set.
858  this.delegatedHandler = (function (h) {
859    return function (evt) {
860      if ((! h.selector) && evt.currentTarget !== evt.target)
861        // no selector means only fire on target
862        return;
863      return h.handler.apply(h.recipient, arguments);
864    };
865  })(this);
866
867  // WHY CAPTURE AND DELEGATE: jQuery can't delegate
868  // non-bubbling events, because
869  // event capture doesn't work in IE 8.  However, there
870  // are all sorts of new-fangled non-bubbling events
871  // like "play" and "touchenter".  We delegate these
872  // events using capture in all browsers except IE 8.
873  // IE 8 doesn't support these events anyway.
874
875  var tryCapturing = elem.addEventListener &&
876        (! _.has(eventsToDelegate,
877                 DOMBackend.Events.parseEventType(type)));
878
879  if (tryCapturing) {
880    this.capturingHandler = (function (h) {
881      return function (evt) {
882        if (h.mode === EVENT_MODE.TBD) {
883          // must be first time we're called.
884          if (evt.bubbles) {
885            // this type of event bubbles, so don't
886            // get called again.
887            h.mode = EVENT_MODE.BUBBLING;
888            DOMBackend.Events.unbindEventCapturer(
889              h.elem, h.type, h.capturingHandler);
890            return;
891          } else {
892            // this type of event doesn't bubble,
893            // so unbind the delegation, preventing
894            // it from ever firing.
895            h.mode = EVENT_MODE.CAPTURING;
896            DOMBackend.Events.undelegateEvents(
897              h.elem, h.type, h.delegatedHandler);
898          }
899        }
900
901        h.delegatedHandler(evt);
902      };
903    })(this);
904
905  } else {
906    this.mode = EVENT_MODE.BUBBLING;
907  }
908};
909EventSupport.HandlerRec = HandlerRec;
910
911HandlerRec.prototype.bind = function () {
912  // `this.mode` may be EVENT_MODE_TBD, in which case we bind both. in
913  // this case, 'capturingHandler' is in charge of detecting the
914  // correct mode and turning off one or the other handlers.
915  if (this.mode !== EVENT_MODE.BUBBLING) {
916    DOMBackend.Events.bindEventCapturer(
917      this.elem, this.type, this.selector || '*',
918      this.capturingHandler);
919  }
920
921  if (this.mode !== EVENT_MODE.CAPTURING)
922    DOMBackend.Events.delegateEvents(
923      this.elem, this.type,
924      this.selector || '*', this.delegatedHandler);
925};
926
927HandlerRec.prototype.unbind = function () {
928  if (this.mode !== EVENT_MODE.BUBBLING)
929    DOMBackend.Events.unbindEventCapturer(this.elem, this.type,
930                                          this.capturingHandler);
931
932  if (this.mode !== EVENT_MODE.CAPTURING)
933    DOMBackend.Events.undelegateEvents(this.elem, this.type,
934                                       this.delegatedHandler);
935};
936
937EventSupport.listen = function (element, events, selector, handler, recipient, getParentRecipient) {
938
939  // Prevent this method from being JITed by Safari.  Due to a
940  // presumed JIT bug in Safari -- observed in Version 7.0.6
941  // (9537.78.2) -- this method may crash the Safari render process if
942  // it is JITed.
943  // Repro: https://github.com/dgreensp/public/tree/master/safari-crash
944  try { element = element; } finally {}
945
946  var eventTypes = [];
947  events.replace(/[^ /]+/g, function (e) {
948    eventTypes.push(e);
949  });
950
951  var newHandlerRecs = [];
952  for (var i = 0, N = eventTypes.length; i < N; i++) {
953    var type = eventTypes[i];
954
955    var eventDict = element.$blaze_events;
956    if (! eventDict)
957      eventDict = (element.$blaze_events = {});
958
959    var info = eventDict[type];
960    if (! info) {
961      info = eventDict[type] = {};
962      info.handlers = [];
963    }
964    var handlerList = info.handlers;
965    var handlerRec = new HandlerRec(
966      element, type, selector, handler, recipient);
967    newHandlerRecs.push(handlerRec);
968    handlerRec.bind();
969    handlerList.push(handlerRec);
970    // Move handlers of enclosing ranges to end, by unbinding and rebinding
971    // them.  In jQuery (or other DOMBackend) this causes them to fire
972    // later when the backend dispatches event handlers.
973    if (getParentRecipient) {
974      for (var r = getParentRecipient(recipient); r;
975           r = getParentRecipient(r)) {
976        // r is an enclosing range (recipient)
977        for (var j = 0, Nj = handlerList.length;
978             j < Nj; j++) {
979          var h = handlerList[j];
980          if (h.recipient === r) {
981            h.unbind();
982            h.bind();
983            handlerList.splice(j, 1); // remove handlerList[j]
984            handlerList.push(h);
985            j--; // account for removed handler
986            Nj--; // don't visit appended handlers
987          }
988        }
989      }
990    }
991  }
992
993  return {
994    // closes over just `element` and `newHandlerRecs`
995    stop: function () {
996      var eventDict = element.$blaze_events;
997      if (! eventDict)
998        return;
999      // newHandlerRecs has only one item unless you specify multiple
1000      // event types.  If this code is slow, it's because we have to
1001      // iterate over handlerList here.  Clearing a whole handlerList
1002      // via stop() methods is O(N^2) in the number of handlers on
1003      // an element.
1004      for (var i = 0; i < newHandlerRecs.length; i++) {
1005        var handlerToRemove = newHandlerRecs[i];
1006        var info = eventDict[handlerToRemove.type];
1007        if (! info)
1008          continue;
1009        var handlerList = info.handlers;
1010        for (var j = handlerList.length - 1; j >= 0; j--) {
1011          if (handlerList[j] === handlerToRemove) {
1012            handlerToRemove.unbind();
1013            handlerList.splice(j, 1); // remove handlerList[j]
1014          }
1015        }
1016      }
1017      newHandlerRecs.length = 0;
1018    }
1019  };
1020};
1021
1022/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1023
1024}).call(this);
1025
1026
1027
1028
1029
1030
1031(function(){
1032
1033/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1034//                                                                                                                     //
1035// packages/blaze/attrs.js                                                                                             //
1036//                                                                                                                     //
1037/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1038                                                                                                                       //
1039var jsUrlsAllowed = false;
1040Blaze._allowJavascriptUrls = function () {
1041  jsUrlsAllowed = true;
1042};
1043Blaze._javascriptUrlsAllowed = function () {
1044  return jsUrlsAllowed;
1045};
1046
1047// An AttributeHandler object is responsible for updating a particular attribute
1048// of a particular element.  AttributeHandler subclasses implement
1049// browser-specific logic for dealing with particular attributes across
1050// different browsers.
1051//
1052// To define a new type of AttributeHandler, use
1053// `var FooHandler = AttributeHandler.extend({ update: function ... })`
1054// where the `update` function takes arguments `(element, oldValue, value)`.
1055// The `element` argument is always the same between calls to `update` on
1056// the same instance.  `oldValue` and `value` are each either `null` or
1057// a Unicode string of the type that might be passed to the value argument
1058// of `setAttribute` (i.e. not an HTML string with character references).
1059// When an AttributeHandler is installed, an initial call to `update` is
1060// always made with `oldValue = null`.  The `update` method can access
1061// `this.name` if the AttributeHandler class is a generic one that applies
1062// to multiple attribute names.
1063//
1064// AttributeHandlers can store custom properties on `this`, as long as they
1065// don't use the names `element`, `name`, `value`, and `oldValue`.
1066//
1067// AttributeHandlers can't influence how attributes appear in rendered HTML,
1068// only how they are updated after materialization as DOM.
1069
1070AttributeHandler = function (name, value) {
1071  this.name = name;
1072  this.value = value;
1073};
1074Blaze._AttributeHandler = AttributeHandler;
1075
1076AttributeHandler.prototype.update = function (element, oldValue, value) {
1077  if (value === null) {
1078    if (oldValue !== null)
1079      element.removeAttribute(this.name);
1080  } else {
1081    element.setAttribute(this.name, value);
1082  }
1083};
1084
1085AttributeHandler.extend = function (options) {
1086  var curType = this;
1087  var subType = function AttributeHandlerSubtype(/*arguments*/) {
1088    AttributeHandler.apply(this, arguments);
1089  };
1090  subType.prototype = new curType;
1091  subType.extend = curType.extend;
1092  if (options)
1093    _.extend(subType.prototype, options);
1094  return subType;
1095};
1096
1097/// Apply the diff between the attributes of "oldValue" and "value" to "element."
1098//
1099// Each subclass must implement a parseValue method which takes a string
1100// as an input and returns an ordered dict of attributes. The keys of the dict
1101// are unique identifiers (ie. css properties in the case of styles), and the
1102// values are the entire attribute which will be injected into the element.
1103//
1104// Extended below to support classes, SVG elements and styles.
1105
1106Blaze._DiffingAttributeHandler = AttributeHandler.extend({
1107  update: function (element, oldValue, value) {
1108    if (!this.getCurrentValue || !this.setValue || !this.parseValue || !this.joinValues)
1109      throw new Error("Missing methods in subclass of 'DiffingAttributeHandler'");
1110
1111    var oldAttrsMap = oldValue ? this.parseValue(oldValue) : new OrderedDict();
1112    var attrsMap = value ? this.parseValue(value) : new OrderedDict();
1113
1114    // the current attributes on the element, which we will mutate.
1115
1116    var currentAttrString = this.getCurrentValue(element);
1117    var currentAttrsMap = currentAttrString ? this.parseValue(currentAttrString) : new OrderedDict();
1118
1119    // Any outside changes to attributes we add at the end.
1120    currentAttrsMap.forEach(function (value, key, i) {
1121      // If the key already exists, we do not use the current value, but the new value.
1122      if (attrsMap.has(key)) {
1123        return;
1124      }
1125
1126      // Key does not already exist, but it existed before. Which means it was explicitly
1127      // removed, so we do not add it.
1128      if (oldAttrsMap.has(key)) {
1129        return;
1130      }
1131
1132      attrsMap.append(key, value);
1133    });
1134
1135    var values = [];
1136    attrsMap.forEach(function (value, key, i) {
1137      values.push(value);
1138    });
1139
1140    this.setValue(element, this.joinValues(values));
1141  }
1142});
1143
1144var ClassHandler = Blaze._DiffingAttributeHandler.extend({
1145  // @param rawValue {String}
1146  getCurrentValue: function (element) {
1147    return element.className;
1148  },
1149  setValue: function (element, className) {
1150    element.className = className;
1151  },
1152  parseValue: function (attrString) {
1153    var tokens = new OrderedDict();
1154
1155    _.each(attrString.split(' '), function(token) {
1156      if (token) {
1157        // Ordered dict requires unique keys.
1158        if (! tokens.has(token)) {
1159          tokens.append(token, token);
1160        }
1161      }
1162    });
1163    return tokens;
1164  },
1165  joinValues: function (values) {
1166    return values.join(' ');
1167  }
1168});
1169
1170var SVGClassHandler = ClassHandler.extend({
1171  getCurrentValue: function (element) {
1172    return element.className.baseVal;
1173  },
1174  setValue: function (element, className) {
1175    element.setAttribute('class', className);
1176  }
1177});
1178
1179var StyleHandler = Blaze._DiffingAttributeHandler.extend({
1180  getCurrentValue: function (element) {
1181    return element.getAttribute('style');
1182  },
1183  setValue: function (element, style) {
1184    if (style === '') {
1185      element.removeAttribute('style');
1186    } else {
1187      element.setAttribute('style', style);
1188    }
1189  },
1190
1191  // Parse a string to produce a map from property to attribute string.
1192  //
1193  // Example:
1194  // "color:red; foo:12px" produces a token {color: "color:red", foo:"foo:12px"}
1195  parseValue: function (attrString) {
1196    var tokens = new OrderedDict();
1197
1198    // Regex for parsing a css attribute declaration, taken from css-parse:
1199    // https://github.com/reworkcss/css-parse/blob/7cef3658d0bba872cde05a85339034b187cb3397/index.js#L219
1200    var regex = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*(?:\'(?:\\\'|.)*?\'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+[;\s]*/g;
1201    var match = regex.exec(attrString);
1202    while (match) {
1203      // match[0] = entire matching string
1204      // match[1] = css property
1205      // Prefix the token to prevent conflicts with existing properties.
1206
1207      // We use the last value for the same key.
1208      if (tokens.has(match[1])) {
1209        tokens.remove(match[1]);
1210      }
1211
1212      // XXX No `String.trim` on Safari 4. Swap out $.trim if we want to
1213      // remove strong dep on jquery.
1214      tokens.append(match[1], match[0].trim ? match[0].trim() : $.trim(match[0]));
1215
1216      match = regex.exec(attrString);
1217    }
1218
1219    return tokens;
1220  },
1221
1222  joinValues: function (values) {
1223    // TODO: Assure that there is always ; between values. But what is an example where it breaks?
1224    return values.join(' ');
1225  }
1226});
1227
1228var BooleanHandler = AttributeHandler.extend({
1229  update: function (element, oldValue, value) {
1230    var name = this.name;
1231    if (value == null) {
1232      if (oldValue != null)
1233        element[name] = false;
1234    } else {
1235      element[name] = true;
1236    }
1237  }
1238});
1239
1240var DOMPropertyHandler = AttributeHandler.extend({
1241  update: function (element, oldValue, value) {
1242    var name = this.name;
1243    if (value !== element[name])
1244      element[name] = value;
1245  }
1246});
1247
1248// attributes of the type 'xlink:something' should be set using
1249// the correct namespace in order to work
1250var XlinkHandler = AttributeHandler.extend({
1251  update: function(element, oldValue, value) {
1252    var NS = 'http://www.w3.org/1999/xlink';
1253    if (value === null) {
1254      if (oldValue !== null)
1255        element.removeAttributeNS(NS, this.name);
1256    } else {
1257      element.setAttributeNS(NS, this.name, this.value);
1258    }
1259  }
1260});
1261
1262// cross-browser version of `instanceof SVGElement`
1263var isSVGElement = function (elem) {
1264  return 'ownerSVGElement' in elem;
1265};
1266
1267var isUrlAttribute = function (tagName, attrName) {
1268  // Compiled from http://www.w3.org/TR/REC-html40/index/attributes.html
1269  // and
1270  // http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1
1271  var urlAttrs = {
1272    FORM: ['action'],
1273    BODY: ['background'],
1274    BLOCKQUOTE: ['cite'],
1275    Q: ['cite'],
1276    DEL: ['cite'],
1277    INS: ['cite'],
1278    OBJECT: ['classid', 'codebase', 'data', 'usemap'],
1279    APPLET: ['codebase'],
1280    A: ['href'],
1281    AREA: ['href'],
1282    LINK: ['href'],
1283    BASE: ['href'],
1284    IMG: ['longdesc', 'src', 'usemap'],
1285    FRAME: ['longdesc', 'src'],
1286    IFRAME: ['longdesc', 'src'],
1287    HEAD: ['profile'],
1288    SCRIPT: ['src'],
1289    INPUT: ['src', 'usemap', 'formaction'],
1290    BUTTON: ['formaction'],
1291    BASE: ['href'],
1292    MENUITEM: ['icon'],
1293    HTML: ['manifest'],
1294    VIDEO: ['poster']
1295  };
1296
1297  if (attrName === 'itemid') {
1298    return true;
1299  }
1300
1301  var urlAttrNames = urlAttrs[tagName] || [];
1302  return _.contains(urlAttrNames, attrName);
1303};
1304
1305// To get the protocol for a URL, we let the browser normalize it for
1306// us, by setting it as the href for an anchor tag and then reading out
1307// the 'protocol' property.
1308if (Meteor.isClient) {
1309  var anchorForNormalization = document.createElement('A');
1310}
1311
1312var getUrlProtocol = function (url) {
1313  if (Meteor.isClient) {
1314    anchorForNormalization.href = url;
1315    return (anchorForNormalization.protocol || "").toLowerCase();
1316  } else {
1317    throw new Error('getUrlProtocol not implemented on the server');
1318  }
1319};
1320
1321// UrlHandler is an attribute handler for all HTML attributes that take
1322// URL values. It disallows javascript: URLs, unless
1323// Blaze._allowJavascriptUrls() has been called. To detect javascript:
1324// urls, we set the attribute on a dummy anchor element and then read
1325// out the 'protocol' property of the attribute.
1326var origUpdate = AttributeHandler.prototype.update;
1327var UrlHandler = AttributeHandler.extend({
1328  update: function (element, oldValue, value) {
1329    var self = this;
1330    var args = arguments;
1331
1332    if (Blaze._javascriptUrlsAllowed()) {
1333      origUpdate.apply(self, args);
1334    } else {
1335      var isJavascriptProtocol = (getUrlProtocol(value) === "javascript:");
1336      var isVBScriptProtocol   = (getUrlProtocol(value) === "vbscript:");
1337      if (isJavascriptProtocol || isVBScriptProtocol) {
1338        Blaze._warn("URLs that use the 'javascript:' or 'vbscript:' protocol are not " +
1339                    "allowed in URL attribute values. " +
1340                    "Call Blaze._allowJavascriptUrls() " +
1341                    "to enable them.");
1342        origUpdate.apply(self, [element, oldValue, null]);
1343      } else {
1344        origUpdate.apply(self, args);
1345      }
1346    }
1347  }
1348});
1349
1350// XXX make it possible for users to register attribute handlers!
1351Blaze._makeAttributeHandler = function (elem, name, value) {
1352  // generally, use setAttribute but certain attributes need to be set
1353  // by directly setting a JavaScript property on the DOM element.
1354  if (name === 'class') {
1355    if (isSVGElement(elem)) {
1356      return new SVGClassHandler(name, value);
1357    } else {
1358      return new ClassHandler(name, value);
1359    }
1360  } else if (name === 'style') {
1361    return new StyleHandler(name, value);
1362  } else if ((elem.tagName === 'OPTION' && name === 'selected') ||
1363             (elem.tagName === 'INPUT' && name === 'checked') ||
1364             (elem.tagName === 'VIDEO' && name === 'muted')) {
1365    return new BooleanHandler(name, value);
1366  } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT')
1367             && name === 'value') {
1368    // internally, TEXTAREAs tracks their value in the 'value'
1369    // attribute just like INPUTs.
1370    return new DOMPropertyHandler(name, value);
1371  } else if (name.substring(0,6) === 'xlink:') {
1372    return new XlinkHandler(name.substring(6), value);
1373  } else if (isUrlAttribute(elem.tagName, name)) {
1374    return new UrlHandler(name, value);
1375  } else {
1376    return new AttributeHandler(name, value);
1377  }
1378
1379  // XXX will need one for 'style' on IE, though modern browsers
1380  // seem to handle setAttribute ok.
1381};
1382
1383
1384ElementAttributesUpdater = function (elem) {
1385  this.elem = elem;
1386  this.handlers = {};
1387};
1388
1389// Update attributes on `elem` to the dictionary `attrs`, whose
1390// values are strings.
1391ElementAttributesUpdater.prototype.update = function(newAttrs) {
1392  var elem = this.elem;
1393  var handlers = this.handlers;
1394
1395  for (var k in handlers) {
1396    if (! _.has(newAttrs, k)) {
1397      // remove attributes (and handlers) for attribute names
1398      // that don't exist as keys of `newAttrs` and so won't
1399      // be visited when traversing it.  (Attributes that
1400      // exist in the `newAttrs` object but are `null`
1401      // are handled later.)
1402      var handler = handlers[k];
1403      var oldValue = handler.value;
1404      handler.value = null;
1405      handler.update(elem, oldValue, null);
1406      delete handlers[k];
1407    }
1408  }
1409
1410  for (var k in newAttrs) {
1411    var handler = null;
1412    var oldValue = null;
1413    var value = newAttrs[k];
1414    if (! _.has(handlers, k)) {
1415      if (value !== null) {
1416        // make new handler
1417        handler = Blaze._makeAttributeHandler(elem, k, value);
1418        handlers[k] = handler;
1419      }
1420    } else {
1421      handler = handlers[k];
1422      oldValue = handler.value;
1423    }
1424    if (oldValue !== value) {
1425      handler.value = value;
1426      handler.update(elem, oldValue, value);
1427      if (value === null)
1428        delete handlers[k];
1429    }
1430  }
1431};
1432
1433/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1434
1435}).call(this);
1436
1437
1438
1439
1440
1441
1442(function(){
1443
1444/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1445//                                                                                                                     //
1446// packages/blaze/materializer.js                                                                                      //
1447//                                                                                                                     //
1448/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1449                                                                                                                       //
1450// Turns HTMLjs into DOM nodes and DOMRanges.
1451//
1452// - `htmljs`: the value to materialize, which may be any of the htmljs
1453//   types (Tag, CharRef, Comment, Raw, array, string, boolean, number,
1454//   null, or undefined) or a View or Template (which will be used to
1455//   construct a View).
1456// - `intoArray`: the array of DOM nodes and DOMRanges to push the output
1457//   into (required)
1458// - `parentView`: the View we are materializing content for (optional)
1459// - `_existingWorkStack`: optional argument, only used for recursive
1460//   calls when there is some other _materializeDOM on the call stack.
1461//   If _materializeDOM called your function and passed in a workStack,
1462//   pass it back when you call _materializeDOM (such as from a workStack
1463//   task).
1464//
1465// Returns `intoArray`, which is especially useful if you pass in `[]`.
1466Blaze._materializeDOM = function (htmljs, intoArray, parentView,
1467                                  _existingWorkStack) {
1468  // In order to use fewer stack frames, materializeDOMInner can push
1469  // tasks onto `workStack`, and they will be popped off
1470  // and run, last first, after materializeDOMInner returns.  The
1471  // reason we use a stack instead of a queue is so that we recurse
1472  // depth-first, doing newer tasks first.
1473  var workStack = (_existingWorkStack || []);
1474  materializeDOMInner(htmljs, intoArray, parentView, workStack);
1475
1476  if (! _existingWorkStack) {
1477    // We created the work stack, so we are responsible for finishing
1478    // the work.  Call each "task" function, starting with the top
1479    // of the stack.
1480    while (workStack.length) {
1481      // Note that running task() may push new items onto workStack.
1482      var task = workStack.pop();
1483      task();
1484    }
1485  }
1486
1487  return intoArray;
1488};
1489
1490var materializeDOMInner = function (htmljs, intoArray, parentView, workStack) {
1491  if (htmljs == null) {
1492    // null or undefined
1493    return;
1494  }
1495
1496  switch (typeof htmljs) {
1497  case 'string': case 'boolean': case 'number':
1498    intoArray.push(document.createTextNode(String(htmljs)));
1499    return;
1500  case 'object':
1501    if (htmljs.htmljsType) {
1502      switch (htmljs.htmljsType) {
1503      case HTML.Tag.htmljsType:
1504        intoArray.push(materializeTag(htmljs, parentView, workStack));
1505        return;
1506      case HTML.CharRef.htmljsType:
1507        intoArray.push(document.createTextNode(htmljs.str));
1508        return;
1509      case HTML.Comment.htmljsType:
1510        intoArray.push(document.createComment(htmljs.sanitizedValue));
1511        return;
1512      case HTML.Raw.htmljsType:
1513        // Get an array of DOM nodes by using the browser's HTML parser
1514        // (like innerHTML).
1515        var nodes = Blaze._DOMBackend.parseHTML(htmljs.value);
1516        for (var i = 0; i < nodes.length; i++)
1517          intoArray.push(nodes[i]);
1518        return;
1519      }
1520    } else if (HTML.isArray(htmljs)) {
1521      for (var i = htmljs.length-1; i >= 0; i--) {
1522        workStack.push(Blaze._bind(Blaze._materializeDOM, null,
1523                              htmljs[i], intoArray, parentView, workStack));
1524      }
1525      return;
1526    } else {
1527      if (htmljs instanceof Blaze.Template) {
1528        htmljs = htmljs.constructView();
1529        // fall through to Blaze.View case below
1530      }
1531      if (htmljs instanceof Blaze.View) {
1532        Blaze._materializeView(htmljs, parentView, workStack, intoArray);
1533        return;
1534      }
1535    }
1536  }
1537
1538  throw new Error("Unexpected object in htmljs: " + htmljs);
1539};
1540
1541var materializeTag = function (tag, parentView, workStack) {
1542  var tagName = tag.tagName;
1543  var elem;
1544  if ((HTML.isKnownSVGElement(tagName) || isSVGAnchor(tag))
1545      && document.createElementNS) {
1546    // inline SVG
1547    elem = document.createElementNS('http://www.w3.org/2000/svg', tagName);
1548  } else {
1549    // normal elements
1550    elem = document.createElement(tagName);
1551  }
1552
1553  var rawAttrs = tag.attrs;
1554  var children = tag.children;
1555  if (tagName === 'textarea' && tag.children.length &&
1556      ! (rawAttrs && ('value' in rawAttrs))) {
1557    // Provide very limited support for TEXTAREA tags with children
1558    // rather than a "value" attribute.
1559    // Reactivity in the form of Views nested in the tag's children
1560    // won't work.  Compilers should compile textarea contents into
1561    // the "value" attribute of the tag, wrapped in a function if there
1562    // is reactivity.
1563    if (typeof rawAttrs === 'function' ||
1564        HTML.isArray(rawAttrs)) {
1565      throw new Error("Can't have reactive children of TEXTAREA node; " +
1566                      "use the 'value' attribute instead.");
1567    }
1568    rawAttrs = _.extend({}, rawAttrs || null);
1569    rawAttrs.value = Blaze._expand(children, parentView);
1570    children = [];
1571  }
1572
1573  if (rawAttrs) {
1574    var attrUpdater = new ElementAttributesUpdater(elem);
1575    var updateAttributes = function () {
1576      var expandedAttrs = Blaze._expandAttributes(rawAttrs, parentView);
1577      var flattenedAttrs = HTML.flattenAttributes(expandedAttrs);
1578      var stringAttrs = {};
1579      for (var attrName in flattenedAttrs) {
1580        // map `null`, `undefined`, and `false` to null, which is important
1581        // so that attributes with nully values are considered absent.
1582        // stringify anything else (e.g. strings, booleans, numbers including 0).
1583        if (flattenedAttrs[attrName] == null || flattenedAttrs[attrName] === false)
1584          stringAttrs[attrName] = null;
1585        else
1586          stringAttrs[attrName] = Blaze._toText(flattenedAttrs[attrName],
1587                                                parentView,
1588                                                HTML.TEXTMODE.STRING);
1589      }
1590      attrUpdater.update(stringAttrs);
1591    };
1592    var updaterComputation;
1593    if (parentView) {
1594      updaterComputation =
1595        parentView.autorun(updateAttributes, undefined, 'updater');
1596    } else {
1597      updaterComputation = Tracker.nonreactive(function () {
1598        return Tracker.autorun(function () {
1599          Tracker._withCurrentView(parentView, updateAttributes);
1600        });
1601      });
1602    }
1603    Blaze._DOMBackend.Teardown.onElementTeardown(elem, function attrTeardown() {
1604      updaterComputation.stop();
1605    });
1606  }
1607
1608  if (children.length) {
1609    var childNodesAndRanges = [];
1610    // push this function first so that it's done last
1611    workStack.push(function () {
1612      for (var i = 0; i < childNodesAndRanges.length; i++) {
1613        var x = childNodesAndRanges[i];
1614        if (x instanceof Blaze._DOMRange)
1615          x.attach(elem);
1616        else
1617          elem.appendChild(x);
1618      }
1619    });
1620    // now push the task that calculates childNodesAndRanges
1621    workStack.push(Blaze._bind(Blaze._materializeDOM, null,
1622                          children, childNodesAndRanges, parentView,
1623                          workStack));
1624  }
1625
1626  return elem;
1627};
1628
1629
1630var isSVGAnchor = function (node) {
1631  // We generally aren't able to detect SVG <a> elements because
1632  // if "A" were in our list of known svg element names, then all
1633  // <a> nodes would be created using
1634  // `document.createElementNS`. But in the special case of <a
1635  // xlink:href="...">, we can at least detect that attribute and
1636  // create an SVG <a> tag in that case.
1637  //
1638  // However, we still have a general problem of knowing when to
1639  // use document.createElementNS and when to use
1640  // document.createElement; for example, font tags will always
1641  // be created as SVG elements which can cause other
1642  // problems. #1977
1643  return (node.tagName === "a" &&
1644          node.attrs &&
1645          node.attrs["xlink:href"] !== undefined);
1646};
1647
1648/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1649
1650}).call(this);
1651
1652
1653
1654
1655
1656
1657(function(){
1658
1659/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1660//                                                                                                                     //
1661// packages/blaze/exceptions.js                                                                                        //
1662//                                                                                                                     //
1663/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1664                                                                                                                       //
1665var debugFunc;
1666
1667// We call into user code in many places, and it's nice to catch exceptions
1668// propagated from user code immediately so that the whole system doesn't just
1669// break.  Catching exceptions is easy; reporting them is hard.  This helper
1670// reports exceptions.
1671//
1672// Usage:
1673//
1674// ```
1675// try {
1676//   // ... someStuff ...
1677// } catch (e) {
1678//   reportUIException(e);
1679// }
1680// ```
1681//
1682// An optional second argument overrides the default message.
1683
1684// Set this to `true` to cause `reportException` to throw
1685// the next exception rather than reporting it.  This is
1686// useful in unit tests that test error messages.
1687Blaze._throwNextException = false;
1688
1689Blaze._reportException = function (e, msg) {
1690  if (Blaze._throwNextException) {
1691    Blaze._throwNextException = false;
1692    throw e;
1693  }
1694
1695  if (! debugFunc)
1696    // adapted from Tracker
1697    debugFunc = function () {
1698      return (typeof Meteor !== "undefined" ? Meteor._debug :
1699              ((typeof console !== "undefined") && console.log ? console.log :
1700               function () {}));
1701    };
1702
1703  // In Chrome, `e.stack` is a multiline string that starts with the message
1704  // and contains a stack trace.  Furthermore, `console.log` makes it clickable.
1705  // `console.log` supplies the space between the two arguments.
1706  debugFunc()(msg || 'Exception caught in template:', e.stack || e.message || e);
1707};
1708
1709Blaze._wrapCatchingExceptions = function (f, where) {
1710  if (typeof f !== 'function')
1711    return f;
1712
1713  return function () {
1714    try {
1715      return f.apply(this, arguments);
1716    } catch (e) {
1717      Blaze._reportException(e, 'Exception in ' + where + ':');
1718    }
1719  };
1720};
1721
1722/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1723
1724}).call(this);
1725
1726
1727
1728
1729
1730
1731(function(){
1732
1733/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1734//                                                                                                                     //
1735// packages/blaze/view.js                                                                                              //
1736//                                                                                                                     //
1737/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1738                                                                                                                       //
1739/// [new] Blaze.View([name], renderMethod)
1740///
1741/// Blaze.View is the building block of reactive DOM.  Views have
1742/// the following features:
1743///
1744/// * lifecycle callbacks - Views are created, rendered, and destroyed,
1745///   and callbacks can be registered to fire when these things happen.
1746///
1747/// * parent pointer - A View points to its parentView, which is the
1748///   View that caused it to be rendered.  These pointers form a
1749///   hierarchy or tree of Views.
1750///
1751/// * render() method - A View's render() method specifies the DOM
1752///   (or HTML) content of the View.  If the method establishes
1753///   reactive dependencies, it may be re-run.
1754///
1755/// * a DOMRange - If a View is rendered to DOM, its position and
1756///   extent in the DOM are tracked using a DOMRange object.
1757///
1758/// When a View is constructed by calling Blaze.View, the View is
1759/// not yet considered "created."  It doesn't have a parentView yet,
1760/// and no logic has been run to initialize the View.  All real
1761/// work is deferred until at least creation time, when the onViewCreated
1762/// callbacks are fired, which happens when the View is "used" in
1763/// some way that requires it to be rendered.
1764///
1765/// ...more lifecycle stuff
1766///
1767/// `name` is an optional string tag identifying the View.  The only
1768/// time it's used is when looking in the View tree for a View of a
1769/// particular name; for example, data contexts are stored on Views
1770/// of name "with".  Names are also useful when debugging, so in
1771/// general it's good for functions that create Views to set the name.
1772/// Views associated with templates have names of the form "Template.foo".
1773
1774/**
1775 * @class
1776 * @summary Constructor for a View, which represents a reactive region of DOM.
1777 * @locus Client
1778 * @param {String} [name] Optional.  A name for this type of View.  See [`view.name`](#view_name).
1779 * @param {Function} renderFunction A function that returns [*renderable content*](#Renderable-Content).  In this function, `this` is bound to the View.
1780 */
1781Blaze.View = function (name, render) {
1782  if (! (this instanceof Blaze.View))
1783    // called without `new`
1784    return new Blaze.View(name, render);
1785
1786  if (typeof name === 'function') {
1787    // omitted "name" argument
1788    render = name;
1789    name = '';
1790  }
1791  this.name = name;
1792  this._render = render;
1793
1794  this._callbacks = {
1795    created: null,
1796    rendered: null,
1797    destroyed: null
1798  };
1799
1800  // Setting all properties here is good for readability,
1801  // and also may help Chrome optimize the code by keeping
1802  // the View object from changing shape too much.
1803  this.isCreated = false;
1804  this._isCreatedForExpansion = false;
1805  this.isRendered = false;
1806  this._isAttached = false;
1807  this.isDestroyed = false;
1808  this._isInRender = false;
1809  this.parentView = null;
1810  this._domrange = null;
1811  // This flag is normally set to false except for the cases when view's parent
1812  // was generated as part of expanding some syntactic sugar expressions or
1813  // methods.
1814  // Ex.: Blaze.renderWithData is an equivalent to creating a view with regular
1815  // Blaze.render and wrapping it into {{#with data}}{{/with}} view. Since the
1816  // users don't know anything about these generated parent views, Blaze needs
1817  // this information to be available on views to make smarter decisions. For
1818  // example: removing the generated parent view with the view on Blaze.remove.
1819  this._hasGeneratedParent = false;
1820  // Bindings accessible to children views (via view.lookup('name')) within the
1821  // closest template view.
1822  this._scopeBindings = {};
1823
1824  this.renderCount = 0;
1825};
1826
1827Blaze.View.prototype._render = function () { return null; };
1828
1829Blaze.View.prototype.onViewCreated = function (cb) {
1830  this._callbacks.created = this._callbacks.created || [];
1831  this._callbacks.created.push(cb);
1832};
1833
1834Blaze.View.prototype._onViewRendered = function (cb) {
1835  this._callbacks.rendered = this._callbacks.rendered || [];
1836  this._callbacks.rendered.push(cb);
1837};
1838
1839Blaze.View.prototype.onViewReady = function (cb) {
1840  var self = this;
1841  var fire = function () {
1842    Tracker.afterFlush(function () {
1843      if (! self.isDestroyed) {
1844        Blaze._withCurrentView(self, function () {
1845          cb.call(self);
1846        });
1847      }
1848    });
1849  };
1850  self._onViewRendered(function onViewRendered() {
1851    if (self.isDestroyed)
1852      return;
1853    if (! self._domrange.attached)
1854      self._domrange.onAttached(fire);
1855    else
1856      fire();
1857  });
1858};
1859
1860Blaze.View.prototype.onViewDestroyed = function (cb) {
1861  this._callbacks.destroyed = this._callbacks.destroyed || [];
1862  this._callbacks.destroyed.push(cb);
1863};
1864Blaze.View.prototype.removeViewDestroyedListener = function (cb) {
1865  var destroyed = this._callbacks.destroyed;
1866  if (! destroyed)
1867    return;
1868  var index = _.lastIndexOf(destroyed, cb);
1869  if (index !== -1) {
1870    // XXX You'd think the right thing to do would be splice, but _fireCallbacks
1871    // gets sad if you remove callbacks while iterating over the list.  Should
1872    // change this to use callback-hook or EventEmitter or something else that
1873    // properly supports removal.
1874    destroyed[index] = null;
1875  }
1876};
1877
1878/// View#autorun(func)
1879///
1880/// Sets up a Tracker autorun that is "scoped" to this View in two
1881/// important ways: 1) Blaze.currentView is automatically set
1882/// on every re-run, and 2) the autorun is stopped when the
1883/// View is destroyed.  As with Tracker.autorun, the first run of
1884/// the function is immediate, and a Computation object that can
1885/// be used to stop the autorun is returned.
1886///
1887/// View#autorun is meant to be called from View callbacks like
1888/// onViewCreated, or from outside the rendering process.  It may not
1889/// be called before the onViewCreated callbacks are fired (too early),
1890/// or from a render() method (too confusing).
1891///
1892/// Typically, autoruns that update the state
1893/// of the View (as in Blaze.With) should be started from an onViewCreated
1894/// callback.  Autoruns that update the DOM should be started
1895/// from either onViewCreated (guarded against the absence of
1896/// view._domrange), or onViewReady.
1897Blaze.View.prototype.autorun = function (f, _inViewScope, displayName) {
1898  var self = this;
1899
1900  // The restrictions on when View#autorun can be called are in order
1901  // to avoid bad patterns, like creating a Blaze.View and immediately
1902  // calling autorun on it.  A freshly created View is not ready to
1903  // have logic run on it; it doesn't have a parentView, for example.
1904  // It's when the View is materialized or expanded that the onViewCreated
1905  // handlers are fired and the View starts up.
1906  //
1907  // Letting the render() method call `this.autorun()` is problematic
1908  // because of re-render.  The best we can do is to stop the old
1909  // autorun and start a new one for each render, but that's a pattern
1910  // we try to avoid internally because it leads to helpers being
1911  // called extra times, in the case where the autorun causes the
1912  // view to re-render (and thus the autorun to be torn down and a
1913  // new one established).
1914  //
1915  // We could lift these restrictions in various ways.  One interesting
1916  // idea is to allow you to call `view.autorun` after instantiating
1917  // `view`, and automatically wrap it in `view.onViewCreated`, deferring
1918  // the autorun so that it starts at an appropriate time.  However,
1919  // then we can't return the Computation object to the caller, because
1920  // it doesn't exist yet.
1921  if (! self.isCreated) {
1922    throw new Error("View#autorun must be called from the created callback at the earliest");
1923  }
1924  if (this._isInRender) {
1925    throw new Error("Can't call View#autorun from inside render(); try calling it from the created or rendered callback");
1926  }
1927
1928  var templateInstanceFunc = Blaze.Template._currentTemplateInstanceFunc;
1929
1930  var func = function viewAutorun(c) {
1931    return Blaze._withCurrentView(_inViewScope || self, function () {
1932      return Blaze.Template._withTemplateInstanceFunc(
1933        templateInstanceFunc, function () {
1934          return f.call(self, c);
1935        });
1936    });
1937  };
1938
1939  // Give the autorun function a better name for debugging and profiling.
1940  // The `displayName` property is not part of the spec but browsers like Chrome
1941  // and Firefox prefer it in debuggers over the name function was declared by.
1942  func.displayName =
1943    (self.name || 'anonymous') + ':' + (displayName || 'anonymous');
1944  var comp = Tracker.autorun(func);
1945
1946  var stopComputation = function () { comp.stop(); };
1947  self.onViewDestroyed(stopComputation);
1948  comp.onStop(function () {
1949    self.removeViewDestroyedListener(stopComputation);
1950  });
1951
1952  return comp;
1953};
1954
1955Blaze.View.prototype._errorIfShouldntCallSubscribe = function () {
1956  var self = this;
1957
1958  if (! self.isCreated) {
1959    throw new Error("View#subscribe must be called from the created callback at the earliest");
1960  }
1961  if (self._isInRender) {
1962    throw new Error("Can't call View#subscribe from inside render(); try calling it from the created or rendered callback");
1963  }
1964  if (self.isDestroyed) {
1965    throw new Error("Can't call View#subscribe from inside the destroyed callback, try calling it inside created or rendered.");
1966  }
1967};
1968
1969/**
1970 * Just like Blaze.View#autorun, but with Meteor.subscribe instead of
1971 * Tracker.autorun. Stop the subscription when the view is destroyed.
1972 * @return {SubscriptionHandle} A handle to the subscription so that you can
1973 * see if it is ready, or stop it manually
1974 */
1975Blaze.View.prototype.subscribe = function (args, options) {
1976  var self = this;
1977  options = options || {};
1978
1979  self._errorIfShouldntCallSubscribe();
1980
1981  var subHandle;
1982  if (options.connection) {
1983    subHandle = options.connection.subscribe.apply(options.connection, args);
1984  } else {
1985    subHandle = Meteor.subscribe.apply(Meteor, args);
1986  }
1987
1988  self.onViewDestroyed(function () {
1989    subHandle.stop();
1990  });
1991
1992  return subHandle;
1993};
1994
1995Blaze.View.prototype.firstNode = function () {
1996  if (! this._isAttached)
1997    throw new Error("View must be attached before accessing its DOM");
1998
1999  return this._domrange.firstNode();
2000};
2001
2002Blaze.View.prototype.lastNode = function () {
2003  if (! this._isAttached)
2004    throw new Error("View must be attached before accessing its DOM");
2005
2006  return this._domrange.lastNode();
2007};
2008
2009Blaze._fireCallbacks = function (view, which) {
2010  Blaze._withCurrentView(view, function () {
2011    Tracker.nonreactive(function fireCallbacks() {
2012      var cbs = view._callbacks[which];
2013      for (var i = 0, N = (cbs && cbs.length); i < N; i++)
2014        cbs[i] && cbs[i].call(view);
2015    });
2016  });
2017};
2018
2019Blaze._createView = function (view, parentView, forExpansion) {
2020  if (view.isCreated)
2021    throw new Error("Can't render the same View twice");
2022
2023  view.parentView = (parentView || null);
2024  view.isCreated = true;
2025  if (forExpansion)
2026    view._isCreatedForExpansion = true;
2027
2028  Blaze._fireCallbacks(view, 'created');
2029};
2030
2031var doFirstRender = function (view, initialContent) {
2032  var domrange = new Blaze._DOMRange(initialContent);
2033  view._domrange = domrange;
2034  domrange.view = view;
2035  view.isRendered = true;
2036  Blaze._fireCallbacks(view, 'rendered');
2037
2038  var teardownHook = null;
2039
2040  domrange.onAttached(function attached(range, element) {
2041    view._isAttached = true;
2042
2043    teardownHook = Blaze._DOMBackend.Teardown.onElementTeardown(
2044      element, function teardown() {
2045        Blaze._destroyView(view, true /* _skipNodes */);
2046      });
2047  });
2048
2049  // tear down the teardown hook
2050  view.onViewDestroyed(function () {
2051    teardownHook && teardownHook.stop();
2052    teardownHook = null;
2053  });
2054
2055  return domrange;
2056};
2057
2058// Take an uncreated View `view` and create and render it to DOM,
2059// setting up the autorun that updates the View.  Returns a new
2060// DOMRange, which has been associated with the View.
2061//
2062// The private arguments `_workStack` and `_intoArray` are passed in
2063// by Blaze._materializeDOM and are only present for recursive calls
2064// (when there is some other _materializeView on the stack).  If
2065// provided, then we avoid the mutual recursion of calling back into
2066// Blaze._materializeDOM so that deep View hierarchies don't blow the
2067// stack.  Instead, we push tasks onto workStack for the initial
2068// rendering and subsequent setup of the View, and they are done after
2069// we return.  When there is a _workStack, we do not return the new
2070// DOMRange, but instead push it into _intoArray from a _workStack
2071// task.
2072Blaze._materializeView = function (view, parentView, _workStack, _intoArray) {
2073  Blaze._createView(view, parentView);
2074
2075  var domrange;
2076  var lastHtmljs;
2077  // We don't expect to be called in a Computation, but just in case,
2078  // wrap in Tracker.nonreactive.
2079  Tracker.nonreactive(function () {
2080    view.autorun(function doRender(c) {
2081      // `view.autorun` sets the current view.
2082      view.renderCount++;
2083      view._isInRender = true;
2084      // Any dependencies that should invalidate this Computation come
2085      // from this line:
2086      var htmljs = view._render();
2087      view._isInRender = false;
2088
2089      if (! c.firstRun && ! Blaze._isContentEqual(lastHtmljs, htmljs)) {
2090        Tracker.nonreactive(function doMaterialize() {
2091          // re-render
2092          var rangesAndNodes = Blaze._materializeDOM(htmljs, [], view);
2093          domrange.setMembers(rangesAndNodes);
2094          Blaze._fireCallbacks(view, 'rendered');
2095        });
2096      }
2097      lastHtmljs = htmljs;
2098
2099      // Causes any nested views to stop immediately, not when we call
2100      // `setMembers` the next time around the autorun.  Otherwise,
2101      // helpers in the DOM tree to be replaced might be scheduled
2102      // to re-run before we have a chance to stop them.
2103      Tracker.onInvalidate(function () {
2104        if (domrange) {
2105          domrange.destroyMembers();
2106        }
2107      });
2108    }, undefined, 'materialize');
2109
2110    // first render.  lastHtmljs is the first htmljs.
2111    var initialContents;
2112    if (! _workStack) {
2113      initialContents = Blaze._materializeDOM(lastHtmljs, [], view);
2114      domrange = doFirstRender(view, initialContents);
2115      initialContents = null; // help GC because we close over this scope a lot
2116    } else {
2117      // We're being called from Blaze._materializeDOM, so to avoid
2118      // recursion and save stack space, provide a description of the
2119      // work to be done instead of doing it.  Tasks pushed onto
2120      // _workStack will be done in LIFO order after we return.
2121      // The work will still be done within a Tracker.nonreactive,
2122      // because it will be done by some call to Blaze._materializeDOM
2123      // (which is always called in a Tracker.nonreactive).
2124      initialContents = [];
2125      // push this function first so that it happens last
2126      _workStack.push(function () {
2127        domrange = doFirstRender(view, initialContents);
2128        initialContents = null; // help GC because of all the closures here
2129        _intoArray.push(domrange);
2130      });
2131      // now push the task that calculates initialContents
2132      _workStack.push(Blaze._bind(Blaze._materializeDOM, null,
2133                             lastHtmljs, initialContents, view, _workStack));
2134    }
2135  });
2136
2137  if (! _workStack) {
2138    return domrange;
2139  } else {
2140    return null;
2141  }
2142};
2143
2144// Expands a View to HTMLjs, calling `render` recursively on all
2145// Views and evaluating any dynamic attributes.  Calls the `created`
2146// callback, but not the `materialized` or `rendered` callbacks.
2147// Destroys the view immediately, unless called in a Tracker Computation,
2148// in which case the view will be destroyed when the Computation is
2149// invalidated.  If called in a Tracker Computation, the result is a
2150// reactive string; that is, the Computation will be invalidated
2151// if any changes are made to the view or subviews that might affect
2152// the HTML.
2153Blaze._expandView = function (view, parentView) {
2154  Blaze._createView(view, parentView, true /*forExpansion*/);
2155
2156  view._isInRender = true;
2157  var htmljs = Blaze._withCurrentView(view, function () {
2158    return view._render();
2159  });
2160  view._isInRender = false;
2161
2162  var result = Blaze._expand(htmljs, view);
2163
2164  if (Tracker.active) {
2165    Tracker.onInvalidate(function () {
2166      Blaze._destroyView(view);
2167    });
2168  } else {
2169    Blaze._destroyView(view);
2170  }
2171
2172  return result;
2173};
2174
2175// Options: `parentView`
2176Blaze._HTMLJSExpander = HTML.TransformingVisitor.extend();
2177Blaze._HTMLJSExpander.def({
2178  visitObject: function (x) {
2179    if (x instanceof Blaze.Template)
2180      x = x.constructView();
2181    if (x instanceof Blaze.View)
2182      return Blaze._expandView(x, this.parentView);
2183
2184    // this will throw an error; other objects are not allowed!
2185    return HTML.TransformingVisitor.prototype.visitObject.call(this, x);
2186  },
2187  visitAttributes: function (attrs) {
2188    // expand dynamic attributes
2189    if (typeof attrs === 'function')
2190      attrs = Blaze._withCurrentView(this.parentView, attrs);
2191
2192    // call super (e.g. for case where `attrs` is an array)
2193    return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs);
2194  },
2195  visitAttribute: function (name, value, tag) {
2196    // expand attribute values that are functions.  Any attribute value
2197    // that contains Views must be wrapped in a function.
2198    if (typeof value === 'function')
2199      value = Blaze._withCurrentView(this.parentView, value);
2200
2201    return HTML.TransformingVisitor.prototype.visitAttribute.call(
2202      this, name, value, tag);
2203  }
2204});
2205
2206// Return Blaze.currentView, but only if it is being rendered
2207// (i.e. we are in its render() method).
2208var currentViewIfRendering = function () {
2209  var view = Blaze.currentView;
2210  return (view && view._isInRender) ? view : null;
2211};
2212
2213Blaze._expand = function (htmljs, parentView) {
2214  parentView = parentView || currentViewIfRendering();
2215  return (new Blaze._HTMLJSExpander(
2216    {parentView: parentView})).visit(htmljs);
2217};
2218
2219Blaze._expandAttributes = function (attrs, parentView) {
2220  parentView = parentView || currentViewIfRendering();
2221  return (new Blaze._HTMLJSExpander(
2222    {parentView: parentView})).visitAttributes(attrs);
2223};
2224
2225Blaze._destroyView = function (view, _skipNodes) {
2226  if (view.isDestroyed)
2227    return;
2228  view.isDestroyed = true;
2229
2230  Blaze._fireCallbacks(view, 'destroyed');
2231
2232  // Destroy views and elements recursively.  If _skipNodes,
2233  // only recurse up to views, not elements, for the case where
2234  // the backend (jQuery) is recursing over the elements already.
2235
2236  if (view._domrange)
2237    view._domrange.destroyMembers(_skipNodes);
2238};
2239
2240Blaze._destroyNode = function (node) {
2241  if (node.nodeType === 1)
2242    Blaze._DOMBackend.Teardown.tearDownElement(node);
2243};
2244
2245// Are the HTMLjs entities `a` and `b` the same?  We could be
2246// more elaborate here but the point is to catch the most basic
2247// cases.
2248Blaze._isContentEqual = function (a, b) {
2249  if (a instanceof HTML.Raw) {
2250    return (b instanceof HTML.Raw) && (a.value === b.value);
2251  } else if (a == null) {
2252    return (b == null);
2253  } else {
2254    return (a === b) &&
2255      ((typeof a === 'number') || (typeof a === 'boolean') ||
2256       (typeof a === 'string'));
2257  }
2258};
2259
2260/**
2261 * @summary The View corresponding to the current template helper, event handler, callback, or autorun.  If there isn't one, `null`.
2262 * @locus Client
2263 * @type {Blaze.View}
2264 */
2265Blaze.currentView = null;
2266
2267Blaze._withCurrentView = function (view, func) {
2268  var oldView = Blaze.currentView;
2269  try {
2270    Blaze.currentView = view;
2271    return func();
2272  } finally {
2273    Blaze.currentView = oldView;
2274  }
2275};
2276
2277// Blaze.render publicly takes a View or a Template.
2278// Privately, it takes any HTMLJS (extended with Views and Templates)
2279// except null or undefined, or a function that returns any extended
2280// HTMLJS.
2281var checkRenderContent = function (content) {
2282  if (content === null)
2283    throw new Error("Can't render null");
2284  if (typeof content === 'undefined')
2285    throw new Error("Can't render undefined");
2286
2287  if ((content instanceof Blaze.View) ||
2288      (content instanceof Blaze.Template) ||
2289      (typeof content === 'function'))
2290    return;
2291
2292  try {
2293    // Throw if content doesn't look like HTMLJS at the top level
2294    // (i.e. verify that this is an HTML.Tag, or an array,
2295    // or a primitive, etc.)
2296    (new HTML.Visitor).visit(content);
2297  } catch (e) {
2298    // Make error message suitable for public API
2299    throw new Error("Expected Template or View");
2300  }
2301};
2302
2303// For Blaze.render and Blaze.toHTML, take content and
2304// wrap it in a View, unless it's a single View or
2305// Template already.
2306var contentAsView = function (content) {
2307  checkRenderContent(content);
2308
2309  if (content instanceof Blaze.Template) {
2310    return content.constructView();
2311  } else if (content instanceof Blaze.View) {
2312    return content;
2313  } else {
2314    var func = content;
2315    if (typeof func !== 'function') {
2316      func = function () {
2317        return content;
2318      };
2319    }
2320    return Blaze.View('render', func);
2321  }
2322};
2323
2324// For Blaze.renderWithData and Blaze.toHTMLWithData, wrap content
2325// in a function, if necessary, so it can be a content arg to
2326// a Blaze.With.
2327var contentAsFunc = function (content) {
2328  checkRenderContent(content);
2329
2330  if (typeof content !== 'function') {
2331    return function () {
2332      return content;
2333    };
2334  } else {
2335    return content;
2336  }
2337};
2338
2339/**
2340 * @summary Renders a template or View to DOM nodes and inserts it into the DOM, returning a rendered [View](#Blaze-View) which can be passed to [`Blaze.remove`](#Blaze-remove).
2341 * @locus Client
2342 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render.  If a template, a View object is [constructed](#template_constructview).  If a View, it must be an unrendered View, which becomes a rendered View and is returned.
2343 * @param {DOMNode} parentNode The node that will be the parent of the rendered template.  It must be an Element node.
2344 * @param {DOMNode} [nextNode] Optional. If provided, must be a child of <em>parentNode</em>; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
2345 * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).
2346 */
2347Blaze.render = function (content, parentElement, nextNode, parentView) {
2348  if (! parentElement) {
2349    Blaze._warn("Blaze.render without a parent element is deprecated. " +
2350                "You must specify where to insert the rendered content.");
2351  }
2352
2353  if (nextNode instanceof Blaze.View) {
2354    // handle omitted nextNode
2355    parentView = nextNode;
2356    nextNode = null;
2357  }
2358
2359  // parentElement must be a DOM node. in particular, can't be the
2360  // result of a call to `$`. Can't check if `parentElement instanceof
2361  // Node` since 'Node' is undefined in IE8.
2362  if (parentElement && typeof parentElement.nodeType !== 'number')
2363    throw new Error("'parentElement' must be a DOM node");
2364  if (nextNode && typeof nextNode.nodeType !== 'number') // 'nextNode' is optional
2365    throw new Error("'nextNode' must be a DOM node");
2366
2367  parentView = parentView || currentViewIfRendering();
2368
2369  var view = contentAsView(content);
2370  Blaze._materializeView(view, parentView);
2371
2372  if (parentElement) {
2373    view._domrange.attach(parentElement, nextNode);
2374  }
2375
2376  return view;
2377};
2378
2379Blaze.insert = function (view, parentElement, nextNode) {
2380  Blaze._warn("Blaze.insert has been deprecated.  Specify where to insert the " +
2381              "rendered content in the call to Blaze.render.");
2382
2383  if (! (view && (view._domrange instanceof Blaze._DOMRange)))
2384    throw new Error("Expected template rendered with Blaze.render");
2385
2386  view._domrange.attach(parentElement, nextNode);
2387};
2388
2389/**
2390 * @summary Renders a template or View to DOM nodes with a data context.  Otherwise identical to `Blaze.render`.
2391 * @locus Client
2392 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object to render.
2393 * @param {Object|Function} data The data context to use, or a function returning a data context.  If a function is provided, it will be reactively re-run.
2394 * @param {DOMNode} parentNode The node that will be the parent of the rendered template.  It must be an Element node.
2395 * @param {DOMNode} [nextNode] Optional. If provided, must be a child of <em>parentNode</em>; the template will be inserted before this node. If not provided, the template will be inserted as the last child of parentNode.
2396 * @param {Blaze.View} [parentView] Optional. If provided, it will be set as the rendered View's [`parentView`](#view_parentview).
2397 */
2398Blaze.renderWithData = function (content, data, parentElement, nextNode, parentView) {
2399  // We defer the handling of optional arguments to Blaze.render.  At this point,
2400  // `nextNode` may actually be `parentView`.
2401  return Blaze.render(Blaze._TemplateWith(data, contentAsFunc(content)),
2402                          parentElement, nextNode, parentView);
2403};
2404
2405/**
2406 * @summary Removes a rendered View from the DOM, stopping all reactive updates and event listeners on it. Also destroys the Blaze.Template instance associated with the view.
2407 * @locus Client
2408 * @param {Blaze.View} renderedView The return value from `Blaze.render` or `Blaze.renderWithData`, or the `view` property of a Blaze.Template instance. Calling `Blaze.remove(Template.instance().view)` from within a template event handler will destroy the view as well as that template and trigger the template's `onDestroyed` handlers.
2409 */
2410Blaze.remove = function (view) {
2411  if (! (view && (view._domrange instanceof Blaze._DOMRange)))
2412    throw new Error("Expected template rendered with Blaze.render");
2413
2414  while (view) {
2415    if (! view.isDestroyed) {
2416      var range = view._domrange;
2417      if (range.attached && ! range.parentRange)
2418        range.detach();
2419      range.destroy();
2420    }
2421
2422    view = view._hasGeneratedParent && view.parentView;
2423  }
2424};
2425
2426/**
2427 * @summary Renders a template or View to a string of HTML.
2428 * @locus Client
2429 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.
2430 */
2431Blaze.toHTML = function (content, parentView) {
2432  parentView = parentView || currentViewIfRendering();
2433
2434  return HTML.toHTML(Blaze._expandView(contentAsView(content), parentView));
2435};
2436
2437/**
2438 * @summary Renders a template or View to HTML with a data context.  Otherwise identical to `Blaze.toHTML`.
2439 * @locus Client
2440 * @param {Template|Blaze.View} templateOrView The template (e.g. `Template.myTemplate`) or View object from which to generate HTML.
2441 * @param {Object|Function} data The data context to use, or a function returning a data context.
2442 */
2443Blaze.toHTMLWithData = function (content, data, parentView) {
2444  parentView = parentView || currentViewIfRendering();
2445
2446  return HTML.toHTML(Blaze._expandView(Blaze._TemplateWith(
2447    data, contentAsFunc(content)), parentView));
2448};
2449
2450Blaze._toText = function (htmljs, parentView, textMode) {
2451  if (typeof htmljs === 'function')
2452    throw new Error("Blaze._toText doesn't take a function, just HTMLjs");
2453
2454  if ((parentView != null) && ! (parentView instanceof Blaze.View)) {
2455    // omitted parentView argument
2456    textMode = parentView;
2457    parentView = null;
2458  }
2459  parentView = parentView || currentViewIfRendering();
2460
2461  if (! textMode)
2462    throw new Error("textMode required");
2463  if (! (textMode === HTML.TEXTMODE.STRING ||
2464         textMode === HTML.TEXTMODE.RCDATA ||
2465         textMode === HTML.TEXTMODE.ATTRIBUTE))
2466    throw new Error("Unknown textMode: " + textMode);
2467
2468  return HTML.toText(Blaze._expand(htmljs, parentView), textMode);
2469};
2470
2471/**
2472 * @summary Returns the current data context, or the data context that was used when rendering a particular DOM element or View from a Meteor template.
2473 * @locus Client
2474 * @param {DOMElement|Blaze.View} [elementOrView] Optional.  An element that was rendered by a Meteor, or a View.
2475 */
2476Blaze.getData = function (elementOrView) {
2477  var theWith;
2478
2479  if (! elementOrView) {
2480    theWith = Blaze.getView('with');
2481  } else if (elementOrView instanceof Blaze.View) {
2482    var view = elementOrView;
2483    theWith = (view.name === 'with' ? view :
2484               Blaze.getView(view, 'with'));
2485  } else if (typeof elementOrView.nodeType === 'number') {
2486    if (elementOrView.nodeType !== 1)
2487      throw new Error("Expected DOM element");
2488    theWith = Blaze.getView(elementOrView, 'with');
2489  } else {
2490    throw new Error("Expected DOM element or View");
2491  }
2492
2493  return theWith ? theWith.dataVar.get() : null;
2494};
2495
2496// For back-compat
2497Blaze.getElementData = function (element) {
2498  Blaze._warn("Blaze.getElementData has been deprecated.  Use " +
2499              "Blaze.getData(element) instead.");
2500
2501  if (element.nodeType !== 1)
2502    throw new Error("Expected DOM element");
2503
2504  return Blaze.getData(element);
2505};
2506
2507// Both arguments are optional.
2508
2509/**
2510 * @summary Gets either the current View, or the View enclosing the given DOM element.
2511 * @locus Client
2512 * @param {DOMElement} [element] Optional.  If specified, the View enclosing `element` is returned.
2513 */
2514Blaze.getView = function (elementOrView, _viewName) {
2515  var viewName = _viewName;
2516
2517  if ((typeof elementOrView) === 'string') {
2518    // omitted elementOrView; viewName present
2519    viewName = elementOrView;
2520    elementOrView = null;
2521  }
2522
2523  // We could eventually shorten the code by folding the logic
2524  // from the other methods into this method.
2525  if (! elementOrView) {
2526    return Blaze._getCurrentView(viewName);
2527  } else if (elementOrView instanceof Blaze.View) {
2528    return Blaze._getParentView(elementOrView, viewName);
2529  } else if (typeof elementOrView.nodeType === 'number') {
2530    return Blaze._getElementView(elementOrView, viewName);
2531  } else {
2532    throw new Error("Expected DOM element or View");
2533  }
2534};
2535
2536// Gets the current view or its nearest ancestor of name
2537// `name`.
2538Blaze._getCurrentView = function (name) {
2539  var view = Blaze.currentView;
2540  // Better to fail in cases where it doesn't make sense
2541  // to use Blaze._getCurrentView().  There will be a current
2542  // view anywhere it does.  You can check Blaze.currentView
2543  // if you want to know whether there is one or not.
2544  if (! view)
2545    throw new Error("There is no current view");
2546
2547  if (name) {
2548    while (view && view.name !== name)
2549      view = view.parentView;
2550    return view || null;
2551  } else {
2552    // Blaze._getCurrentView() with no arguments just returns
2553    // Blaze.currentView.
2554    return view;
2555  }
2556};
2557
2558Blaze._getParentView = function (view, name) {
2559  var v = view.parentView;
2560
2561  if (name) {
2562    while (v && v.name !== name)
2563      v = v.parentView;
2564  }
2565
2566  return v || null;
2567};
2568
2569Blaze._getElementView = function (elem, name) {
2570  var range = Blaze._DOMRange.forElement(elem);
2571  var view = null;
2572  while (range && ! view) {
2573    view = (range.view || null);
2574    if (! view) {
2575      if (range.parentRange)
2576        range = range.parentRange;
2577      else
2578        range = Blaze._DOMRange.forElement(range.parentElement);
2579    }
2580  }
2581
2582  if (name) {
2583    while (view && view.name !== name)
2584      view = view.parentView;
2585    return view || null;
2586  } else {
2587    return view;
2588  }
2589};
2590
2591Blaze._addEventMap = function (view, eventMap, thisInHandler) {
2592  thisInHandler = (thisInHandler || null);
2593  var handles = [];
2594
2595  if (! view._domrange)
2596    throw new Error("View must have a DOMRange");
2597
2598  view._domrange.onAttached(function attached_eventMaps(range, element) {
2599    _.each(eventMap, function (handler, spec) {
2600      var clauses = spec.split(/,\s+/);
2601      // iterate over clauses of spec, e.g. ['click .foo', 'click .bar']
2602      _.each(clauses, function (clause) {
2603        var parts = clause.split(/\s+/);
2604        if (parts.length === 0)
2605          return;
2606
2607        var newEvents = parts.shift();
2608        var selector = parts.join(' ');
2609        handles.push(Blaze._EventSupport.listen(
2610          element, newEvents, selector,
2611          function (evt) {
2612            if (! range.containsElement(evt.currentTarget))
2613              return null;
2614            var handlerThis = thisInHandler || this;
2615            var handlerArgs = arguments;
2616            return Blaze._withCurrentView(view, function () {
2617              return handler.apply(handlerThis, handlerArgs);
2618            });
2619          },
2620          range, function (r) {
2621            return r.parentRange;
2622          }));
2623      });
2624    });
2625  });
2626
2627  view.onViewDestroyed(function () {
2628    _.each(handles, function (h) {
2629      h.stop();
2630    });
2631    handles.length = 0;
2632  });
2633};
2634
2635/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2636
2637}).call(this);
2638
2639
2640
2641
2642
2643
2644(function(){
2645
2646/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2647//                                                                                                                     //
2648// packages/blaze/builtins.js                                                                                          //
2649//                                                                                                                     //
2650/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2651                                                                                                                       //
2652Blaze._calculateCondition = function (cond) {
2653  if (cond instanceof Array && cond.length === 0)
2654    cond = false;
2655  return !! cond;
2656};
2657
2658/**
2659 * @summary Constructs a View that renders content with a data context.
2660 * @locus Client
2661 * @param {Object|Function} data An object to use as the data context, or a function returning such an object.  If a function is provided, it will be reactively re-run.
2662 * @param {Function} contentFunc A Function that returns [*renderable content*](#Renderable-Content).
2663 */
2664Blaze.With = function (data, contentFunc) {
2665  var view = Blaze.View('with', contentFunc);
2666
2667  view.dataVar = new ReactiveVar;
2668
2669  view.onViewCreated(function () {
2670    if (typeof data === 'function') {
2671      // `data` is a reactive function
2672      view.autorun(function () {
2673        view.dataVar.set(data());
2674      }, view.parentView, 'setData');
2675    } else {
2676      view.dataVar.set(data);
2677    }
2678  });
2679
2680  return view;
2681};
2682
2683/**
2684 * Attaches bindings to the instantiated view.
2685 * @param {Object} bindings A dictionary of bindings, each binding name
2686 * corresponds to a value or a function that will be reactively re-run.
2687 * @param {View} view The target.
2688 */
2689Blaze._attachBindingsToView = function (bindings, view) {
2690  view.onViewCreated(function () {
2691    _.each(bindings, function (binding, name) {
2692      view._scopeBindings[name] = new ReactiveVar;
2693      if (typeof binding === 'function') {
2694        view.autorun(function () {
2695          view._scopeBindings[name].set(binding());
2696        }, view.parentView);
2697      } else {
2698        view._scopeBindings[name].set(binding);
2699      }
2700    });
2701  });
2702};
2703
2704/**
2705 * @summary Constructs a View setting the local lexical scope in the block.
2706 * @param {Function} bindings Dictionary mapping names of bindings to
2707 * values or computations to reactively re-run.
2708 * @param {Function} contentFunc A Function that returns [*renderable content*](#Renderable-Content).
2709 */
2710Blaze.Let = function (bindings, contentFunc) {
2711  var view = Blaze.View('let', contentFunc);
2712  Blaze._attachBindingsToView(bindings, view);
2713
2714  return view;
2715};
2716
2717/**
2718 * @summary Constructs a View that renders content conditionally.
2719 * @locus Client
2720 * @param {Function} conditionFunc A function to reactively re-run.  Whether the result is truthy or falsy determines whether `contentFunc` or `elseFunc` is shown.  An empty array is considered falsy.
2721 * @param {Function} contentFunc A Function that returns [*renderable content*](#Renderable-Content).
2722 * @param {Function} [elseFunc] Optional.  A Function that returns [*renderable content*](#Renderable-Content).  If no `elseFunc` is supplied, no content is shown in the "else" case.
2723 */
2724Blaze.If = function (conditionFunc, contentFunc, elseFunc, _not) {
2725  var conditionVar = new ReactiveVar;
2726
2727  var view = Blaze.View(_not ? 'unless' : 'if', function () {
2728    return conditionVar.get() ? contentFunc() :
2729      (elseFunc ? elseFunc() : null);
2730  });
2731  view.__conditionVar = conditionVar;
2732  view.onViewCreated(function () {
2733    this.autorun(function () {
2734      var cond = Blaze._calculateCondition(conditionFunc());
2735      conditionVar.set(_not ? (! cond) : cond);
2736    }, this.parentView, 'condition');
2737  });
2738
2739  return view;
2740};
2741
2742/**
2743 * @summary An inverted [`Blaze.If`](#Blaze-If).
2744 * @locus Client
2745 * @param {Function} conditionFunc A function to reactively re-run.  If the result is falsy, `contentFunc` is shown, otherwise `elseFunc` is shown.  An empty array is considered falsy.
2746 * @param {Function} contentFunc A Function that returns [*renderable content*](#Renderable-Content).
2747 * @param {Function} [elseFunc] Optional.  A Function that returns [*renderable content*](#Renderable-Content).  If no `elseFunc` is supplied, no content is shown in the "else" case.
2748 */
2749Blaze.Unless = function (conditionFunc, contentFunc, elseFunc) {
2750  return Blaze.If(conditionFunc, contentFunc, elseFunc, true /*_not*/);
2751};
2752
2753/**
2754 * @summary Constructs a View that renders `contentFunc` for each item in a sequence.
2755 * @locus Client
2756 * @param {Function} argFunc A function to reactively re-run. The function can
2757 * return one of two options:
2758 *
2759 * 1. An object with two fields: '_variable' and '_sequence'. Each iterates over
2760 *   '_sequence', it may be a Cursor, an array, null, or undefined. Inside the
2761 *   Each body you will be able to get the current item from the sequence using
2762 *   the name specified in the '_variable' field.
2763 *
2764 * 2. Just a sequence (Cursor, array, null, or undefined) not wrapped into an
2765 *   object. Inside the Each body, the current item will be set as the data
2766 *   context.
2767 * @param {Function} contentFunc A Function that returns  [*renderable
2768 * content*](#Renderable-Content).
2769 * @param {Function} [elseFunc] A Function that returns [*renderable
2770 * content*](#Renderable-Content) to display in the case when there are no items
2771 * in the sequence.
2772 */
2773Blaze.Each = function (argFunc, contentFunc, elseFunc) {
2774  var eachView = Blaze.View('each', function () {
2775    var subviews = this.initialSubviews;
2776    this.initialSubviews = null;
2777    if (this._isCreatedForExpansion) {
2778      this.expandedValueDep = new Tracker.Dependency;
2779      this.expandedValueDep.depend();
2780    }
2781    return subviews;
2782  });
2783  eachView.initialSubviews = [];
2784  eachView.numItems = 0;
2785  eachView.inElseMode = false;
2786  eachView.stopHandle = null;
2787  eachView.contentFunc = contentFunc;
2788  eachView.elseFunc = elseFunc;
2789  eachView.argVar = new ReactiveVar;
2790  eachView.variableName = null;
2791
2792  // update the @index value in the scope of all subviews in the range
2793  var updateIndices = function (from, to) {
2794    if (to === undefined) {
2795      to = eachView.numItems - 1;
2796    }
2797
2798    for (var i = from; i <= to; i++) {
2799      var view = eachView._domrange.members[i].view;
2800      view._scopeBindings['@index'].set(i);
2801    }
2802  };
2803
2804  eachView.onViewCreated(function () {
2805    // We evaluate argFunc in an autorun to make sure
2806    // Blaze.currentView is always set when it runs (rather than
2807    // passing argFunc straight to ObserveSequence).
2808    eachView.autorun(function () {
2809      // argFunc can return either a sequence as is or a wrapper object with a
2810      // _sequence and _variable fields set.
2811      var arg = argFunc();
2812      if (_.isObject(arg) && _.has(arg, '_sequence')) {
2813        eachView.variableName = arg._variable || null;
2814        arg = arg._sequence;
2815      }
2816
2817      eachView.argVar.set(arg);
2818    }, eachView.parentView, 'collection');
2819
2820    eachView.stopHandle = ObserveSequence.observe(function () {
2821      return eachView.argVar.get();
2822    }, {
2823      addedAt: function (id, item, index) {
2824        Tracker.nonreactive(function () {
2825          var newItemView;
2826          if (eachView.variableName) {
2827            // new-style #each (as in {{#each item in items}})
2828            // doesn't create a new data context
2829            newItemView = Blaze.View('item', eachView.contentFunc);
2830          } else {
2831            newItemView = Blaze.With(item, eachView.contentFunc);
2832          }
2833
2834          eachView.numItems++;
2835
2836          var bindings = {};
2837          bindings['@index'] = index;
2838          if (eachView.variableName) {
2839            bindings[eachView.variableName] = item;
2840          }
2841          Blaze._attachBindingsToView(bindings, newItemView);
2842
2843          if (eachView.expandedValueDep) {
2844            eachView.expandedValueDep.changed();
2845          } else if (eachView._domrange) {
2846            if (eachView.inElseMode) {
2847              eachView._domrange.removeMember(0);
2848              eachView.inElseMode = false;
2849            }
2850
2851            var range = Blaze._materializeView(newItemView, eachView);
2852            eachView._domrange.addMember(range, index);
2853            updateIndices(index);
2854          } else {
2855            eachView.initialSubviews.splice(index, 0, newItemView);
2856          }
2857        });
2858      },
2859      removedAt: function (id, item, index) {
2860        Tracker.nonreactive(function () {
2861          eachView.numItems--;
2862          if (eachView.expandedValueDep) {
2863            eachView.expandedValueDep.changed();
2864          } else if (eachView._domrange) {
2865            eachView._domrange.removeMember(index);
2866            updateIndices(index);
2867            if (eachView.elseFunc && eachView.numItems === 0) {
2868              eachView.inElseMode = true;
2869              eachView._domrange.addMember(
2870                Blaze._materializeView(
2871                  Blaze.View('each_else',eachView.elseFunc),
2872                  eachView), 0);
2873            }
2874          } else {
2875            eachView.initialSubviews.splice(index, 1);
2876          }
2877        });
2878      },
2879      changedAt: function (id, newItem, oldItem, index) {
2880        Tracker.nonreactive(function () {
2881          if (eachView.expandedValueDep) {
2882            eachView.expandedValueDep.changed();
2883          } else {
2884            var itemView;
2885            if (eachView._domrange) {
2886              itemView = eachView._domrange.getMember(index).view;
2887            } else {
2888              itemView = eachView.initialSubviews[index];
2889            }
2890            if (eachView.variableName) {
2891              itemView._scopeBindings[eachView.variableName].set(newItem);
2892            } else {
2893              itemView.dataVar.set(newItem);
2894            }
2895          }
2896        });
2897      },
2898      movedTo: function (id, item, fromIndex, toIndex) {
2899        Tracker.nonreactive(function () {
2900          if (eachView.expandedValueDep) {
2901            eachView.expandedValueDep.changed();
2902          } else if (eachView._domrange) {
2903            eachView._domrange.moveMember(fromIndex, toIndex);
2904            updateIndices(
2905              Math.min(fromIndex, toIndex), Math.max(fromIndex, toIndex));
2906          } else {
2907            var subviews = eachView.initialSubviews;
2908            var itemView = subviews[fromIndex];
2909            subviews.splice(fromIndex, 1);
2910            subviews.splice(toIndex, 0, itemView);
2911          }
2912        });
2913      }
2914    });
2915
2916    if (eachView.elseFunc && eachView.numItems === 0) {
2917      eachView.inElseMode = true;
2918      eachView.initialSubviews[0] =
2919        Blaze.View('each_else', eachView.elseFunc);
2920    }
2921  });
2922
2923  eachView.onViewDestroyed(function () {
2924    if (eachView.stopHandle)
2925      eachView.stopHandle.stop();
2926  });
2927
2928  return eachView;
2929};
2930
2931Blaze._TemplateWith = function (arg, contentFunc) {
2932  var w;
2933
2934  var argFunc = arg;
2935  if (typeof arg !== 'function') {
2936    argFunc = function () {
2937      return arg;
2938    };
2939  }
2940
2941  // This is a little messy.  When we compile `{{> Template.contentBlock}}`, we
2942  // wrap it in Blaze._InOuterTemplateScope in order to skip the intermediate
2943  // parent Views in the current template.  However, when there's an argument
2944  // (`{{> Template.contentBlock arg}}`), the argument needs to be evaluated
2945  // in the original scope.  There's no good order to nest
2946  // Blaze._InOuterTemplateScope and Spacebars.TemplateWith to achieve this,
2947  // so we wrap argFunc to run it in the "original parentView" of the
2948  // Blaze._InOuterTemplateScope.
2949  //
2950  // To make this better, reconsider _InOuterTemplateScope as a primitive.
2951  // Longer term, evaluate expressions in the proper lexical scope.
2952  var wrappedArgFunc = function () {
2953    var viewToEvaluateArg = null;
2954    if (w.parentView && w.parentView.name === 'InOuterTemplateScope') {
2955      viewToEvaluateArg = w.parentView.originalParentView;
2956    }
2957    if (viewToEvaluateArg) {
2958      return Blaze._withCurrentView(viewToEvaluateArg, argFunc);
2959    } else {
2960      return argFunc();
2961    }
2962  };
2963
2964  var wrappedContentFunc = function () {
2965    var content = contentFunc.call(this);
2966
2967    // Since we are generating the Blaze._TemplateWith view for the
2968    // user, set the flag on the child view.  If `content` is a template,
2969    // construct the View so that we can set the flag.
2970    if (content instanceof Blaze.Template) {
2971      content = content.constructView();
2972    }
2973    if (content instanceof Blaze.View) {
2974      content._hasGeneratedParent = true;
2975    }
2976
2977    return content;
2978  };
2979
2980  w = Blaze.With(wrappedArgFunc, wrappedContentFunc);
2981  w.__isTemplateWith = true;
2982  return w;
2983};
2984
2985Blaze._InOuterTemplateScope = function (templateView, contentFunc) {
2986  var view = Blaze.View('InOuterTemplateScope', contentFunc);
2987  var parentView = templateView.parentView;
2988
2989  // Hack so that if you call `{{> foo bar}}` and it expands into
2990  // `{{#with bar}}{{> foo}}{{/with}}`, and then `foo` is a template
2991  // that inserts `{{> Template.contentBlock}}`, the data context for
2992  // `Template.contentBlock` is not `bar` but the one enclosing that.
2993  if (parentView.__isTemplateWith)
2994    parentView = parentView.parentView;
2995
2996  view.onViewCreated(function () {
2997    this.originalParentView = this.parentView;
2998    this.parentView = parentView;
2999    this.__childDoesntStartNewLexicalScope = true;
3000  });
3001  return view;
3002};
3003
3004// XXX COMPAT WITH 0.9.0
3005Blaze.InOuterTemplateScope = Blaze._InOuterTemplateScope;
3006
3007/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3008
3009}).call(this);
3010
3011
3012
3013
3014
3015
3016(function(){
3017
3018/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3019//                                                                                                                     //
3020// packages/blaze/lookup.js                                                                                            //
3021//                                                                                                                     //
3022/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3023                                                                                                                       //
3024Blaze._globalHelpers = {};
3025
3026// Documented as Template.registerHelper.
3027// This definition also provides back-compat for `UI.registerHelper`.
3028Blaze.registerHelper = function (name, func) {
3029  Blaze._globalHelpers[name] = func;
3030};
3031
3032// Also documented as Template.deregisterHelper
3033Blaze.deregisterHelper = function(name) {
3034  delete Blaze._globalHelpers[name];
3035};
3036
3037var bindIfIsFunction = function (x, target) {
3038  if (typeof x !== 'function')
3039    return x;
3040  return Blaze._bind(x, target);
3041};
3042
3043// If `x` is a function, binds the value of `this` for that function
3044// to the current data context.
3045var bindDataContext = function (x) {
3046  if (typeof x === 'function') {
3047    return function () {
3048      var data = Blaze.getData();
3049      if (data == null)
3050        data = {};
3051      return x.apply(data, arguments);
3052    };
3053  }
3054  return x;
3055};
3056
3057Blaze._OLDSTYLE_HELPER = {};
3058
3059Blaze._getTemplateHelper = function (template, name, tmplInstanceFunc) {
3060  // XXX COMPAT WITH 0.9.3
3061  var isKnownOldStyleHelper = false;
3062
3063  if (template.__helpers.has(name)) {
3064    var helper = template.__helpers.get(name);
3065    if (helper === Blaze._OLDSTYLE_HELPER) {
3066      isKnownOldStyleHelper = true;
3067    } else if (helper != null) {
3068      return wrapHelper(bindDataContext(helper), tmplInstanceFunc);
3069    } else {
3070      return null;
3071    }
3072  }
3073
3074  // old-style helper
3075  if (name in template) {
3076    // Only warn once per helper
3077    if (! isKnownOldStyleHelper) {
3078      template.__helpers.set(name, Blaze._OLDSTYLE_HELPER);
3079      if (! template._NOWARN_OLDSTYLE_HELPERS) {
3080        Blaze._warn('Assigning helper with `' + template.viewName + '.' +
3081                    name + ' = ...` is deprecated.  Use `' + template.viewName +
3082                    '.helpers(...)` instead.');
3083      }
3084    }
3085    if (template[name] != null) {
3086      return wrapHelper(bindDataContext(template[name]), tmplInstanceFunc);
3087    }
3088  }
3089
3090  return null;
3091};
3092
3093var wrapHelper = function (f, templateFunc) {
3094  if (typeof f !== "function") {
3095    return f;
3096  }
3097
3098  return function () {
3099    var self = this;
3100    var args = arguments;
3101
3102    return Blaze.Template._withTemplateInstanceFunc(templateFunc, function () {
3103      return Blaze._wrapCatchingExceptions(f, 'template helper').apply(self, args);
3104    });
3105  };
3106};
3107
3108Blaze._lexicalBindingLookup = function (view, name) {
3109  var currentView = view;
3110  var blockHelpersStack = [];
3111
3112  // walk up the views stopping at a Spacebars.include or Template view that
3113  // doesn't have an InOuterTemplateScope view as a parent
3114  do {
3115    // skip block helpers views
3116    // if we found the binding on the scope, return it
3117    if (_.has(currentView._scopeBindings, name)) {
3118      var bindingReactiveVar = currentView._scopeBindings[name];
3119      return function () {
3120        return bindingReactiveVar.get();
3121      };
3122    }
3123  } while (! (currentView.__startsNewLexicalScope &&
3124              ! (currentView.parentView &&
3125                 currentView.parentView.__childDoesntStartNewLexicalScope))
3126           && (currentView = currentView.parentView));
3127
3128  return null;
3129};
3130
3131// templateInstance argument is provided to be available for possible
3132// alternative implementations of this function by 3rd party packages.
3133Blaze._getTemplate = function (name, templateInstance) {
3134  if ((name in Blaze.Template) && (Blaze.Template[name] instanceof Blaze.Template)) {
3135    return Blaze.Template[name];
3136  }
3137  return null;
3138};
3139
3140Blaze._getGlobalHelper = function (name, templateInstance) {
3141  if (Blaze._globalHelpers[name] != null) {
3142    return wrapHelper(bindDataContext(Blaze._globalHelpers[name]), templateInstance);
3143  }
3144  return null;
3145};
3146
3147// Looks up a name, like "foo" or "..", as a helper of the
3148// current template; the name of a template; a global helper;
3149// or a property of the data context.  Called on the View of
3150// a template (i.e. a View with a `.template` property,
3151// where the helpers are).  Used for the first name in a
3152// "path" in a template tag, like "foo" in `{{foo.bar}}` or
3153// ".." in `{{frobulate ../blah}}`.
3154//
3155// Returns a function, a non-function value, or null.  If
3156// a function is found, it is bound appropriately.
3157//
3158// NOTE: This function must not establish any reactive
3159// dependencies itself.  If there is any reactivity in the
3160// value, lookup should return a function.
3161Blaze.View.prototype.lookup = function (name, _options) {
3162  var template = this.template;
3163  var lookupTemplate = _options && _options.template;
3164  var helper;
3165  var binding;
3166  var boundTmplInstance;
3167  var foundTemplate;
3168
3169  if (this.templateInstance) {
3170    boundTmplInstance = Blaze._bind(this.templateInstance, this);
3171  }
3172
3173  // 0. looking up the parent data context with the special "../" syntax
3174  if (/^\./.test(name)) {
3175    // starts with a dot. must be a series of dots which maps to an
3176    // ancestor of the appropriate height.
3177    if (!/^(\.)+$/.test(name))
3178      throw new Error("id starting with dot must be a series of dots");
3179
3180    return Blaze._parentData(name.length - 1, true /*_functionWrapped*/);
3181
3182  }
3183
3184  // 1. look up a helper on the current template
3185  if (template && ((helper = Blaze._getTemplateHelper(template, name, boundTmplInstance)) != null)) {
3186    return helper;
3187  }
3188
3189  // 2. look up a binding by traversing the lexical view hierarchy inside the
3190  // current template
3191  if (template && (binding = Blaze._lexicalBindingLookup(Blaze.currentView, name)) != null) {
3192    return binding;
3193  }
3194
3195  // 3. look up a template by name
3196  if (lookupTemplate && ((foundTemplate = Blaze._getTemplate(name, boundTmplInstance)) != null)) {
3197    return foundTemplate;
3198  }
3199
3200  // 4. look up a global helper
3201  if ((helper = Blaze._getGlobalHelper(name, boundTmplInstance)) != null) {
3202    return helper;
3203  }
3204
3205  // 5. look up in a data context
3206  return function () {
3207    var isCalledAsFunction = (arguments.length > 0);
3208    var data = Blaze.getData();
3209    var x = data && data[name];
3210    if (! x) {
3211      if (lookupTemplate) {
3212        throw new Error("No such template: " + name);
3213      } else if (isCalledAsFunction) {
3214        throw new Error("No such function: " + name);
3215      } else if (name.charAt(0) === '@' && ((x === null) ||
3216                                            (x === undefined))) {
3217        // Throw an error if the user tries to use a `@directive`
3218        // that doesn't exist.  We don't implement all directives
3219        // from Handlebars, so there's a potential for confusion
3220        // if we fail silently.  On the other hand, we want to
3221        // throw late in case some app or package wants to provide
3222        // a missing directive.
3223        throw new Error("Unsupported directive: " + name);
3224      }
3225    }
3226    if (! data) {
3227      return null;
3228    }
3229    if (typeof x !== 'function') {
3230      if (isCalledAsFunction) {
3231        throw new Error("Can't call non-function: " + x);
3232      }
3233      return x;
3234    }
3235    return x.apply(data, arguments);
3236  };
3237};
3238
3239// Implement Spacebars' {{../..}}.
3240// @param height {Number} The number of '..'s
3241Blaze._parentData = function (height, _functionWrapped) {
3242  // If height is null or undefined, we default to 1, the first parent.
3243  if (height == null) {
3244    height = 1;
3245  }
3246  var theWith = Blaze.getView('with');
3247  for (var i = 0; (i < height) && theWith; i++) {
3248    theWith = Blaze.getView(theWith, 'with');
3249  }
3250
3251  if (! theWith)
3252    return null;
3253  if (_functionWrapped)
3254    return function () { return theWith.dataVar.get(); };
3255  return theWith.dataVar.get();
3256};
3257
3258
3259Blaze.View.prototype.lookupTemplate = function (name) {
3260  return this.lookup(name, {template:true});
3261};
3262
3263/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3264
3265}).call(this);
3266
3267
3268
3269
3270
3271
3272(function(){
3273
3274/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3275//                                                                                                                     //
3276// packages/blaze/template.js                                                                                          //
3277//                                                                                                                     //
3278/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3279                                                                                                                       //
3280// [new] Blaze.Template([viewName], renderFunction)
3281//
3282// `Blaze.Template` is the class of templates, like `Template.foo` in
3283// Meteor, which is `instanceof Template`.
3284//
3285// `viewKind` is a string that looks like "Template.foo" for templates
3286// defined by the compiler.
3287
3288/**
3289 * @class
3290 * @summary Constructor for a Template, which is used to construct Views with particular name and content.
3291 * @locus Client
3292 * @param {String} [viewName] Optional.  A name for Views constructed by this Template.  See [`view.name`](#view_name).
3293 * @param {Function} renderFunction A function that returns [*renderable content*](#Renderable-Content).  This function is used as the `renderFunction` for Views constructed by this Template.
3294 */
3295Blaze.Template = function (viewName, renderFunction) {
3296  if (! (this instanceof Blaze.Template))
3297    // called without `new`
3298    return new Blaze.Template(viewName, renderFunction);
3299
3300  if (typeof viewName === 'function') {
3301    // omitted "viewName" argument
3302    renderFunction = viewName;
3303    viewName = '';
3304  }
3305  if (typeof viewName !== 'string')
3306    throw new Error("viewName must be a String (or omitted)");
3307  if (typeof renderFunction !== 'function')
3308    throw new Error("renderFunction must be a function");
3309
3310  this.viewName = viewName;
3311  this.renderFunction = renderFunction;
3312
3313  this.__helpers = new HelperMap;
3314  this.__eventMaps = [];
3315
3316  this._callbacks = {
3317    created: [],
3318    rendered: [],
3319    destroyed: []
3320  };
3321};
3322var Template = Blaze.Template;
3323
3324var HelperMap = function () {};
3325HelperMap.prototype.get = function (name) {
3326  return this[' '+name];
3327};
3328HelperMap.prototype.set = function (name, helper) {
3329  this[' '+name] = helper;
3330};
3331HelperMap.prototype.has = function (name) {
3332  return (typeof this[' '+name] !== 'undefined');
3333};
3334
3335/**
3336 * @summary Returns true if `value` is a template object like `Template.myTemplate`.
3337 * @locus Client
3338 * @param {Any} value The value to test.
3339 */
3340Blaze.isTemplate = function (t) {
3341  return (t instanceof Blaze.Template);
3342};
3343
3344/**
3345 * @name  onCreated
3346 * @instance
3347 * @memberOf Template
3348 * @summary Register a function to be called when an instance of this template is created.
3349 * @param {Function} callback A function to be added as a callback.
3350 * @locus Client
3351 * @importFromPackage templating
3352 */
3353Template.prototype.onCreated = function (cb) {
3354  this._callbacks.created.push(cb);
3355};
3356
3357/**
3358 * @name  onRendered
3359 * @instance
3360 * @memberOf Template
3361 * @summary Register a function to be called when an instance of this template is inserted into the DOM.
3362 * @param {Function} callback A function to be added as a callback.
3363 * @locus Client
3364 * @importFromPackage templating
3365 */
3366Template.prototype.onRendered = function (cb) {
3367  this._callbacks.rendered.push(cb);
3368};
3369
3370/**
3371 * @name  onDestroyed
3372 * @instance
3373 * @memberOf Template
3374 * @summary Register a function to be called when an instance of this template is removed from the DOM and destroyed.
3375 * @param {Function} callback A function to be added as a callback.
3376 * @locus Client
3377 * @importFromPackage templating
3378 */
3379Template.prototype.onDestroyed = function (cb) {
3380  this._callbacks.destroyed.push(cb);
3381};
3382
3383Template.prototype._getCallbacks = function (which) {
3384  var self = this;
3385  var callbacks = self[which] ? [self[which]] : [];
3386  // Fire all callbacks added with the new API (Template.onRendered())
3387  // as well as the old-style callback (e.g. Template.rendered) for
3388  // backwards-compatibility.
3389  callbacks = callbacks.concat(self._callbacks[which]);
3390  return callbacks;
3391};
3392
3393var fireCallbacks = function (callbacks, template) {
3394  Template._withTemplateInstanceFunc(
3395    function () { return template; },
3396    function () {
3397      for (var i = 0, N = callbacks.length; i < N; i++) {
3398        callbacks[i].call(template);
3399      }
3400    });
3401};
3402
3403Template.prototype.constructView = function (contentFunc, elseFunc) {
3404  var self = this;
3405  var view = Blaze.View(self.viewName, self.renderFunction);
3406  view.template = self;
3407
3408  view.templateContentBlock = (
3409    contentFunc ? new Template('(contentBlock)', contentFunc) : null);
3410  view.templateElseBlock = (
3411    elseFunc ? new Template('(elseBlock)', elseFunc) : null);
3412
3413  if (self.__eventMaps || typeof self.events === 'object') {
3414    view._onViewRendered(function () {
3415      if (view.renderCount !== 1)
3416        return;
3417
3418      if (! self.__eventMaps.length && typeof self.events === "object") {
3419        // Provide limited back-compat support for `.events = {...}`
3420        // syntax.  Pass `template.events` to the original `.events(...)`
3421        // function.  This code must run only once per template, in
3422        // order to not bind the handlers more than once, which is
3423        // ensured by the fact that we only do this when `__eventMaps`
3424        // is falsy, and we cause it to be set now.
3425        Template.prototype.events.call(self, self.events);
3426      }
3427
3428      _.each(self.__eventMaps, function (m) {
3429        Blaze._addEventMap(view, m, view);
3430      });
3431    });
3432  }
3433
3434  view._templateInstance = new Blaze.TemplateInstance(view);
3435  view.templateInstance = function () {
3436    // Update data, firstNode, and lastNode, and return the TemplateInstance
3437    // object.
3438    var inst = view._templateInstance;
3439
3440    /**
3441     * @instance
3442     * @memberOf Blaze.TemplateInstance
3443     * @name  data
3444     * @summary The data context of this instance's latest invocation.
3445     * @locus Client
3446     */
3447    inst.data = Blaze.getData(view);
3448
3449    if (view._domrange && !view.isDestroyed) {
3450      inst.firstNode = view._domrange.firstNode();
3451      inst.lastNode = view._domrange.lastNode();
3452    } else {
3453      // on 'created' or 'destroyed' callbacks we don't have a DomRange
3454      inst.firstNode = null;
3455      inst.lastNode = null;
3456    }
3457
3458    return inst;
3459  };
3460
3461  /**
3462   * @name  created
3463   * @instance
3464   * @memberOf Template
3465   * @summary Provide a callback when an instance of a template is created.
3466   * @locus Client
3467   * @deprecated in 1.1
3468   */
3469  // To avoid situations when new callbacks are added in between view
3470  // instantiation and event being fired, decide on all callbacks to fire
3471  // immediately and then fire them on the event.
3472  var createdCallbacks = self._getCallbacks('created');
3473  view.onViewCreated(function () {
3474    fireCallbacks(createdCallbacks, view.templateInstance());
3475  });
3476
3477  /**
3478   * @name  rendered
3479   * @instance
3480   * @memberOf Template
3481   * @summary Provide a callback when an instance of a template is rendered.
3482   * @locus Client
3483   * @deprecated in 1.1
3484   */
3485  var renderedCallbacks = self._getCallbacks('rendered');
3486  view.onViewReady(function () {
3487    fireCallbacks(renderedCallbacks, view.templateInstance());
3488  });
3489
3490  /**
3491   * @name  destroyed
3492   * @instance
3493   * @memberOf Template
3494   * @summary Provide a callback when an instance of a template is destroyed.
3495   * @locus Client
3496   * @deprecated in 1.1
3497   */
3498  var destroyedCallbacks = self._getCallbacks('destroyed');
3499  view.onViewDestroyed(function () {
3500    fireCallbacks(destroyedCallbacks, view.templateInstance());
3501  });
3502
3503  return view;
3504};
3505
3506/**
3507 * @class
3508 * @summary The class for template instances
3509 * @param {Blaze.View} view
3510 * @instanceName template
3511 */
3512Blaze.TemplateInstance = function (view) {
3513  if (! (this instanceof Blaze.TemplateInstance))
3514    // called without `new`
3515    return new Blaze.TemplateInstance(view);
3516
3517  if (! (view instanceof Blaze.View))
3518    throw new Error("View required");
3519
3520  view._templateInstance = this;
3521
3522  /**
3523   * @name view
3524   * @memberOf Blaze.TemplateInstance
3525   * @instance
3526   * @summary The [View](../api/blaze.html#Blaze-View) object for this invocation of the template.
3527   * @locus Client
3528   * @type {Blaze.View}
3529   */
3530  this.view = view;
3531  this.data = null;
3532
3533  /**
3534   * @name firstNode
3535   * @memberOf Blaze.TemplateInstance
3536   * @instance
3537   * @summary The first top-level DOM node in this template instance.
3538   * @locus Client
3539   * @type {DOMNode}
3540   */
3541  this.firstNode = null;
3542
3543  /**
3544   * @name lastNode
3545   * @memberOf Blaze.TemplateInstance
3546   * @instance
3547   * @summary The last top-level DOM node in this template instance.
3548   * @locus Client
3549   * @type {DOMNode}
3550   */
3551  this.lastNode = null;
3552
3553  // This dependency is used to identify state transitions in
3554  // _subscriptionHandles which could cause the result of
3555  // TemplateInstance#subscriptionsReady to change. Basically this is triggered
3556  // whenever a new subscription handle is added or when a subscription handle
3557  // is removed and they are not ready.
3558  this._allSubsReadyDep = new Tracker.Dependency();
3559  this._allSubsReady = false;
3560
3561  this._subscriptionHandles = {};
3562};
3563
3564/**
3565 * @summary Find all elements matching `selector` in this template instance, and return them as a JQuery object.
3566 * @locus Client
3567 * @param {String} selector The CSS selector to match, scoped to the template contents.
3568 * @returns {DOMNode[]}
3569 */
3570Blaze.TemplateInstance.prototype.$ = function (selector) {
3571  var view = this.view;
3572  if (! view._domrange)
3573    throw new Error("Can't use $ on template instance with no DOM");
3574  return view._domrange.$(selector);
3575};
3576
3577/**
3578 * @summary Find all elements matching `selector` in this template instance.
3579 * @locus Client
3580 * @param {String} selector The CSS selector to match, scoped to the template contents.
3581 * @returns {DOMElement[]}
3582 */
3583Blaze.TemplateInstance.prototype.findAll = function (selector) {
3584  return Array.prototype.slice.call(this.$(selector));
3585};
3586
3587/**
3588 * @summary Find one element matching `selector` in this template instance.
3589 * @locus Client
3590 * @param {String} selector The CSS selector to match, scoped to the template contents.
3591 * @returns {DOMElement}
3592 */
3593Blaze.TemplateInstance.prototype.find = function (selector) {
3594  var result = this.$(selector);
3595  return result[0] || null;
3596};
3597
3598/**
3599 * @summary A version of [Tracker.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) that is stopped when the template is destroyed.
3600 * @locus Client
3601 * @param {Function} runFunc The function to run. It receives one argument: a Tracker.Computation object.
3602 */
3603Blaze.TemplateInstance.prototype.autorun = function (f) {
3604  return this.view.autorun(f);
3605};
3606
3607/**
3608 * @summary A version of [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe) that is stopped
3609 * when the template is destroyed.
3610 * @return {SubscriptionHandle} The subscription handle to the newly made
3611 * subscription. Call `handle.stop()` to manually stop the subscription, or
3612 * `handle.ready()` to find out if this particular subscription has loaded all
3613 * of its inital data.
3614 * @locus Client
3615 * @param {String} name Name of the subscription.  Matches the name of the
3616 * server's `publish()` call.
3617 * @param {Any} [arg1,arg2...] Optional arguments passed to publisher function
3618 * on server.
3619 * @param {Function|Object} [options] If a function is passed instead of an
3620 * object, it is interpreted as an `onReady` callback.
3621 * @param {Function} [options.onReady] Passed to [`Meteor.subscribe`](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe).
3622 * @param {Function} [options.onStop] Passed to [`Meteor.subscribe`](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe).
3623 * @param {DDP.Connection} [options.connection] The connection on which to make the
3624 * subscription.
3625 */
3626Blaze.TemplateInstance.prototype.subscribe = function (/* arguments */) {
3627  var self = this;
3628
3629  var subHandles = self._subscriptionHandles;
3630  var args = _.toArray(arguments);
3631
3632  // Duplicate logic from Meteor.subscribe
3633  var options = {};
3634  if (args.length) {
3635    var lastParam = _.last(args);
3636
3637    // Match pattern to check if the last arg is an options argument
3638    var lastParamOptionsPattern = {
3639      onReady: Match.Optional(Function),
3640      // XXX COMPAT WITH 1.0.3.1 onError used to exist, but now we use
3641      // onStop with an error callback instead.
3642      onError: Match.Optional(Function),
3643      onStop: Match.Optional(Function),
3644      connection: Match.Optional(Match.Any)
3645    };
3646
3647    if (_.isFunction(lastParam)) {
3648      options.onReady = args.pop();
3649    } else if (lastParam && ! _.isEmpty(lastParam) && Match.test(lastParam, lastParamOptionsPattern)) {
3650      options = args.pop();
3651    }
3652  }
3653
3654  var subHandle;
3655  var oldStopped = options.onStop;
3656  options.onStop = function (error) {
3657    // When the subscription is stopped, remove it from the set of tracked
3658    // subscriptions to avoid this list growing without bound
3659    delete subHandles[subHandle.subscriptionId];
3660
3661    // Removing a subscription can only change the result of subscriptionsReady
3662    // if we are not ready (that subscription could be the one blocking us being
3663    // ready).
3664    if (! self._allSubsReady) {
3665      self._allSubsReadyDep.changed();
3666    }
3667
3668    if (oldStopped) {
3669      oldStopped(error);
3670    }
3671  };
3672
3673  var connection = options.connection;
3674  var callbacks = _.pick(options, ["onReady", "onError", "onStop"]);
3675
3676  // The callbacks are passed as the last item in the arguments array passed to
3677  // View#subscribe
3678  args.push(callbacks);
3679
3680  // View#subscribe takes the connection as one of the options in the last
3681  // argument
3682  subHandle = self.view.subscribe.call(self.view, args, {
3683    connection: connection
3684  });
3685
3686  if (! _.has(subHandles, subHandle.subscriptionId)) {
3687    subHandles[subHandle.subscriptionId] = subHandle;
3688
3689    // Adding a new subscription will always cause us to transition from ready
3690    // to not ready, but if we are already not ready then this can't make us
3691    // ready.
3692    if (self._allSubsReady) {
3693      self._allSubsReadyDep.changed();
3694    }
3695  }
3696
3697  return subHandle;
3698};
3699
3700/**
3701 * @summary A reactive function that returns true when all of the subscriptions
3702 * called with [this.subscribe](#TemplateInstance-subscribe) are ready.
3703 * @return {Boolean} True if all subscriptions on this template instance are
3704 * ready.
3705 */
3706Blaze.TemplateInstance.prototype.subscriptionsReady = function () {
3707  this._allSubsReadyDep.depend();
3708
3709  this._allSubsReady = _.all(this._subscriptionHandles, function (handle) {
3710    return handle.ready();
3711  });
3712
3713  return this._allSubsReady;
3714};
3715
3716/**
3717 * @summary Specify template helpers available to this template.
3718 * @locus Client
3719 * @param {Object} helpers Dictionary of helper functions by name.
3720 * @importFromPackage templating
3721 */
3722Template.prototype.helpers = function (dict) {
3723  if (! _.isObject(dict)) {
3724    throw new Error("Helpers dictionary has to be an object");
3725  }
3726
3727  for (var k in dict)
3728    this.__helpers.set(k, dict[k]);
3729};
3730
3731var canUseGetters = function() {
3732  if (Object.defineProperty) {
3733    var obj = {};
3734    try {
3735      Object.defineProperty(obj, "self", {
3736        get: function () { return obj; }
3737      });
3738    } catch (e) {
3739      return false;
3740    }
3741    return obj.self === obj;
3742  }
3743  return false;
3744}();
3745
3746if (canUseGetters) {
3747  // Like Blaze.currentView but for the template instance. A function
3748  // rather than a value so that not all helpers are implicitly dependent
3749  // on the current template instance's `data` property, which would make
3750  // them dependent on the data context of the template inclusion.
3751  var currentTemplateInstanceFunc = null;
3752
3753  // If getters are supported, define this property with a getter function
3754  // to make it effectively read-only, and to work around this bizarre JSC
3755  // bug: https://github.com/meteor/meteor/issues/9926
3756  Object.defineProperty(Template, "_currentTemplateInstanceFunc", {
3757    get: function () {
3758      return currentTemplateInstanceFunc;
3759    }
3760  });
3761
3762  Template._withTemplateInstanceFunc = function (templateInstanceFunc, func) {
3763    if (typeof func !== 'function') {
3764      throw new Error("Expected function, got: " + func);
3765    }
3766    var oldTmplInstanceFunc = currentTemplateInstanceFunc;
3767    try {
3768      currentTemplateInstanceFunc = templateInstanceFunc;
3769      return func();
3770    } finally {
3771      currentTemplateInstanceFunc = oldTmplInstanceFunc;
3772    }
3773  };
3774
3775} else {
3776  // If getters are not supported, just use a normal property.
3777  Template._currentTemplateInstanceFunc = null;
3778
3779  Template._withTemplateInstanceFunc = function (templateInstanceFunc, func) {
3780    if (typeof func !== 'function') {
3781      throw new Error("Expected function, got: " + func);
3782    }
3783    var oldTmplInstanceFunc = Template._currentTemplateInstanceFunc;
3784    try {
3785      Template._currentTemplateInstanceFunc = templateInstanceFunc;
3786      return func();
3787    } finally {
3788      Template._currentTemplateInstanceFunc = oldTmplInstanceFunc;
3789    }
3790  };
3791}
3792
3793/**
3794 * @summary Specify event handlers for this template.
3795 * @locus Client
3796 * @param {EventMap} eventMap Event handlers to associate with this template.
3797 * @importFromPackage templating
3798 */
3799Template.prototype.events = function (eventMap) {
3800  if (! _.isObject(eventMap)) {
3801    throw new Error("Event map has to be an object");
3802  }
3803
3804  var template = this;
3805  var eventMap2 = {};
3806  for (var k in eventMap) {
3807    eventMap2[k] = (function (k, v) {
3808      return function (event/*, ...*/) {
3809        var view = this; // passed by EventAugmenter
3810        var data = Blaze.getData(event.currentTarget);
3811        if (data == null)
3812          data = {};
3813        var args = Array.prototype.slice.call(arguments);
3814        var tmplInstanceFunc = Blaze._bind(view.templateInstance, view);
3815        args.splice(1, 0, tmplInstanceFunc());
3816
3817        return Template._withTemplateInstanceFunc(tmplInstanceFunc, function () {
3818          return v.apply(data, args);
3819        });
3820      };
3821    })(k, eventMap[k]);
3822  }
3823
3824  template.__eventMaps.push(eventMap2);
3825};
3826
3827/**
3828 * @function
3829 * @name instance
3830 * @memberOf Template
3831 * @summary The [template instance](#Template-instances) corresponding to the current template helper, event handler, callback, or autorun.  If there isn't one, `null`.
3832 * @locus Client
3833 * @returns {Blaze.TemplateInstance}
3834 * @importFromPackage templating
3835 */
3836Template.instance = function () {
3837  return Template._currentTemplateInstanceFunc
3838    && Template._currentTemplateInstanceFunc();
3839};
3840
3841// Note: Template.currentData() is documented to take zero arguments,
3842// while Blaze.getData takes up to one.
3843
3844/**
3845 * @summary
3846 *
3847 * - Inside an `onCreated`, `onRendered`, or `onDestroyed` callback, returns
3848 * the data context of the template.
3849 * - Inside an event handler, returns the data context of the template on which
3850 * this event handler was defined.
3851 * - Inside a helper, returns the data context of the DOM node where the helper
3852 * was used.
3853 *
3854 * Establishes a reactive dependency on the result.
3855 * @locus Client
3856 * @function
3857 * @importFromPackage templating
3858 */
3859Template.currentData = Blaze.getData;
3860
3861/**
3862 * @summary Accesses other data contexts that enclose the current data context.
3863 * @locus Client
3864 * @function
3865 * @param {Integer} [numLevels] The number of levels beyond the current data context to look. Defaults to 1.
3866 * @importFromPackage templating
3867 */
3868Template.parentData = Blaze._parentData;
3869
3870/**
3871 * @summary Defines a [helper function](#Template-helpers) which can be used from all templates.
3872 * @locus Client
3873 * @function
3874 * @param {String} name The name of the helper function you are defining.
3875 * @param {Function} function The helper function itself.
3876 * @importFromPackage templating
3877 */
3878Template.registerHelper = Blaze.registerHelper;
3879
3880/**
3881 * @summary Removes a global [helper function](#Template-helpers).
3882 * @locus Client
3883 * @function
3884 * @param {String} name The name of the helper function you are defining.
3885 * @importFromPackage templating
3886 */
3887Template.deregisterHelper = Blaze.deregisterHelper;
3888
3889/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3890
3891}).call(this);
3892
3893
3894
3895
3896
3897
3898(function(){
3899
3900/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3901//                                                                                                                     //
3902// packages/blaze/backcompat.js                                                                                        //
3903//                                                                                                                     //
3904/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3905                                                                                                                       //
3906UI = Blaze;
3907
3908Blaze.ReactiveVar = ReactiveVar;
3909UI._templateInstance = Blaze.Template.instance;
3910
3911Handlebars = {};
3912Handlebars.registerHelper = Blaze.registerHelper;
3913
3914Handlebars._escape = Blaze._escape;
3915
3916// Return these from {{...}} helpers to achieve the same as returning
3917// strings from {{{...}}} helpers
3918Handlebars.SafeString = function(string) {
3919  this.string = string;
3920};
3921Handlebars.SafeString.prototype.toString = function() {
3922  return this.string.toString();
3923};
3924
3925/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3926
3927}).call(this);
3928
3929
3930/* Exports */
3931Package._define("blaze", {
3932  Blaze: Blaze,
3933  UI: UI,
3934  Handlebars: Handlebars
3935});
3936
3937})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.