469 lines
14 KiB
JavaScript
469 lines
14 KiB
JavaScript
//////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// This is a generated file. You can view the original //
|
|
// source in your browser if your browser supports source maps. //
|
|
// Source maps are supported by all recent versions of Chrome, Safari, //
|
|
// and Firefox, and by Internet Explorer 11. //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
(function () {
|
|
|
|
/* Imports */
|
|
var Meteor = Package.meteor.Meteor;
|
|
var global = Package.meteor.global;
|
|
var meteorEnv = Package.meteor.meteorEnv;
|
|
var _ = Package.underscore._;
|
|
var Tracker = Package.tracker.Tracker;
|
|
var Deps = Package.tracker.Deps;
|
|
var ReactiveDict = Package['reactive-dict'].ReactiveDict;
|
|
var Template = Package['templating-runtime'].Template;
|
|
var Iron = Package['iron:core'].Iron;
|
|
var Blaze = Package.blaze.Blaze;
|
|
var UI = Package.blaze.UI;
|
|
var Handlebars = Package.blaze.Handlebars;
|
|
var Spacebars = Package.spacebars.Spacebars;
|
|
var HTML = Package.htmljs.HTML;
|
|
|
|
/* Package-scope variables */
|
|
var WaitList, Controller;
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/iron_controller/lib/wait_list.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/*****************************************************************************/
|
|
/* Imports */
|
|
/*****************************************************************************/
|
|
var assert = Iron.utils.assert;
|
|
|
|
/*****************************************************************************/
|
|
/* Private */
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* Returns an object of computation ids starting with
|
|
* the current computation and including all ancestor
|
|
* computations. The data structure is an object
|
|
* so we can index by id and do quick checks.
|
|
*/
|
|
var parentComputations = function () {
|
|
var list = {};
|
|
var c = Deps.currentComputation;
|
|
|
|
while (c) {
|
|
list[String(c._id)] = true;
|
|
c = c._parent;
|
|
}
|
|
|
|
return list;
|
|
};
|
|
|
|
/**
|
|
* Check whether the user has called ready() and then called wait(). This
|
|
* can cause a condition that can be simplified to this:
|
|
*
|
|
* dep = new Deps.Dependency;
|
|
*
|
|
* Deps.autorun(function () {
|
|
* dep.depend();
|
|
* dep.changed();
|
|
* });
|
|
*/
|
|
var assertNoInvalidationLoop = function (dependency) {
|
|
var parentComps = parentComputations();
|
|
var depCompIds = _.keys(dependency._dependentsById);
|
|
|
|
_.each(depCompIds, function (id) {
|
|
assert(!parentComps[id], "\n\n\
|
|
You called wait() after calling ready() inside the same computation tree.\
|
|
\n\n\
|
|
You can fix this problem in two possible ways:\n\n\
|
|
1) Put all of your wait() calls before any ready() calls.\n\
|
|
2) Put your ready() call in its own computation with Deps.autorun."
|
|
);
|
|
});
|
|
};
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* WaitList */
|
|
/*****************************************************************************/
|
|
/**
|
|
* A WaitList tracks a list of reactive functions, each in its own computation.
|
|
* The list is ready() when all of the functions return true. This list is not
|
|
* ready (i.e. this.ready() === false) if at least one function returns false.
|
|
*
|
|
* You add functions by calling the wait(fn) method. Each function is run its
|
|
* own computation. The ready() method is a reactive method but only calls the
|
|
* deps changed function if the overall state of the list changes from true to
|
|
* false or from false to true.
|
|
*/
|
|
WaitList = function () {
|
|
this._readyDep = new Deps.Dependency;
|
|
this._comps = [];
|
|
this._notReadyCount = 0;
|
|
};
|
|
|
|
/**
|
|
* Pass a function that returns true or false.
|
|
*/
|
|
WaitList.prototype.wait = function (fn) {
|
|
var self = this;
|
|
|
|
var activeComp = Deps.currentComputation;
|
|
|
|
assertNoInvalidationLoop(self._readyDep);
|
|
|
|
// break with parent computation and grab the new comp
|
|
Deps.nonreactive(function () {
|
|
|
|
// store the cached result so we can see if it's different from one run to
|
|
// the next.
|
|
var cachedResult = null;
|
|
|
|
// create a computation for this handle
|
|
var comp = Deps.autorun(function (c) {
|
|
// let's get the new result coerced into a true or false value.
|
|
var result = !!fn();
|
|
|
|
var oldNotReadyCount = self._notReadyCount;
|
|
|
|
// if it's the first run and we're false then inc
|
|
if (c.firstRun && !result)
|
|
self._notReadyCount++;
|
|
else if (cachedResult !== null && result !== cachedResult && result === true)
|
|
self._notReadyCount--;
|
|
else if (cachedResult !== null && result !== cachedResult && result === false)
|
|
self._notReadyCount++;
|
|
|
|
cachedResult = result;
|
|
|
|
if (oldNotReadyCount === 0 && self._notReadyCount > 0)
|
|
self._readyDep.changed();
|
|
else if (oldNotReadyCount > 0 && self._notReadyCount === 0)
|
|
self._readyDep.changed();
|
|
});
|
|
|
|
self._comps.push(comp);
|
|
|
|
if (activeComp) {
|
|
activeComp.onInvalidate(function () {
|
|
// keep the old computation and notReadyCount the same for one
|
|
// flush cycle so that we don't end up in an intermediate state
|
|
// where list.ready() is not correct.
|
|
|
|
// keep the state the same until the flush cycle is complete
|
|
Deps.afterFlush(function () {
|
|
// stop the computation
|
|
comp.stop();
|
|
|
|
// remove the computation from the list
|
|
self._comps.splice(_.indexOf(self._comps, comp), 1);
|
|
|
|
if (cachedResult === false) {
|
|
self._notReadyCount--;
|
|
|
|
if (self._notReadyCount === 0)
|
|
self._readyDep.changed();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
WaitList.prototype.ready = function () {
|
|
this._readyDep.depend();
|
|
return this._notReadyCount === 0;
|
|
};
|
|
|
|
WaitList.prototype.stop = function () {
|
|
_.each(this._comps, function (c) { c.stop(); });
|
|
this._comps = [];
|
|
};
|
|
|
|
Iron.WaitList = WaitList;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/iron_controller/lib/controller.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/*****************************************************************************/
|
|
/* Imports */
|
|
/*****************************************************************************/
|
|
var debug = Iron.utils.debug('iron:controller');
|
|
var Layout = Iron.Layout;
|
|
var DynamicTemplate = Iron.DynamicTemplate;
|
|
|
|
/*****************************************************************************/
|
|
/* Private */
|
|
/*****************************************************************************/
|
|
var bindData = function (value, thisArg) {
|
|
return function () {
|
|
return (typeof value === 'function') ? value.apply(thisArg, arguments) : value;
|
|
};
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* Controller */
|
|
/*****************************************************************************/
|
|
Controller = function (options) {
|
|
var self = this;
|
|
this.options = options || {};
|
|
this._layout = this.options.layout || new Layout(this.options);
|
|
this._isController = true;
|
|
this._layout._setLookupHost(this);
|
|
|
|
// grab the event map from the Controller constructor which was
|
|
// set if the user does MyController.events({...});
|
|
var eventMap = Controller._collectEventMaps.call(this.constructor);
|
|
this._layout.events(eventMap, this);
|
|
|
|
this.init(options);
|
|
};
|
|
|
|
/**
|
|
* Set or get the layout's template and optionally its data context.
|
|
*/
|
|
Controller.prototype.layout = function (template, options) {
|
|
var self = this;
|
|
|
|
this._layout.template(template);
|
|
|
|
// check whether options has a data property
|
|
if (options && (_.has(options, 'data')))
|
|
this._layout.data(bindData(options.data, this));
|
|
|
|
return {
|
|
data: function (val) {
|
|
return self._layout.data(bindData(val, self));
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Render a template into a region of the layout.
|
|
*/
|
|
Controller.prototype.render = function (template, options) {
|
|
var self = this;
|
|
|
|
if (options && (typeof options.data !== 'undefined'))
|
|
options.data = bindData(options.data, this);
|
|
|
|
var tmpl = this._layout.render(template, options);
|
|
|
|
// allow caller to do: this.render('MyTemplate').data(function () {...});
|
|
return {
|
|
data: function (func) {
|
|
return tmpl.data(bindData(func, self));
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Begin recording rendered regions.
|
|
*/
|
|
Controller.prototype.beginRendering = function (onComplete) {
|
|
return this._layout.beginRendering(onComplete);
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* Controller Static Methods */
|
|
/*****************************************************************************/
|
|
/**
|
|
* Inherit from Controller.
|
|
*
|
|
* Note: The inheritance function in Meteor._inherits is broken. Static
|
|
* properties on functions don't get copied.
|
|
*/
|
|
Controller.extend = function (props) {
|
|
return Iron.utils.extend(this, props);
|
|
};
|
|
|
|
Controller.events = function (events) {
|
|
this._eventMap = events;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Returns a single event map merged from super to child.
|
|
* Called from the constructor function like this:
|
|
*
|
|
* this.constructor._collectEventMaps()
|
|
*/
|
|
|
|
var mergeStaticInheritedObjectProperty = function (ctor, prop) {
|
|
var merge = {};
|
|
|
|
if (ctor.__super__)
|
|
_.extend(merge, mergeStaticInheritedObjectProperty(ctor.__super__.constructor, prop));
|
|
|
|
return _.has(ctor, prop) ? _.extend(merge, ctor[prop]) : merge;
|
|
};
|
|
|
|
Controller._collectEventMaps = function () {
|
|
return mergeStaticInheritedObjectProperty(this, '_eventMap');
|
|
};
|
|
|
|
// NOTE: helpers are not inherited from one controller to another, for now.
|
|
Controller._helpers = {};
|
|
Controller.helpers = function (helpers) {
|
|
_.extend(this._helpers, helpers);
|
|
return this;
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* Global Helpers */
|
|
/*****************************************************************************/
|
|
if (typeof Template !== 'undefined') {
|
|
/**
|
|
* Returns the nearest controller for a template instance. You can call this
|
|
* function from inside a template helper.
|
|
*
|
|
* Example:
|
|
* Template.MyPage.helpers({
|
|
* greeting: function () {
|
|
* var controller = Iron.controller();
|
|
* return controller.state.get('greeting');
|
|
* }
|
|
* });
|
|
*/
|
|
Iron.controller = function () {
|
|
//XXX establishes a reactive dependency which causes helper to run
|
|
return DynamicTemplate.findLookupHostWithProperty(Blaze.getView(), '_isController');
|
|
};
|
|
|
|
/**
|
|
* Find a lookup host with a state key and return it reactively if we have
|
|
* it.
|
|
*/
|
|
Template.registerHelper('get', function (key) {
|
|
var controller = Iron.controller();
|
|
if (controller && controller.state)
|
|
return controller.state.get(key);
|
|
});
|
|
}
|
|
/*****************************************************************************/
|
|
/* Namespacing */
|
|
/*****************************************************************************/
|
|
Iron.Controller = Controller;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/iron_controller/lib/controller_client.js //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/*****************************************************************************/
|
|
/* Imports */
|
|
/*****************************************************************************/
|
|
var Layout = Iron.Layout;
|
|
var debug = Iron.utils.debug('iron:controller');
|
|
var defaultValue = Iron.utils.defaultValue;
|
|
|
|
/*****************************************************************************/
|
|
/* Private */
|
|
/*****************************************************************************/
|
|
var bindData = function (value, thisArg) {
|
|
return function () {
|
|
return (typeof value === 'function') ? value.apply(thisArg, arguments) : value;
|
|
};
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* Controller Client */
|
|
/*****************************************************************************/
|
|
/**
|
|
* Client specific init code.
|
|
*/
|
|
Controller.prototype.init = function (options) {
|
|
this._waitlist = new WaitList;
|
|
this.state = new ReactiveDict;
|
|
};
|
|
|
|
/**
|
|
* Insert the controller's layout into the DOM.
|
|
*/
|
|
Controller.prototype.insert = function (options) {
|
|
return this._layout.insert.apply(this._layout, arguments);
|
|
};
|
|
|
|
/**
|
|
* Add an item to the waitlist.
|
|
*/
|
|
Controller.prototype.wait = function (fn) {
|
|
var self = this;
|
|
|
|
if (!fn)
|
|
// it's possible fn is just undefined but we'll just return instead
|
|
// of throwing an error, to make it easier to call this function
|
|
// with waitOn which might not return anything.
|
|
return;
|
|
|
|
if (_.isArray(fn)) {
|
|
_.each(fn, function eachWait (fnOrHandle) {
|
|
self.wait(fnOrHandle);
|
|
});
|
|
} else if (fn.ready) {
|
|
this._waitlist.wait(function () { return fn.ready(); });
|
|
} else {
|
|
this._waitlist.wait(fn);
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Returns true if all items in the waitlist are ready.
|
|
*/
|
|
Controller.prototype.ready = function () {
|
|
return this._waitlist.ready();
|
|
};
|
|
|
|
/**
|
|
* Clean up the controller and stop the waitlist.
|
|
*/
|
|
Controller.prototype.stop = function () {
|
|
this._waitlist.stop();
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
/* Exports */
|
|
Package._define("iron:controller");
|
|
|
|
})();
|