<commit_before>dojo.provide("dijit.tree.TreeStoreModel");

dojo.declare(
		"dijit.tree.TreeStoreModel",
		null,
	{
		// summary:
		//		Implements dijit.Tree.model connecting to a store with a single
		//		root item.  Any methods passed into the constructor will override
		//		the ones defined here.

		// store: dojo.data.Store
		//		Underlying store
		store: null,

		// childrenAttrs: String[]
		//		One or more attribute names (attributes in the dojo.data item) that specify that item's children
		childrenAttrs: ["children"],

		// newItemIdAttr: String
		//		Name of attribute in the Object passed to newItem() that specifies the id.
		//
		//		If newItemIdAttr is set then it's used when newItem() is called to see if an
		//		item with the same id already exists, and if so just links to the old item
		//		(so that the old item ends up with two parents).
		//
		//		Setting this to null or "" will make every drop create a new item.
		newItemIdAttr: "id",

		// labelAttr: String
		//		If specified, get label for tree node from this attribute, rather
		//		than by calling store.getLabel()
		labelAttr: "",

	 	// root: [readonly] dojo.data.Item
		//		Pointer to the root item (read only, not a parameter)
		root: null,

		// query: anything
		//		Specifies datastore query to return the root item for the tree.
		//		Must only return a single item.   Alternately can just pass in pointer
		//		to root item.
		// example:
		//	|	{id:'ROOT'}
		query: null,

		// deferItemLoadingUntilExpand: Boolean
		//		Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
		// 		until they are expanded. This allows for lazying loading where only one
		//		loadItem (and generally one network call, consequently) per expansion
		// 		(rather than one for each child).
		// 		This relies on partial loading of the children items; each children item of a
		// 		fully loaded item should contain the label and info about having children.
		deferItemLoadingUntilExpand: false,

		constructor: function(/* Object */ args){
			// summary:
			//		Passed the arguments listed above (store, etc)
			// tags:
			//		private

			dojo.mixin(this, args);

			this.connects = [];

			var store = this.store;
			if(!store.getFeatures()['dojo.data.api.Identity']){
				throw new Error("dijit.Tree: store must support dojo.data.Identity");
			}

			// if the store supports Notification, subscribe to the notification events
			if(store.getFeatures()['dojo.data.api.Notification']){
				this.connects = this.connects.concat([
					dojo.connect(store, "onNew", this, "onNewItem"),
					dojo.connect(store, "onDelete", this, "onDeleteItem"),
					dojo.connect(store, "onSet", this, "onSetItem")
				]);
			}
		},

		destroy: function(){
			dojo.forEach(this.connects, dojo.disconnect);
			// TODO: should cancel any in-progress processing of getRoot(), getChildren()
		},

		// =======================================================================
		// Methods for traversing hierarchy

		getRoot: function(onItem, onError){
			// summary:
			//		Calls onItem with the root item for the tree, possibly a fabricated item.
			//		Calls onError on error.
			if(this.root){
				onItem(this.root);
			}else{
				this.store.fetch({
					query: this.query,
					onComplete: dojo.hitch(this, function(items){
						if(items.length != 1){
							throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
							 	" items, but must return exactly one item");
						}
						this.root = items[0];
						onItem(this.root);
					}),
					onError: onError
				});
			}
		},

		mayHaveChildren: function(/*dojo.data.Item*/ item){
			// summary:
			//		Tells if an item has or may have children.  Implementing logic here
			//		avoids showing +/- expando icon for nodes that we know don't have children.
			//		(For efficiency reasons we may not want to check if an element actually
			//		has children until user clicks the expando node)
			return dojo.some(this.childrenAttrs, function(attr){
				return this.store.hasAttribute(item, attr);
			}, this);
		},

		getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
			// summary:
			// 		Calls onComplete() with array of child items of given parent item, all loaded.

			var store = this.store;
			if(!store.isItemLoaded(parentItem)){
				// The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
				// mode, so we will load it and just return the children (without loading each
				// child item)
				var getChildren = dojo.hitch(this, arguments.callee);
				store.loadItem({
					item: parentItem,
					onItem: function(parentItem){
						getChildren(parentItem, onComplete, onError);
					},
					onError: onError
				});
				return;
			}
			// get children of specified item
			var childItems = [];
			for(var i=0; i<this.childrenAttrs.length; i++){
				var vals = store.getValues(parentItem, this.childrenAttrs[i]);
				childItems = childItems.concat(vals);
			}

			// count how many items need to be loaded
			var _waitCount = 0;
			if(!this.deferItemLoadingUntilExpand){
				dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
			}

			if(_waitCount == 0){
				// all items are already loaded (or we aren't loading them).  proceed...
				onComplete(childItems);
			}else{
				// still waiting for some or all of the items to load
				dojo.forEach(childItems, function(item, idx){
					if(!store.isItemLoaded(item)){
						store.loadItem({
							item: function onItem(item){
								childItems[idx] = item;
								if(--_waitCount == 0){
									// all nodes have been loaded, send them to the tree
									onComplete(childItems);
								}
							},
							onItem: onItem,
							onError: onError
						});
					}
				});
			}
		},

		// =======================================================================
		// Inspecting items

		isItem: function(/* anything */ something){
			return this.store.isItem(something);	// Boolean
		},

		fetchItemByIdentity: function(/* object */ keywordArgs){
			this.store.fetchItemByIdentity(keywordArgs);
		},

		getIdentity: function(/* item */ item){
			return this.store.getIdentity(item);	// Object
		},

		getLabel: function(/*dojo.data.Item*/ item){
			// summary:
			//		Get the label for an item
			if(this.labelAttr){
				return this.store.getValue(item,this.labelAttr);	// String
			}else{
				return this.store.getLabel(item);	// String
			}
		},

		// =======================================================================
		// Write interface

		newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
			// summary:
			//		Creates a new item.   See `dojo.data.api.Write` for details on args.
			//		Used in drag & drop when item from external source dropped onto tree.
			// description:
			//		Developers will need to override this method if new items get added
			//		to parents with multiple children attributes, in order to define which
			//		children attribute points to the new item.

			var pInfo = {parent: parent, attribute: this.childrenAttrs[0], insertIndex: insertIndex};

			if(this.newItemIdAttr && args[this.newItemIdAttr]){
				// Maybe there's already a corresponding item in the store; if so, reuse it.
				this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
					if(item){
						// There's already a matching item in store, use it
						this.pasteItem(item, null, parent, true, insertIndex);
					}else{
						// Create new item in the tree, based on the drag source.
						this.store.newItem(args, pInfo);
					}
				}});
			}else{
				// [as far as we know] there is no id so we must assume this is a new item
				this.store.newItem(args, pInfo);
			}
		},

		pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
			// summary:
			//		Move or copy an item from one parent item to another.
			//		Used in drag & drop
			var store = this.store,
				parentAttr = this.childrenAttrs[0];	// name of "children" attr in parent item

			// remove child from source item, and record the attribute that child occurred in
			if(oldParentItem){
				dojo.forEach(this.childrenAttrs, function(attr){
					if(store.containsValue(oldParentItem, attr, childItem)){
						if(!bCopy){
							var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
								return x != childItem;
							});
							store.setValues(oldParentItem, attr, values);
						}
						parentAttr = attr;
					}
				});
			}

			// modify target item's children attribute to include this item
			if(newParentItem){
				if(typeof insertIndex == "number"){
					var childItems = store.getValues(newParentItem, parentAttr);
					childItems.splice(insertIndex, 0, childItem);
					store.setValues(newParentItem, parentAttr, childItems);
				}else{
				store.setValues(newParentItem, parentAttr,
					store.getValues(newParentItem, parentAttr).concat(childItem));
			}
			}
		},

		// =======================================================================
		// Callbacks

		onChange: function(/*dojo.data.Item*/ item){
			// summary:
			//		Callback whenever an item has changed, so that Tree
			//		can update the label, icon, etc.   Note that changes
			//		to an item's children or parent(s) will trigger an
			//		onChildrenChange() so you can ignore those changes here.
			// tags:
			//		callback
		},

		onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
			// summary:
			//		Callback to do notifications about new, updated, or deleted items.
			// tags:
			//		callback
		},

		onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
			// summary:
			//		Callback when an item has been deleted.
			// description:
			//		Note that there will also be an onChildrenChange() callback for the parent
			//		of this item.
			// tags:
			//		callback
		},

		// =======================================================================
		// Events from data store

		onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
			// summary:
			//		Handler for when new items appear in the store, either from a drop operation
			//		or some other way.   Updates the tree view (if necessary).
			// description:
			//		If the new item is a child of an existing item,
			//		calls onChildrenChange() with the new list of children
			//		for that existing item.
			//
			// tags:
			//		extension

			// We only care about the new item if it has a parent that corresponds to a TreeNode
			// we are currently displaying
			if(!parentInfo){
				return;
			}

			// Call onChildrenChange() on parent (ie, existing) item with new list of children
			// In the common case, the new list of children is simply parentInfo.newValue or
			// [ parentInfo.newValue ], although if items in the store has multiple
			// child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
			// so call getChildren() to be sure to get right answer.
			this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
				this.onChildrenChange(parentInfo.item, children);
			}));
		},

		onDeleteItem: function(/*Object*/ item){
			// summary:
			//		Handler for delete notifications from underlying store
			this.onDelete(item);
		},

		onSetItem: function(/* item */ item,
						/* attribute-name-string */ attribute,
						/* object | array */ oldValue,
						/* object | array */ newValue){
			// summary:
			//		Updates the tree view according to changes in the data store.
			// description:
			//		Handles updates to an item's children by calling onChildrenChange(), and
			//		other updates to an item by calling onChange().
			//
			//		See `onNewItem` for more details on handling updates to an item's children.
			// tags:
			//		extension

			if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
				// item's children list changed
				this.getChildren(item, dojo.hitch(this, function(children){
					// See comments in onNewItem() about calling getChildren()
					this.onChildrenChange(item, children);
				}));
			}else{
				// item's label/icon/etc. changed.
				this.onChange(item);
			}
		}
	});

<commit_msg>fix indent, refs #10048.<commit_after>dojo.provide("dijit.tree.TreeStoreModel");

dojo.declare(
		"dijit.tree.TreeStoreModel",
		null,
	{
		// summary:
		//		Implements dijit.Tree.model connecting to a store with a single
		//		root item.  Any methods passed into the constructor will override
		//		the ones defined here.

		// store: dojo.data.Store
		//		Underlying store
		store: null,

		// childrenAttrs: String[]
		//		One or more attribute names (attributes in the dojo.data item) that specify that item's children
		childrenAttrs: ["children"],

		// newItemIdAttr: String
		//		Name of attribute in the Object passed to newItem() that specifies the id.
		//
		//		If newItemIdAttr is set then it's used when newItem() is called to see if an
		//		item with the same id already exists, and if so just links to the old item
		//		(so that the old item ends up with two parents).
		//
		//		Setting this to null or "" will make every drop create a new item.
		newItemIdAttr: "id",

		// labelAttr: String
		//		If specified, get label for tree node from this attribute, rather
		//		than by calling store.getLabel()
		labelAttr: "",

	 	// root: [readonly] dojo.data.Item
		//		Pointer to the root item (read only, not a parameter)
		root: null,

		// query: anything
		//		Specifies datastore query to return the root item for the tree.
		//		Must only return a single item.   Alternately can just pass in pointer
		//		to root item.
		// example:
		//	|	{id:'ROOT'}
		query: null,

		// deferItemLoadingUntilExpand: Boolean
		//		Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
		// 		until they are expanded. This allows for lazying loading where only one
		//		loadItem (and generally one network call, consequently) per expansion
		// 		(rather than one for each child).
		// 		This relies on partial loading of the children items; each children item of a
		// 		fully loaded item should contain the label and info about having children.
		deferItemLoadingUntilExpand: false,

		constructor: function(/* Object */ args){
			// summary:
			//		Passed the arguments listed above (store, etc)
			// tags:
			//		private

			dojo.mixin(this, args);

			this.connects = [];

			var store = this.store;
			if(!store.getFeatures()['dojo.data.api.Identity']){
				throw new Error("dijit.Tree: store must support dojo.data.Identity");
			}

			// if the store supports Notification, subscribe to the notification events
			if(store.getFeatures()['dojo.data.api.Notification']){
				this.connects = this.connects.concat([
					dojo.connect(store, "onNew", this, "onNewItem"),
					dojo.connect(store, "onDelete", this, "onDeleteItem"),
					dojo.connect(store, "onSet", this, "onSetItem")
				]);
			}
		},

		destroy: function(){
			dojo.forEach(this.connects, dojo.disconnect);
			// TODO: should cancel any in-progress processing of getRoot(), getChildren()
		},

		// =======================================================================
		// Methods for traversing hierarchy

		getRoot: function(onItem, onError){
			// summary:
			//		Calls onItem with the root item for the tree, possibly a fabricated item.
			//		Calls onError on error.
			if(this.root){
				onItem(this.root);
			}else{
				this.store.fetch({
					query: this.query,
					onComplete: dojo.hitch(this, function(items){
						if(items.length != 1){
							throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
							 	" items, but must return exactly one item");
						}
						this.root = items[0];
						onItem(this.root);
					}),
					onError: onError
				});
			}
		},

		mayHaveChildren: function(/*dojo.data.Item*/ item){
			// summary:
			//		Tells if an item has or may have children.  Implementing logic here
			//		avoids showing +/- expando icon for nodes that we know don't have children.
			//		(For efficiency reasons we may not want to check if an element actually
			//		has children until user clicks the expando node)
			return dojo.some(this.childrenAttrs, function(attr){
				return this.store.hasAttribute(item, attr);
			}, this);
		},

		getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
			// summary:
			// 		Calls onComplete() with array of child items of given parent item, all loaded.

			var store = this.store;
			if(!store.isItemLoaded(parentItem)){
				// The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
				// mode, so we will load it and just return the children (without loading each
				// child item)
				var getChildren = dojo.hitch(this, arguments.callee);
				store.loadItem({
					item: parentItem,
					onItem: function(parentItem){
						getChildren(parentItem, onComplete, onError);
					},
					onError: onError
				});
				return;
			}
			// get children of specified item
			var childItems = [];
			for(var i=0; i<this.childrenAttrs.length; i++){
				var vals = store.getValues(parentItem, this.childrenAttrs[i]);
				childItems = childItems.concat(vals);
			}

			// count how many items need to be loaded
			var _waitCount = 0;
			if(!this.deferItemLoadingUntilExpand){
				dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
			}

			if(_waitCount == 0){
				// all items are already loaded (or we aren't loading them).  proceed...
				onComplete(childItems);
			}else{
				// still waiting for some or all of the items to load
				dojo.forEach(childItems, function(item, idx){
					if(!store.isItemLoaded(item)){
						store.loadItem({
							item: function onItem(item){
								childItems[idx] = item;
								if(--_waitCount == 0){
									// all nodes have been loaded, send them to the tree
									onComplete(childItems);
								}
							},
							onItem: onItem,
							onError: onError
						});
					}
				});
			}
		},

		// =======================================================================
		// Inspecting items

		isItem: function(/* anything */ something){
			return this.store.isItem(something);	// Boolean
		},

		fetchItemByIdentity: function(/* object */ keywordArgs){
			this.store.fetchItemByIdentity(keywordArgs);
		},

		getIdentity: function(/* item */ item){
			return this.store.getIdentity(item);	// Object
		},

		getLabel: function(/*dojo.data.Item*/ item){
			// summary:
			//		Get the label for an item
			if(this.labelAttr){
				return this.store.getValue(item,this.labelAttr);	// String
			}else{
				return this.store.getLabel(item);	// String
			}
		},

		// =======================================================================
		// Write interface

		newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
			// summary:
			//		Creates a new item.   See `dojo.data.api.Write` for details on args.
			//		Used in drag & drop when item from external source dropped onto tree.
			// description:
			//		Developers will need to override this method if new items get added
			//		to parents with multiple children attributes, in order to define which
			//		children attribute points to the new item.

			var pInfo = {parent: parent, attribute: this.childrenAttrs[0], insertIndex: insertIndex};

			if(this.newItemIdAttr && args[this.newItemIdAttr]){
				// Maybe there's already a corresponding item in the store; if so, reuse it.
				this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
					if(item){
						// There's already a matching item in store, use it
						this.pasteItem(item, null, parent, true, insertIndex);
					}else{
						// Create new item in the tree, based on the drag source.
						this.store.newItem(args, pInfo);
					}
				}});
			}else{
				// [as far as we know] there is no id so we must assume this is a new item
				this.store.newItem(args, pInfo);
			}
		},

		pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
			// summary:
			//		Move or copy an item from one parent item to another.
			//		Used in drag & drop
			var store = this.store,
				parentAttr = this.childrenAttrs[0];	// name of "children" attr in parent item

			// remove child from source item, and record the attribute that child occurred in
			if(oldParentItem){
				dojo.forEach(this.childrenAttrs, function(attr){
					if(store.containsValue(oldParentItem, attr, childItem)){
						if(!bCopy){
							var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
								return x != childItem;
							});
							store.setValues(oldParentItem, attr, values);
						}
						parentAttr = attr;
					}
				});
			}

			// modify target item's children attribute to include this item
			if(newParentItem){
				if(typeof insertIndex == "number"){
					var childItems = store.getValues(newParentItem, parentAttr);
					childItems.splice(insertIndex, 0, childItem);
					store.setValues(newParentItem, parentAttr, childItems);
				}else{
					store.setValues(newParentItem, parentAttr,
						store.getValues(newParentItem, parentAttr).concat(childItem));
				}
			}
		},

		// =======================================================================
		// Callbacks

		onChange: function(/*dojo.data.Item*/ item){
			// summary:
			//		Callback whenever an item has changed, so that Tree
			//		can update the label, icon, etc.   Note that changes
			//		to an item's children or parent(s) will trigger an
			//		onChildrenChange() so you can ignore those changes here.
			// tags:
			//		callback
		},

		onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
			// summary:
			//		Callback to do notifications about new, updated, or deleted items.
			// tags:
			//		callback
		},

		onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
			// summary:
			//		Callback when an item has been deleted.
			// description:
			//		Note that there will also be an onChildrenChange() callback for the parent
			//		of this item.
			// tags:
			//		callback
		},

		// =======================================================================
		// Events from data store

		onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
			// summary:
			//		Handler for when new items appear in the store, either from a drop operation
			//		or some other way.   Updates the tree view (if necessary).
			// description:
			//		If the new item is a child of an existing item,
			//		calls onChildrenChange() with the new list of children
			//		for that existing item.
			//
			// tags:
			//		extension

			// We only care about the new item if it has a parent that corresponds to a TreeNode
			// we are currently displaying
			if(!parentInfo){
				return;
			}

			// Call onChildrenChange() on parent (ie, existing) item with new list of children
			// In the common case, the new list of children is simply parentInfo.newValue or
			// [ parentInfo.newValue ], although if items in the store has multiple
			// child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
			// so call getChildren() to be sure to get right answer.
			this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
				this.onChildrenChange(parentInfo.item, children);
			}));
		},

		onDeleteItem: function(/*Object*/ item){
			// summary:
			//		Handler for delete notifications from underlying store
			this.onDelete(item);
		},

		onSetItem: function(/* item */ item,
						/* attribute-name-string */ attribute,
						/* object | array */ oldValue,
						/* object | array */ newValue){
			// summary:
			//		Updates the tree view according to changes in the data store.
			// description:
			//		Handles updates to an item's children by calling onChildrenChange(), and
			//		other updates to an item by calling onChange().
			//
			//		See `onNewItem` for more details on handling updates to an item's children.
			// tags:
			//		extension

			if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
				// item's children list changed
				this.getChildren(item, dojo.hitch(this, function(children){
					// See comments in onNewItem() about calling getChildren()
					this.onChildrenChange(item, children);
				}));
			}else{
				// item's label/icon/etc. changed.
				this.onChange(item);
			}
		}
	});

<|endoftext|>


<commit_before>/* Ember Mocha Adapter | (C) 2014 Teddy Zeenny | https://github.com/teddyzeenny/ember-mocha-adapter */

(function() {
  var done, doneTimeout, countAsync, emberBdd;

  done = null;
  doneTimeout = null;
  isAsync = false;

  Ember.Test.MochaAdapter = Ember.Test.Adapter.extend({
    init: function() {
      this._super();
      window.Mocha.interfaces['ember-bdd'] = emberBdd;
      window.mocha.ui('ember-bdd');
    },
    asyncStart: function() {
      isAsync = true;
      clearTimeout(doneTimeout);
    },
    asyncEnd: function() {
      isAsync = false;
      if (done) {
        doneTimeout = setTimeout(function() {
          var d = done;
          done = null;
          d();
        });
      }
    },
    exception: function(reason) {
      var error, d;

      error = new Error(reason);
      if (done) {
        d = done;
        done = null;
        clearTimeout(doneTimeout)
        d(error);
      } else {
        setTimeout(function() {
          throw error;
        });
      }
    }
  });

  function fixAsync(suites, methodName) {
    return function(fn) {
      if (fn.length === 1) {
        suites[0][methodName](fn);
      } else {
        suites[0][methodName](function(d) {
          invoke(this, fn, d);
        });
      }
    };
  }

  function invoke(context, fn, d) {
    done = d;
    fn.call(context);
    if (!isAsync) {
      done = null;
      d();
    }
  }

  /**
    ember-bdd mocha interface.
    This interface allows
    the Ember.js tester
    to forget about sync / async
    and treat all tests the same.

    This interface, along with the adapter
    will take care of handling sync vs async
  */

  emberBdd = function(suite) {
    var suites = [suite];

    suite.on('pre-require', function(context, file, mocha) {

      context.before = fixAsync(suites, 'beforeAll');

      context.after = fixAsync(suites, 'afterAll');

      context.beforeEach = fixAsync(suites, 'beforeEach');

      context.afterEach = fixAsync(suites, 'afterEach');

      context.it = context.specify = function(title, fn){
        var suite = suites[0], test;
        if (suite.pending) {
          fn = null;
        }
        if (!fn || fn.length === 1) {
          test = new Mocha.Test(title, fn);
        } else {
          var method = function(d) {
            invoke(this, fn, d);
          };
          method.toString = function() {
            return fn.toString();
          }
          test = new Mocha.Test(title, method);
        }
        suite.addTest(test);
        return test;
      };

      context.describe = context.context = function(title, fn){
        var suite = Mocha.Suite.create(suites[0], title);
        suites.unshift(suite);
        fn.call(suite);
        suites.shift();
        return suite;
      };

      context.xdescribe =
      context.xcontext =
      context.describe.skip = function(title, fn){
        var suite = Mocha.Suite.create(suites[0], title);
        suite.pending = true;
        suites.unshift(suite);
        fn.call(suite);
        suites.shift();
      };

      context.describe.only = function(title, fn){
        var suite = context.describe(title, fn);
        mocha.grep(suite.fullTitle());
      };

      context.it.only = function(title, fn){
        var test = context.it(title, fn);
        mocha.grep(test.fullTitle());
      };

      context.xit =
      context.xspecify =
      context.it.skip = function(title){
        context.it(title);
      };

    });

  };

}());

Ember.Test.adapter = Ember.Test.MochaAdapter.create();
<commit_msg>If test returns a promise, complete test when promise resolves<commit_after>/* Ember Mocha Adapter | (C) 2014 Teddy Zeenny | https://github.com/teddyzeenny/ember-mocha-adapter */

(function() {
  var done, doneTimeout, countAsync, emberBdd, isPromise;

  done = null;
  doneTimeout = null;
  isAsync = false;

  Ember.Test.MochaAdapter = Ember.Test.Adapter.extend({
    init: function() {
      this._super();
      window.Mocha.interfaces['ember-bdd'] = emberBdd;
      window.mocha.ui('ember-bdd');
    },
    asyncStart: function() {
      isAsync = true;
      clearTimeout(doneTimeout);
    },
    asyncEnd: function() {
      isAsync = false;
      if (done && !isPromise) {
        doneTimeout = setTimeout(function() {
          complete();
        });
      }
    },
    exception: function(reason) {
      var error, d;

      error = new Error(reason);
      if (done) {
        complete(error);
      } else {
        setTimeout(function() {
          throw error;
        });
      }
    }
  });

  function fixAsync(suites, methodName) {
    return function(fn) {
      if (fn.length === 1) {
        suites[0][methodName](fn);
      } else {
        suites[0][methodName](function(d) {
          invoke(this, fn, d);
        });
      }
    };
  }

  function invoke(context, fn, d) {
    done = d;
    isPromise = false;
    var result = fn.call(context);
    // If a promise is returned,
    // complete test when promise fulfills / rejects
    if (result && typeof result.then === 'function') {
      isPromise = true;
      result.then(function() { complete(); }, complete);
    } else {
       if (!isAsync) { complete(); }
    }
  }

  // Called whenever an async test passes or fails.
  // if `e` is passed, that means the test
  // failed with exception `e`
  function complete(e) {
    clearTimeout(doneTimeout);
    if (!done) { return; }
    var d = done;
    done = null;
    if (e) {
      // test failure
      if (!(e instanceof Error)) {
        e = new Error(e);
      }
      d(e);
    } else {
      // test passed
      d();
    }
  }

  /**
    ember-bdd mocha interface.
    This interface allows
    the Ember.js tester
    to forget about sync / async
    and treat all tests the same.

    This interface, along with the adapter
    will take care of handling sync vs async
  */

  emberBdd = function(suite) {
    var suites = [suite];

    suite.on('pre-require', function(context, file, mocha) {

      context.before = fixAsync(suites, 'beforeAll');

      context.after = fixAsync(suites, 'afterAll');

      context.beforeEach = fixAsync(suites, 'beforeEach');

      context.afterEach = fixAsync(suites, 'afterEach');

      context.it = context.specify = function(title, fn){
        var suite = suites[0], test;
        if (suite.pending) {
          fn = null;
        }
        if (!fn || fn.length === 1) {
          test = new Mocha.Test(title, fn);
        } else {
          var method = function(d) {
            invoke(this, fn, d);
          };
          method.toString = function() {
            return fn.toString();
          }
          test = new Mocha.Test(title, method);
        }
        suite.addTest(test);
        return test;
      };

      context.describe = context.context = function(title, fn){
        var suite = Mocha.Suite.create(suites[0], title);
        suites.unshift(suite);
        fn.call(suite);
        suites.shift();
        return suite;
      };

      context.xdescribe =
      context.xcontext =
      context.describe.skip = function(title, fn){
        var suite = Mocha.Suite.create(suites[0], title);
        suite.pending = true;
        suites.unshift(suite);
        fn.call(suite);
        suites.shift();
      };

      context.describe.only = function(title, fn){
        var suite = context.describe(title, fn);
        mocha.grep(suite.fullTitle());
      };

      context.it.only = function(title, fn){
        var test = context.it(title, fn);
        mocha.grep(test.fullTitle());
      };

      context.xit =
      context.xspecify =
      context.it.skip = function(title){
        context.it(title);
      };

    });

  };

}());

Ember.Test.adapter = Ember.Test.MochaAdapter.create();
<|endoftext|>


<commit_before>/*jslint node:true*/
/*globals RTCPeerConnection, mozRTCPeerConnection, webkitRTCPeerConnection */
/*globals RTCSessionDescription, mozRTCSessionDescription */
/*globals RTCIceCandidate, mozRTCIceCandidate */
'use strict';

var myRTCPeerConnection = null;
var myRTCSessionDescription = null;
var myRTCIceCandidate = null;

var renameIceURLs = function (config) {
  if (!config) {
    return;
  }
  if (!config.iceServers) {
    return config;
  }
  config.iceServers.forEach(function (server) {
    server.url = server.urls;
    delete server.urls;
  });
  return config;
};

var fixChromeStatsResponse = function(response) {
  var standardReport = {};
  var reports = response.result();
  reports.forEach(function(report) {
    var standardStats = {};
    standardStats.id = report.id;
    standardStats.timestamp = report.timestamp;
    standardStats.type = report.type;
    var names = report.names();
    names.forEach(function(name) {
      standardStats[name] = report.stat(name);
    });
    standardReport[standardStats.id] = standardStats;
  });

  return standardReport;
};

// Unify PeerConnection Object.
if (typeof RTCPeerConnection !== 'undefined') {
  myRTCPeerConnection = RTCPeerConnection;
} else if (typeof mozRTCPeerConnection !== 'undefined') {
  // Firefox uses 'url' rather than 'urls' for RTCIceServer.urls
  myRTCPeerConnection = function (configuration, constraints) {
    return new mozRTCPeerConnection(renameIceURLs(configuration), constraints);
  };
} else if (typeof webkitRTCPeerConnection !== 'undefined') {
  // Chrome returns a nonstandard, non-JSON-ifiable response from getStats.
  myRTCPeerConnection = function(configuration, constraints) {
    var pc = new webkitRTCPeerConnection(configuration, constraints);
    var boundGetStats = pc.getStats.bind(pc);
    pc.getStats = function(selector, successCallback, failureCallback) {
      var successCallbackWrapper = function(chromeStatsResponse) {
        successCallback(fixChromeStatsResponse(chromeStatsResponse));
      };
      // Chrome also takes its arguments in the wrong order.
      boundGetStats(successCallbackWrapper, failureCallback, selector);
    };
    return pc;
  };
}

// Unify SessionDescrption Object.
if (typeof RTCSessionDescription !== 'undefined') {
  myRTCSessionDescription = RTCSessionDescription;
} else if (typeof mozRTCSessionDescription !== 'undefined') {
  myRTCSessionDescription = mozRTCSessionDescription;
}

// Unify IceCandidate Object.
if (typeof RTCIceCandidate !== 'undefined') {
  myRTCIceCandidate = RTCIceCandidate;
} else if (typeof mozRTCIceCandidate !== 'undefined') {
  myRTCIceCandidate = mozRTCIceCandidate;
}

exports.RTCPeerConnection = myRTCPeerConnection;
exports.RTCSessionDescription = myRTCSessionDescription;
exports.RTCIceCandidate = myRTCIceCandidate;
<commit_msg>Beautify code phrasing.<commit_after>/*jslint node:true*/
/*globals RTCPeerConnection, mozRTCPeerConnection, webkitRTCPeerConnection */
/*globals RTCSessionDescription, mozRTCSessionDescription */
/*globals RTCIceCandidate, mozRTCIceCandidate */
'use strict';

var myRTCPeerConnection = null;
var myRTCSessionDescription = null;
var myRTCIceCandidate = null;

var renameIceURLs = function (config) {
  if (!config) {
    return;
  }
  if (!config.iceServers) {
    return config;
  }
  config.iceServers.forEach(function (server) {
    server.url = server.urls;
    delete server.urls;
  });
  return config;
};

var fixChromeStatsResponse = function(response) {
  var standardReport = {};
  var reports = response.result();
  reports.forEach(function(report) {
    var standardStats = {
      id: report.id,
      timestamp: report.timestamp,
      type: report.type
    };
    report.names().forEach(function(name) {
      standardStats[name] = report.stat(name);
    });
    standardReport[standardStats.id] = standardStats;
  });

  return standardReport;
};

// Unify PeerConnection Object.
if (typeof RTCPeerConnection !== 'undefined') {
  myRTCPeerConnection = RTCPeerConnection;
} else if (typeof mozRTCPeerConnection !== 'undefined') {
  // Firefox uses 'url' rather than 'urls' for RTCIceServer.urls
  myRTCPeerConnection = function (configuration, constraints) {
    return new mozRTCPeerConnection(renameIceURLs(configuration), constraints);
  };
} else if (typeof webkitRTCPeerConnection !== 'undefined') {
  // Chrome returns a nonstandard, non-JSON-ifiable response from getStats.
  myRTCPeerConnection = function(configuration, constraints) {
    var pc = new webkitRTCPeerConnection(configuration, constraints);
    var boundGetStats = pc.getStats.bind(pc);
    pc.getStats = function(selector, successCallback, failureCallback) {
      var successCallbackWrapper = function(chromeStatsResponse) {
        successCallback(fixChromeStatsResponse(chromeStatsResponse));
      };
      // Chrome also takes its arguments in the wrong order.
      boundGetStats(successCallbackWrapper, failureCallback, selector);
    };
    return pc;
  };
}

// Unify SessionDescrption Object.
if (typeof RTCSessionDescription !== 'undefined') {
  myRTCSessionDescription = RTCSessionDescription;
} else if (typeof mozRTCSessionDescription !== 'undefined') {
  myRTCSessionDescription = mozRTCSessionDescription;
}

// Unify IceCandidate Object.
if (typeof RTCIceCandidate !== 'undefined') {
  myRTCIceCandidate = RTCIceCandidate;
} else if (typeof mozRTCIceCandidate !== 'undefined') {
  myRTCIceCandidate = mozRTCIceCandidate;
}

exports.RTCPeerConnection = myRTCPeerConnection;
exports.RTCSessionDescription = myRTCSessionDescription;
exports.RTCIceCandidate = myRTCIceCandidate;
<|endoftext|>


<commit_before>(function () {
  'use strict';

  function deep (d) {
    d.addEventListener('DOMContentLoaded', function () {
      var a = $.$('#skip-ad', d.document);
      if (a) {
        $.openLink(a.href);
      }
    });
  }

  $.register({
    rule: {
      host: /^coinurl\.com|cur\.lv$/,
    },
    ready: function () {
      var d = window.frames[0];
      if (d) {
        deep(d);
        return;
      }
      var o = new MutationObserver(function (mutations) {
        o.disconnect();
        var d = window.frames[0];
        d.addEventListener('DOMContentLoaded', function () {
          d = d.frames[0];
          deep(d);
        });
      });
      o.observe(document.body, {
        childList: true,
      });
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<commit_msg>cur.lv<commit_after>(function () {
  'use strict';

  function deep (d) {
    d.addEventListener('DOMContentLoaded', function () {
      var a = $.$('#skip-ad', d.document);
      if (a) {
        $.openLink(a.href);
      }
    });
  }

  $.register({
    rule: {
      host: /^coinurl\.com|cur\.lv$/,
    },
    ready: function () {
      var d = unsafeWindow.frames[0];
      if (d) {
        deep(d);
        return;
      }
      var o = new MutationObserver(function (mutations) {
        o.disconnect();
        var d = unsafeWindow.frames[0];
        d.addEventListener('DOMContentLoaded', function () {
          d = d.frames[0];
          deep(d);
        });
      });
      o.observe(document.body, {
        childList: true,
      });
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<|endoftext|>


<commit_before>'use strict';
//should correspond to what's in package.json
var gulp    = require('gulp'),
    gutil   = require('gulp-util'),
    jslint  = require('gulp-jslint'),
    sass    = require('gulp-sass'),
    jade    = require('gulp-jade'),
    notify  = require('gulp-notify'),
    autoprefixer = require('gulp-autoprefixer'),
    include = require('gulp-include'),
    connect = require('gulp-connect'),
    concat = require('gulp-concat'),
    changed = require('gulp-changed'),
    plumber = require('gulp-plumber');

gulp.task('lint', function() {
  gulp.src('./js/*.js')
    .pipe(jslint())
    .pipe(jslint.reporter('default'));
});

gulp.task('scripts', function() {
  gulp.src(['./js/main.js','./components/**/*.js'])
    .pipe(plumber())
    .pipe(include())
    .pipe(concat('main.js'))
    .pipe(gulp.dest('../build/js'));
});

gulp.task('styles', function() {
  gulp.src('./scss/style.scss')
    .pipe(sass({onError: function(e) { console.log(e); } }))
    .pipe(autoprefixer('last 2 versions', '> 1%', 'ie 8'))
    .pipe(gulp.dest('../build/styles'))
    .pipe(connect.reload());
});

//pretty : true for non-minified html output
gulp.task('markup', function() {
  gulp.src(['./templates/pages/**/*.jade','./templates/*.jade'])
    .pipe(plumber())
    .pipe(jade({
      pretty: true
    }))
    .pipe(gulp.dest('../build/html'))
    .pipe(connect.reload());
});

gulp.task('server', function() {
  connect.server({
    livereload: true,
    root: '../build'
  });
});

gulp.task('copy-data', function() {
  gulp.src('./data/*.json')
    .pipe(changed('./data/*.json'))
    .pipe(gulp.dest('../build/data'));
});

gulp.task('copy-lib', function() {
  gulp.src('./js/lib/*.js')
    .pipe(changed('./js/lib/*.js'))
    .pipe(gulp.dest('../build/js/lib'));
});

gulp.task('copy-media', function() {
  gulp.src('./media/**/*')
    .pipe(changed('./media/**/*'))
    .pipe(gulp.dest('../build/media'));
});

gulp.task('watch', function() {

  gulp.watch('./components/**/*.jade', ['markup']);
  gulp.watch('./templates/**/*.jade', ['markup']);
  gulp.watch('./templates/pages/index.jade', ['markup']);
  gulp.watch('./templates/pages/**/*.jade', ['markup']);
  gulp.watch('./templates/layouts/*.jade', ['markup']);

  //style sheets
  gulp.watch('./scss/*.scss', ['styles']);
  gulp.watch('./components/**/*.scss', ['styles']);

  //plain old copy stuff over
  gulp.watch('./scripts/lib/*.js', ['copy-lib']);
  gulp.watch('./data/*.json', ['copy-data']);

  //scripts
  gulp.watch('./js/*.js', ['scripts']);
  gulp.watch('./components/**/*.js', ['scripts']);
  gulp.watch('./templates/pages/**/*.js', ['scripts']);
});

gulp.task('default', ['scripts', 'styles', 'markup', 'server', 'copy-data', 'copy-lib', 'copy-media', 'watch' ]);

<commit_msg>auto agg component css<commit_after>'use strict';
//should correspond to what's in package.json
var gulp    = require('gulp'),
    gutil   = require('gulp-util'),
    jslint  = require('gulp-jslint'),
    sass    = require('gulp-sass'),
    jade    = require('gulp-jade'),
    notify  = require('gulp-notify'),
    autoprefixer = require('gulp-autoprefixer'),
    include = require('gulp-include'),
    connect = require('gulp-connect'),
    concat = require('gulp-concat'),
    changed = require('gulp-changed'),
    plumber = require('gulp-plumber');

gulp.task('lint', function() {
  gulp.src('./js/*.js')
    .pipe(jslint())
    .pipe(jslint.reporter('default'));
});

gulp.task('scripts', function() {
  gulp.src(['./js/main.js','./components/**/*.js'])
    .pipe(plumber())
    .pipe(include())
    .pipe(concat('main.js'))
    .pipe(gulp.dest('../build/js'));
});

gulp.task('styles', function() {
  gulp.src('./scss/style.scss')
    .pipe(sass({onError: function(e) { console.log(e); } }))
    .pipe(autoprefixer('last 2 versions', '> 1%', 'ie 8'))
    .pipe(concat('style.css'))
    .pipe(gulp.dest('../build/styles'))
    .pipe(connect.reload());
});

//pretty : true for non-minified html output
gulp.task('markup', function() {
  gulp.src(['./templates/pages/**/*.jade','./templates/*.jade'])
    .pipe(plumber())
    .pipe(jade({
      pretty: true
    }))
    .pipe(gulp.dest('../build/html'))
    .pipe(connect.reload());
});

gulp.task('server', function() {
  connect.server({
    livereload: true,
    root: '../build'
  });
});

gulp.task('copy-data', function() {
  gulp.src('./data/*.json')
    .pipe(changed('./data/*.json'))
    .pipe(gulp.dest('../build/data'));
});

gulp.task('copy-lib', function() {
  gulp.src('./js/lib/*.js')
    .pipe(changed('./js/lib/*.js'))
    .pipe(gulp.dest('../build/js/lib'));
});

gulp.task('copy-media', function() {
  gulp.src('./media/**/*')
    .pipe(changed('./media/**/*'))
    .pipe(gulp.dest('../build/media'));
});

gulp.task('watch', function() {

  gulp.watch('./components/**/*.jade', ['markup']);
  gulp.watch('./templates/**/*.jade', ['markup']);
  gulp.watch('./templates/pages/index.jade', ['markup']);
  gulp.watch('./templates/pages/**/*.jade', ['markup']);
  gulp.watch('./templates/layouts/*.jade', ['markup']);

  //style sheets
  gulp.watch('./scss/*.scss', ['styles']);
  gulp.watch('./components/**/*.scss', ['styles']);

  //plain old copy stuff over
  gulp.watch('./scripts/lib/*.js', ['copy-lib']);
  gulp.watch('./data/*.json', ['copy-data']);

  //scripts
  gulp.watch('./js/*.js', ['scripts']);
  gulp.watch('./components/**/*.js', ['scripts']);
  gulp.watch('./templates/pages/**/*.js', ['scripts']);
});

gulp.task('default', ['scripts', 'styles', 'markup', 'server', 'copy-data', 'copy-lib', 'copy-media', 'watch' ]);

<|endoftext|>


<commit_before>/**************************
 * Auto complete plugin  *
 *************************/
$.fn.autocompleteajax = function (options) {
    // Defaults
    var defaults = {
        data: {},
        ajax: {},
        callback: null,
        delay: null,
        minLength: 2,
        autocomplete_id: null,
        input_name: null
    };

    options = $.extend(defaults, options);

    return this.each(function() {
        var $input = $(this);
        var data = options.data,
            $inputDiv = $input.closest('.input-field'); // Div to append on

        // Create autocomplete element
        var $autocomplete = $('

');

        // Append autocomplete element
        if ($inputDiv.length) {
            $inputDiv.append($autocomplete); // Set ul in body
        } else {
            $input.after($autocomplete);
        }

        var highlight = function(string, $el) {
            var img = $el.find('img');
            var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""),
                matchEnd = matchStart + string.length - 1,
                beforeMatch = $el.text().slice(0, matchStart),
                matchText = $el.text().slice(matchStart, matchEnd + 1),
                afterMatch = $el.text().slice(matchEnd + 1);
            $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + "");

            if (img.length) {
                $el.prepend(img);
            }
        };

        var timer;

        // Perform search
        $input.on('keyup', function (e) {
            if($(this).val().length > options.minLength) {
                // Send ajax request
                if (timer){
                    clearTimeout(timer);
                }

                timer =  setTimeout(function() {
                    if(!$.isEmptyObject(options.ajax)) {

                        // Copy ajax data object
                        var dataCopy = Object.assign({}, options.ajax.data);

                        // Replace custom prop name for the value of the input
                        for (var prop in dataCopy) {
                            if (dataCopy[prop].toString().indexOf("%s") > -1) {
                                dataCopy[prop] = dataCopy[prop].replace("%s", encodeURIComponent($input.val()));
                            }
                        }

                        $.ajax({
                            url: options.ajax.url,
                            method: options.ajax.method,
                            data: dataCopy,
                            dataType: options.ajax.dataType,
                            error: options.ajax.error,
                            beforeSend: function(jqXHR, settings) {
                                options.ajax.beforeSend ? options.ajax.beforeSend(jqXHR, settings) : null;
                            },
                            success: function(res) {
                                data = res;

                                // If wanna work with response result and get the updated version
                                if(options.callback != null) {
                                    data = options.callback(res) || data;
                                }
                            }
                        });

                    }

                    // Capture Enter
                    if (e.which === 13) {
                        $autocomplete.find('li').first().click();
                        return;
                    }
                }, options.delay);
            }

            var val = $input.val().toLowerCase();
            $autocomplete.empty();

            // Check if the input isn't empty
            if (val !== '') {
                (data) && $.each(data, function(i, value) {
                    if (value.value.toLowerCase().indexOf(val) !== -1 &&
                        value.value.toLowerCase() !== val) {
                        var autocompleteOption = $('

');

                        if(!!value.image) {
                            autocompleteOption.append(''+ value.value +'');
                        } else {
                            autocompleteOption.append(''+ value.value +'');
                        }

                        $autocomplete.append(autocompleteOption);
                        highlight(val, autocompleteOption);
                    }
                });
            }
        });

        // Set input value
        $autocomplete.on('click', 'li', function () {
            $input.val($(this).text().trim());

            var autocomplete_id = options.autocomplete_id;

            if (autocomplete_id) {
                var input_name = options.input_name ? options.input_name : 'autocomplete-id[' + autocomplete_id + ']';

                if($('#' + autocomplete_id).length == 0) {
                    $input.after("<input type='hidden' id='" + autocomplete_id +
                        "' name='" + input_name + "' class='multi_autocomplete_id' value='" + $(this).attr('data-id') +
                        "' data-initial='" + $(this).attr('data-id') + "'>");
                } else {
                    $('#' + autocomplete_id).val($(this).attr('data-id')).attr('data-initial', $(this).attr('data-id'));
                }
            } else {
                if($('.autocomplete-id').length == 0) {
                    $input.after("<input type='hidden' class='autocomplete-id' name='autocomplete-id' value='" + $(this).attr('data-id') + "'>");
                } else {
                    $('.autocomplete-id').val($(this).attr('data-id'));
                }
            }

            $autocomplete.empty();
        });
    });
};
<commit_msg>Updated to work in my case<commit_after>/**************************
 * Auto complete plugin  *
 *************************/
$.fn.autocompleteajax = function (options) {
    // Defaults
    var defaults = {
        data: {},
        ajax: {},
        callback: null,
        delay: null,
        minLength: 2,
        autocomplete_id: null,
        input_name: null
    };

    options = $.extend(defaults, options);

    return this.each(function() {
        var $input = $(this);
        var data = options.data,
            $inputDiv = $input.closest('.input-field'); // Div to append on

        // Create autocomplete element
        var $autocomplete = $('

');

        // Append autocomplete element
        if ($inputDiv.length) {
            $inputDiv.append($autocomplete); // Set ul in body
        } else {
            $input.after($autocomplete);
        }

        var highlight = function(string, $el) {
            var img = $el.find('img');
            var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""),
                matchEnd = matchStart + string.length - 1,
                beforeMatch = $el.text().slice(0, matchStart),
                matchText = $el.text().slice(matchStart, matchEnd + 1),
                afterMatch = $el.text().slice(matchEnd + 1);
            $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + "");

            if (img.length) {
                $el.prepend(img);
            }
        };

        var timer;

        // Perform search
        $input.on('keyup', function (e) {
            if($(this).val().length > options.minLength) {
                // Send ajax request
                if (timer){
                    clearTimeout(timer);
                }

                timer =  setTimeout(function() {
                    if(!$.isEmptyObject(options.ajax)) {

                        // Set search string
                        var dataCopy = {'string' : $input.val()};

                        $.ajax({
                            url: options.ajax.url,
                            method: options.ajax.method,
                            data: dataCopy,
                            dataType: options.ajax.dataType,
                            error: options.ajax.error,
                            beforeSend: function(jqXHR, settings) {
                                options.ajax.beforeSend ? options.ajax.beforeSend(jqXHR, settings) : null;
                            },
                            success: function(res) {
                                data = res;

                                // If wanna work with response result and get the updated version
                                if(options.callback != null) {
                                    data = options.callback(res) || data;
                                }
                            }
                        });

                    }

                    // Capture Enter
                    if (e.which === 13) {
                        $autocomplete.find('li').first().click();
                        return;
                    }
                }, options.delay);
            }

            var val = $input.val().toLowerCase();
            $autocomplete.empty();

            // Check if the input isn't empty
            if (val !== '') {
                var results = data.data;
                (results) && $.each(results, function(i, value) {
                    if (value.value.toLowerCase().indexOf(val) !== -1 &&
                        value.value.toLowerCase() !== val) {
                        var autocompleteOption = $('

');

                        if(!!value.image) {
                            autocompleteOption.append(''+ value.value +'');
                        } else {
                            autocompleteOption.append(''+ value.value +'');
                        }

                        $autocomplete.append(autocompleteOption);
                        highlight(val, autocompleteOption);
                    }
                });
            }
        });

        // Set input value
        $autocomplete.on('click', 'li', function () {
            $input.val($(this).text().trim());

            var autocomplete_id = options.autocomplete_id;

            if (autocomplete_id) {
                var input_name = options.input_name ? options.input_name : 'autocomplete-id[' + autocomplete_id + ']';

                if($('#' + autocomplete_id).length == 0) {
                    $input.after("<input type='hidden' id='" + autocomplete_id +
                        "' name='" + input_name + "' class='multi_autocomplete_id' value='" + $(this).attr('data-id') +
                        "' data-initial='" + $(this).attr('data-id') + "'>");
                } else {
                    $('#' + autocomplete_id).val($(this).attr('data-id')).attr('data-initial', $(this).attr('data-id'));
                }
            } else {
                if($('.autocomplete-id').length == 0) {
                    $input.after("<input type='hidden' class='autocomplete-id' name='autocomplete-id' value='" + $(this).attr('data-id') + "'>");
                } else {
                    $('.autocomplete-id').val($(this).attr('data-id'));
                }
            }

            $autocomplete.empty();
        });
    });
};
<|endoftext|>


<commit_before>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import { deburrUpper } from 'app/utils';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import uniq from 'lodash/uniq';
import { ESP_BLACKLIST, FILTERS_BY_CATEGORY } from 'data/constants';

const getCategory = state =>
  (state.category && state.category.toLowerCase()) || null;
const getData = state => state.categoryData || null;
const getQuery = state => deburrUpper(state.query) || '';
const getSearch = state => state.search || null;

export const getDefaultColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return [
        'full_name',
        'developed_by',
        'geographic_coverage',
        'time_horizon'
      ];
    case 'scenarios':
      return ['model', 'name', 'geographic_coverage_country'];
    case 'indicators':
      return ['name', 'category', 'unit'];
    default:
      return null;
  }
});

export const getFullTextColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return ['full_name', 'geographic_coverage'];
    case 'scenarios':
      return ['geographic_coverage_country'];
    case 'indicators':
      return [];
    default:
      return null;
  }
});

export const flattenedData = createSelector(
  [getData, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const attributesWithObjects = {
      models: [],
      scenarios: ['model'],
      indicators: ['model', 'category', 'subcategory']
    };
    const updatedData = data;
    return updatedData.map(d => {
      const flattenedD = d;
      attributesWithObjects[category].forEach(a => {
        if (Object.prototype.hasOwnProperty.call(d, a)) {
          flattenedD[a] = d[a] && (d[a].name || d[a].full_name);
        }
      });
      return flattenedD;
    });
  }
);

export const filteredDataBySearch = createSelector(
  [flattenedData, getQuery],
  (data, query) => {
    if (!data) return null;
    if (!query) return data;
    const updatedData = data;
    return updatedData.filter(d =>
      Object.keys(d).some(key => {
        if (Object.prototype.hasOwnProperty.call(d, key) && d[key] !== null) {
          return deburrUpper(d[key]).indexOf(query) > -1;
        }
        return false;
      })
    );
  }
);

export const titleLinks = createSelector(
  [getCategory, getData],
  (categoryName, data) => {
    if (!data || isEmpty(data) || !categoryName) return null;
    const categoryId = {
      models: 'full_name',
      scenarios: 'name'
    };
    const updatedData = data;
    return updatedData.map(d => ({
      fieldName: categoryId[categoryName],
      url: `${categoryName}/${d.id}`
    }));
  }
);

const getSelectedFields = createSelector(
  [getSearch, getCategory],
  (search, category) => {
    if (!search) return null;
    let selectedFields = search;
    const selectedKeys = Object.keys(selectedFields).filter(k =>
      k.startsWith(category)
    );
    selectedFields = pick(selectedFields, selectedKeys);

    const fieldsWithoutPrefix = {};
    Object.keys(selectedFields).forEach(k => {
      const keyWithoutPrefix = k.replace(`${category}-`, '');
      fieldsWithoutPrefix[keyWithoutPrefix] = selectedFields[k];
    });
    return fieldsWithoutPrefix;
  }
);

export const getSelectedFieldOptions = createSelector(
  [getSelectedFields],
  fields => {
    if (!fields) return null;
    const fieldOptions = {};
    Object.keys(fields).forEach(key => {
      fieldOptions[key] = { value: fields[key], label: fields[key] };
    });
    return fieldOptions;
  }
);

export const filteredDataByFilters = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters) return data;
    let filteredData = data;
    const availableSubcategories = [];
    Object.keys(filters).forEach(key => {
      filteredData = filteredData.filter(d => {
        if (key === 'category' && d[key] === filters[key]) {
          availableSubcategories.push(d.subcategory);
        }
        return d[key] === undefined || d[key] === filters[key];
      });
    });
    return filteredData;
  }
);

export const getAvailableSubcategories = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters || !filters.category) return [];
    const availableSubcategories = [];
    data.forEach(d => {
      if (d.category === filters.category) {
        availableSubcategories.push(d.subcategory);
      }
    });
    return uniq(availableSubcategories);
  }
);

export const getFilterOptionsByCategory = createSelector(
  [getCategory, getData, getAvailableSubcategories],
  (category, data, subcategories) => {
    if (!category || !data || isEmpty(data)) return null;
    const filters = FILTERS_BY_CATEGORY[category];
    const categoryOptions = {};
    filters.forEach(f => {
      const sanitizedFilterData = [];
      data.forEach(d => {
        if (d[f] !== null && d[f] !== '' && d[f] !== undefined) {
          const filterName = typeof d[f] === 'string' ? d[f] : d[f].name;
          sanitizedFilterData.push(filterName);
        }
      });
      let availableData = uniq(sanitizedFilterData);
      if (f === 'subcategory') {
        availableData = uniq(sanitizedFilterData).filter(
          d => subcategories.indexOf(d) > -1
        );
      }
      categoryOptions[f] = availableData.map(filterData => ({
        value: filterData,
        label: filterData
      }));
    });
    return categoryOptions;
  }
);

export const filterDataByBlackList = createSelector(
  [filteredDataByFilters, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data[0]),
      n => ESP_BLACKLIST[category].indexOf(n) === -1
    );
    return data.map(d => pick(d, whiteList));
  }
);

export const renameDataColumns = createSelector(
  [filteredDataByFilters, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    if (category === 'models') {
      let renamedData = data;
      const changes = [{ old: 'maintainer_name', new: 'developed_by' }];
      renamedData = renamedData.map(d => {
        const updatedD = d;
        changes.forEach(change => {
          if (d[change.old]) {
            updatedD[change.new] = d[change.old];
            delete updatedD[change.new];
          }
        });
        return updatedD;
      });
      return renamedData;
    }
    return data;
  }
);

export default {
  renameDataColumns,
  titleLinks,
  filteredDataByFilters,
  getFilterOptionsByCategory,
  getSelectedFieldOptions
};
<commit_msg>Reinstate blacklist in table<commit_after>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import { deburrUpper } from 'app/utils';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import uniq from 'lodash/uniq';
import { ESP_BLACKLIST, FILTERS_BY_CATEGORY } from 'data/constants';

const getCategory = state =>
  (state.category && state.category.toLowerCase()) || null;
const getData = state => state.categoryData || null;
const getQuery = state => deburrUpper(state.query) || '';
const getSearch = state => state.search || null;

export const getDefaultColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return [
        'full_name',
        'developed_by',
        'geographic_coverage',
        'time_horizon'
      ];
    case 'scenarios':
      return ['model', 'name', 'geographic_coverage_country'];
    case 'indicators':
      return ['name', 'category', 'unit'];
    default:
      return null;
  }
});

export const getFullTextColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return ['full_name', 'geographic_coverage'];
    case 'scenarios':
      return ['geographic_coverage_country'];
    case 'indicators':
      return [];
    default:
      return null;
  }
});

export const flattenedData = createSelector(
  [getData, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const attributesWithObjects = {
      models: [],
      scenarios: ['model'],
      indicators: ['model', 'category', 'subcategory']
    };
    const updatedData = data;
    return updatedData.map(d => {
      const flattenedD = d;
      attributesWithObjects[category].forEach(a => {
        if (Object.prototype.hasOwnProperty.call(d, a)) {
          flattenedD[a] = d[a] && (d[a].name || d[a].full_name);
        }
      });
      return flattenedD;
    });
  }
);

export const filteredDataBySearch = createSelector(
  [flattenedData, getQuery],
  (data, query) => {
    if (!data) return null;
    if (!query) return data;
    const updatedData = data;
    return updatedData.filter(d =>
      Object.keys(d).some(key => {
        if (Object.prototype.hasOwnProperty.call(d, key) && d[key] !== null) {
          return deburrUpper(d[key]).indexOf(query) > -1;
        }
        return false;
      })
    );
  }
);

export const titleLinks = createSelector(
  [getCategory, getData],
  (categoryName, data) => {
    if (!data || isEmpty(data) || !categoryName) return null;
    const categoryId = {
      models: 'full_name',
      scenarios: 'name'
    };
    const updatedData = data;
    return updatedData.map(d => ({
      fieldName: categoryId[categoryName],
      url: `${categoryName}/${d.id}`
    }));
  }
);

const getSelectedFields = createSelector(
  [getSearch, getCategory],
  (search, category) => {
    if (!search) return null;
    let selectedFields = search;
    const selectedKeys = Object.keys(selectedFields).filter(k =>
      k.startsWith(category)
    );
    selectedFields = pick(selectedFields, selectedKeys);

    const fieldsWithoutPrefix = {};
    Object.keys(selectedFields).forEach(k => {
      const keyWithoutPrefix = k.replace(`${category}-`, '');
      fieldsWithoutPrefix[keyWithoutPrefix] = selectedFields[k];
    });
    return fieldsWithoutPrefix;
  }
);

export const getSelectedFieldOptions = createSelector(
  [getSelectedFields],
  fields => {
    if (!fields) return null;
    const fieldOptions = {};
    Object.keys(fields).forEach(key => {
      fieldOptions[key] = { value: fields[key], label: fields[key] };
    });
    return fieldOptions;
  }
);

export const filteredDataByFilters = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters) return data;
    let filteredData = data;
    const availableSubcategories = [];
    Object.keys(filters).forEach(key => {
      filteredData = filteredData.filter(d => {
        if (key === 'category' && d[key] === filters[key]) {
          availableSubcategories.push(d.subcategory);
        }
        return d[key] === undefined || d[key] === filters[key];
      });
    });
    return filteredData;
  }
);

export const getAvailableSubcategories = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters || !filters.category) return [];
    const availableSubcategories = [];
    data.forEach(d => {
      if (d.category === filters.category) {
        availableSubcategories.push(d.subcategory);
      }
    });
    return uniq(availableSubcategories);
  }
);

export const getFilterOptionsByCategory = createSelector(
  [getCategory, getData, getAvailableSubcategories],
  (category, data, subcategories) => {
    if (!category || !data || isEmpty(data)) return null;
    const filters = FILTERS_BY_CATEGORY[category];
    const categoryOptions = {};
    filters.forEach(f => {
      const sanitizedFilterData = [];
      data.forEach(d => {
        if (d[f] !== null && d[f] !== '' && d[f] !== undefined) {
          const filterName = typeof d[f] === 'string' ? d[f] : d[f].name;
          sanitizedFilterData.push(filterName);
        }
      });
      let availableData = uniq(sanitizedFilterData);
      if (f === 'subcategory') {
        availableData = uniq(sanitizedFilterData).filter(
          d => subcategories.indexOf(d) > -1
        );
      }
      categoryOptions[f] = availableData.map(filterData => ({
        value: filterData,
        label: filterData
      }));
    });
    return categoryOptions;
  }
);

export const filterDataByBlackList = createSelector(
  [filteredDataByFilters, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data[0]),
      n => ESP_BLACKLIST[category].indexOf(n) === -1
    );
    return data.map(d => pick(d, whiteList));
  }
);

export const renameDataColumns = createSelector(
  [filterDataByBlackList, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    if (category === 'models') {
      let renamedData = data;
      const changes = [{ old: 'maintainer_name', new: 'developed_by' }];
      renamedData = renamedData.map(d => {
        const updatedD = d;
        changes.forEach(change => {
          if (d[change.old]) {
            updatedD[change.new] = d[change.old];
            delete updatedD[change.new];
          }
        });
        return updatedD;
      });
      return renamedData;
    }
    return data;
  }
);

export default {
  renameDataColumns,
  titleLinks,
  filteredDataByFilters,
  getFilterOptionsByCategory,
  getSelectedFieldOptions
};
<|endoftext|>


<commit_before>// Global template helpers (exported)

var regHelper = Template.registerHelper;
if (typeof regHelper !== "function") {
  regHelper = UI.registerHelper;
}

/*
 * afFieldMessage
 */
regHelper('afFieldMessage', function autoFormFieldMessage(options) {
  options = parseOptions(options, 'afFieldMessage');

  return options.ss.namedContext(options.formId).keyErrorMessage(options.name);
});

/*
 * afFieldIsInvalid
 */
regHelper('afFieldIsInvalid', function autoFormFieldIsInvalid(options) {
  options = parseOptions(options, 'afFieldIsInvalid');

  return options.ss.namedContext(options.formId).keyIsInvalid(options.name);
});

/*
 * afArrayFieldHasMoreThanMinimum
 */
regHelper('afArrayFieldHasMoreThanMinimum', function autoFormArrayFieldHasMoreThanMinimum(options) {
  options = parseOptions(options, 'afArrayFieldHasMoreThanMinimum');

  var range = arrayTracker.getMinMax(options.ss, options.name, options.minCount, options.maxCount);
  var visibleCount = arrayTracker.getVisibleCount(options.formId, options.name);
  return (visibleCount > range.minCount);
});

/*
 * afArrayFieldHasLessThanMaximum
 */
regHelper('afArrayFieldHasLessThanMaximum', function autoFormArrayFieldHasLessThanMaximum(options) {
  options = parseOptions(options, 'afArrayFieldHasLessThanMaximum');

  var range = arrayTracker.getMinMax(options.ss, options.name, options.minCount, options.maxCount);
  var visibleCount = arrayTracker.getVisibleCount(options.formId, options.name);
  return (visibleCount < range.maxCount);
});

/*
 * afFieldValueIs
 */
regHelper('afFieldValueIs', function autoFormFieldValueIs(options) {
  options = parseOptions(options, 'afFieldValueIs');

  var currentValue = AutoForm.getFieldValue(options.formId, options.name);
  return currentValue === options.value;
});

/*
 * afArrayFieldIsFirstVisible
 */
regHelper('afArrayFieldIsFirstVisible', function autoFormArrayFieldIsFirstVisible() {
  var context = this;
  return arrayTracker.isFirstFieldlVisible(context.formId, context.arrayFieldName, context.index);
});

/*
 * afArrayFieldIsLastVisible
 */
regHelper('afArrayFieldIsLastVisible', function autoFormArrayFieldIsLastVisible() {
  var context = this;
  return arrayTracker.isLastFieldlVisible(context.formId, context.arrayFieldName, context.index);
});

/*
 * afFieldValueContains
 */
regHelper('afFieldValueContains', function autoFormFieldValueContains(options) {
  options = parseOptions(options, 'afFieldValueContains');

  var currentValue = AutoForm.getFieldValue(options.formId, options.name);
  return _.isArray(currentValue) && _.contains(currentValue, options.value);
});

/*
 * afFieldLabelText
 */
regHelper('afFieldLabelText', function autoFormFieldLabelText(options) {
  options = parseOptions(options, 'afFieldLabelText');

  if (SimpleSchema._makeGeneric(options.name).slice(-1) === "$") {
    // for array items we don't want to inflect the label because
    // we will end up with a number
    var label = options.ss.label(options.name);
    if (!isNaN(parseInt(label, 10))) {
      return null;
    } else {
      return label;
    }
  } else {
    return options.ss.label(options.name);
  }
});

/*
 * afFieldNames
 */
regHelper("afFieldNames", function autoFormFieldNames(options) {
  options = parseOptions(options, 'afFieldNames');
  var ss = options.ss, name = options.name, namePlusDot, genericName, genericNamePlusDot;

  if (name) {
    namePlusDot = name + ".";
    genericName = SimpleSchema._makeGeneric(name);
    genericNamePlusDot = genericName + ".";
  }

  // Get the list of fields we want included
  var fieldList = AutoForm.findAttribute("fields");
  if (fieldList) {
    fieldList = AutoForm.Utility.stringToArray(fieldList, 'AutoForm: fields attribute must be an array or a string containing a comma-delimited list of fields');

    // Take only those fields in the fieldList that are descendants of the `name` field
    if (name) {
      // Replace generic name with real name. We assume that field names
      // with $ apply to all array items. Field list will not have the
      // correct array field item number instead of $.
      if (genericName !== name) {
        fieldList = _.map(fieldList, function (field) {
          if (field.indexOf(genericNamePlusDot) === 0) {
            return namePlusDot + field.slice(genericNamePlusDot.length);
          }
          return field;
        });
      }

      fieldList = _.filter(fieldList, function filterFieldsByName(field) {
        return field.indexOf(namePlusDot) === 0;
      });
    }

    // If top level fields, be sure to remove any with $ in them
    else {
      fieldList = _.filter(fieldList, function filterFieldsByName(field) {
        return (field.slice(-2) !== '.$' && field.indexOf('.$.') === -1);
      });
    }

    // First we filter out any fields that are subobjects where the
    // parent object is also in the fieldList and is NOT the current
    // field name.
    // This means that if you do `fields="address,address.city"` we
    // will use an afObjectField for address and include only the
    // "city" field within that, but if you instead do `fields="address.city"`
    // we will use a single field for the city, with no afObjectField
    // template around it.
    fieldList = _.reject(fieldList, function (field) {
      var lastDotPos = field.lastIndexOf(".");
      if (lastDotPos === -1) {
        return false; //keep
      }

      var parentField = field.slice(0, lastDotPos);
      if (parentField.slice(-2) === ".$") {
        parentField = parentField.slice(0, -2);
      }
      return _.contains(fieldList, parentField) && parentField !== name && parentField !== genericName;
    });
  }

  if (!fieldList || fieldList.length === 0) {
    // Get list of field names that are descendants of this field's name.
    // If name/genericName is undefined, this will return top-level
    // schema keys.
    fieldList = ss.objectKeys(genericName);

    if (name) {
      // Tack child field name on to end of parent field name. This
      // ensures that we keep the desired array index for array items.
      fieldList = _.map(fieldList, function (field) {
        return name + "." + field;
      });
    }
  }

  // If user wants to omit some fields, remove those from the array
  var omitFields = AutoForm.findAttribute("omitFields");
  if (omitFields) {
    omitFields = AutoForm.Utility.stringToArray(omitFields, 'AutoForm: omitFields attribute must be an array or a string containing a comma-delimited list of fields');
    fieldList = _.difference(fieldList, omitFields);
    // If omitFields contains generic field names (with $) we omit those too
    fieldList = _.reject(fieldList, function (f) {
      return _.contains(omitFields, SimpleSchema._makeGeneric(f));
    });
  }

  // Filter out fields we never want
  fieldList = _.filter(fieldList, function shouldIncludeField(field) {
    var fieldDefs = ss.schema(field);

    // Don't include fields with autoform.omit=true
    if (fieldDefs.autoform && fieldDefs.autoform.omit === true)
      return false;

    // Don't include fields with denyInsert=true when it's an insert form
    if (fieldDefs.denyInsert && options.submitType === "insert")
      return false;

    // Don't include fields with denyUpdate=true when it's an update form
    if (fieldDefs.denyUpdate && options.submitType === "update")
      return false;

    return true;
  });

  // Ensure fields are not added more than once
  fieldList = _.unique(fieldList);

  return fieldList;
});

/*
 * afTemplateName
 *
 * Returns the full template name. In the simplest scenario, this is templateType_templateName
 * as passed in. However, if templateName is not provided, it is looked up in the following
 * manner:
 *
 * 1. autoform.<componentType>.template from the schema (field+type override for all forms)
 * 2. autoform.template from the schema (field override for all forms)
 * 3. template-<componentType> attribute on an ancestor component within the same form (form+type for all fields)
 * 4. template attribute on an ancestor component within the same form (form specificity for all types and fields)
 * 5. Default template for component type, as set by AutoForm.setDefaultTemplateForType
 * 6. Default template, as set by AutoForm.setDefaultTemplate.
 * 7. Built-in default template, currently bootstrap-3.
 */
regHelper('afTemplateName', function afTemplateNameHelper(templateType, templateName) {
  var self = this, result, schemaAutoFormDefs, templateFromAncestor, defaultTemplate;

  var result = templateType + '_' + templateName; // templateName might be undefined, but the result will be the same
  if (Template[result]) {
    return result;
  }

  // If the attributes provided a templateName but that template didn't exist, show a warning
  if (templateName && AutoForm._debug) {
    console.warn(templateType + ': "' + templateName + '" is not a valid template name. Falling back to a different template.');
  }

  // Get `autoform` object from the schema, if present.
  // Skip for quickForm because it renders a form and not a field.
  if (templateType !== 'quickForm' && self.atts && self.atts.name) {
    schemaAutoFormDefs = AutoForm.getSchemaForField(self.atts.name).autoform;
  }

  // Fallback #1: autoform.<componentType>.template from the schema
  if (schemaAutoFormDefs && schemaAutoFormDefs[templateType] && schemaAutoFormDefs[templateType].template && Template[templateType + '_' + schemaAutoFormDefs[templateType].template]) {
    return templateType + '_' + schemaAutoFormDefs[templateType].template;
  }

  // Fallback #2: autoform.template from the schema
  if (schemaAutoFormDefs && schemaAutoFormDefs.template && Template[templateType + '_' + schemaAutoFormDefs.template]) {
    return templateType + '_' + schemaAutoFormDefs.template;
  }

  // Fallback #3: template-<componentType> attribute on an ancestor component within the same form
  templateFromAncestor = AutoForm.findAttribute("template-" + templateType);
  if (templateFromAncestor && Template[templateType + '_' + templateFromAncestor]) {
    return templateType + '_' + templateFromAncestor;
  }

  // Fallback #4: template attribute on an ancestor component within the same form
  templateFromAncestor = AutoForm.findAttribute("template");
  if (templateFromAncestor && Template[templateType + '_' + templateFromAncestor]) {
    return templateType + '_' + templateFromAncestor;
  }

  // Fallback #5: Default template for component type, as set by AutoForm.setDefaultTemplateForType
  defaultTemplate = AutoForm.getDefaultTemplateForType(templateType);
  if (defaultTemplate && Template[templateType + '_' + defaultTemplate]) {
    return templateType + '_' + defaultTemplate;
  }

  // Fallback #6: Default template, as set by AutoForm.setDefaultTemplate
  defaultTemplate = AutoForm.getDefaultTemplate();
  if (defaultTemplate && Template[templateType + '_' + defaultTemplate]) {
    return templateType + '_' + defaultTemplate;
  }

  // Fallback #7: hard-coded default
  return "bootstrap3";
});

/*
 * PRIVATE
 */

function parseOptions(options, helperName) {
  var hash = (options || {}).hash || {};
  // Find the autoform context
  var afContext = AutoForm.find(helperName);
  // Call getDefs for side effect of throwing errors when name is not in schema
  hash.name && AutoForm.Utility.getDefs(afContext.ss, hash.name);
  return _.extend({}, afContext, hash);
}
<commit_msg>fix fields/omitFields with afFieldNames; fixes #451<commit_after>// Global template helpers (exported)

var regHelper = Template.registerHelper;
if (typeof regHelper !== "function") {
  regHelper = UI.registerHelper;
}

/*
 * afFieldMessage
 */
regHelper('afFieldMessage', function autoFormFieldMessage(options) {
  options = parseOptions(options, 'afFieldMessage');

  return options.ss.namedContext(options.formId).keyErrorMessage(options.name);
});

/*
 * afFieldIsInvalid
 */
regHelper('afFieldIsInvalid', function autoFormFieldIsInvalid(options) {
  options = parseOptions(options, 'afFieldIsInvalid');

  return options.ss.namedContext(options.formId).keyIsInvalid(options.name);
});

/*
 * afArrayFieldHasMoreThanMinimum
 */
regHelper('afArrayFieldHasMoreThanMinimum', function autoFormArrayFieldHasMoreThanMinimum(options) {
  options = parseOptions(options, 'afArrayFieldHasMoreThanMinimum');

  var range = arrayTracker.getMinMax(options.ss, options.name, options.minCount, options.maxCount);
  var visibleCount = arrayTracker.getVisibleCount(options.formId, options.name);
  return (visibleCount > range.minCount);
});

/*
 * afArrayFieldHasLessThanMaximum
 */
regHelper('afArrayFieldHasLessThanMaximum', function autoFormArrayFieldHasLessThanMaximum(options) {
  options = parseOptions(options, 'afArrayFieldHasLessThanMaximum');

  var range = arrayTracker.getMinMax(options.ss, options.name, options.minCount, options.maxCount);
  var visibleCount = arrayTracker.getVisibleCount(options.formId, options.name);
  return (visibleCount < range.maxCount);
});

/*
 * afFieldValueIs
 */
regHelper('afFieldValueIs', function autoFormFieldValueIs(options) {
  options = parseOptions(options, 'afFieldValueIs');

  var currentValue = AutoForm.getFieldValue(options.formId, options.name);
  return currentValue === options.value;
});

/*
 * afArrayFieldIsFirstVisible
 */
regHelper('afArrayFieldIsFirstVisible', function autoFormArrayFieldIsFirstVisible() {
  var context = this;
  return arrayTracker.isFirstFieldlVisible(context.formId, context.arrayFieldName, context.index);
});

/*
 * afArrayFieldIsLastVisible
 */
regHelper('afArrayFieldIsLastVisible', function autoFormArrayFieldIsLastVisible() {
  var context = this;
  return arrayTracker.isLastFieldlVisible(context.formId, context.arrayFieldName, context.index);
});

/*
 * afFieldValueContains
 */
regHelper('afFieldValueContains', function autoFormFieldValueContains(options) {
  options = parseOptions(options, 'afFieldValueContains');

  var currentValue = AutoForm.getFieldValue(options.formId, options.name);
  return _.isArray(currentValue) && _.contains(currentValue, options.value);
});

/*
 * afFieldLabelText
 */
regHelper('afFieldLabelText', function autoFormFieldLabelText(options) {
  options = parseOptions(options, 'afFieldLabelText');

  if (SimpleSchema._makeGeneric(options.name).slice(-1) === "$") {
    // for array items we don't want to inflect the label because
    // we will end up with a number
    var label = options.ss.label(options.name);
    if (!isNaN(parseInt(label, 10))) {
      return null;
    } else {
      return label;
    }
  } else {
    return options.ss.label(options.name);
  }
});

/*
 * afFieldNames
 */
regHelper("afFieldNames", function autoFormFieldNames(options) {
  options = parseOptions(options, 'afFieldNames');
  var ss = options.ss, name = options.name, namePlusDot, genericName, genericNamePlusDot;

  if (name) {
    namePlusDot = name + ".";
    genericName = SimpleSchema._makeGeneric(name);
    genericNamePlusDot = genericName + ".";
  }

  // Get the list of fields we want included
  var fieldList = options.fields || AutoForm.findAttribute("fields");
  if (fieldList) {
    fieldList = AutoForm.Utility.stringToArray(fieldList, 'AutoForm: fields attribute must be an array or a string containing a comma-delimited list of fields');

    // Take only those fields in the fieldList that are descendants of the `name` field
    if (name) {
      // Replace generic name with real name. We assume that field names
      // with $ apply to all array items. Field list will not have the
      // correct array field item number instead of $.
      if (genericName !== name) {
        fieldList = _.map(fieldList, function (field) {
          if (field.indexOf(genericNamePlusDot) === 0) {
            return namePlusDot + field.slice(genericNamePlusDot.length);
          }
          return field;
        });
      }

      fieldList = _.filter(fieldList, function filterFieldsByName(field) {
        return field.indexOf(namePlusDot) === 0;
      });
    }

    // If top level fields, be sure to remove any with $ in them
    else {
      fieldList = _.filter(fieldList, function filterFieldsByName(field) {
        return (field.slice(-2) !== '.$' && field.indexOf('.$.') === -1);
      });
    }

    // First we filter out any fields that are subobjects where the
    // parent object is also in the fieldList and is NOT the current
    // field name.
    // This means that if you do `fields="address,address.city"` we
    // will use an afObjectField for address and include only the
    // "city" field within that, but if you instead do `fields="address.city"`
    // we will use a single field for the city, with no afObjectField
    // template around it.
    fieldList = _.reject(fieldList, function (field) {
      var lastDotPos = field.lastIndexOf(".");
      if (lastDotPos === -1) {
        return false; //keep
      }

      var parentField = field.slice(0, lastDotPos);
      if (parentField.slice(-2) === ".$") {
        parentField = parentField.slice(0, -2);
      }
      return _.contains(fieldList, parentField) && parentField !== name && parentField !== genericName;
    });
  }

  if (!fieldList || fieldList.length === 0) {
    // Get list of field names that are descendants of this field's name.
    // If name/genericName is undefined, this will return top-level
    // schema keys.
    fieldList = ss.objectKeys(genericName);

    if (name) {
      // Tack child field name on to end of parent field name. This
      // ensures that we keep the desired array index for array items.
      fieldList = _.map(fieldList, function (field) {
        return name + "." + field;
      });
    }
  }

  // If user wants to omit some fields, remove those from the array
  var omitFields = options.omitFields || AutoForm.findAttribute("omitFields");
  if (omitFields) {
    omitFields = AutoForm.Utility.stringToArray(omitFields, 'AutoForm: omitFields attribute must be an array or a string containing a comma-delimited list of fields');
    fieldList = _.difference(fieldList, omitFields);
    // If omitFields contains generic field names (with $) we omit those too
    fieldList = _.reject(fieldList, function (f) {
      return _.contains(omitFields, SimpleSchema._makeGeneric(f));
    });
  }

  // Filter out fields we never want
  fieldList = _.filter(fieldList, function shouldIncludeField(field) {
    var fieldDefs = ss.schema(field);

    // Don't include fields with autoform.omit=true
    if (fieldDefs.autoform && fieldDefs.autoform.omit === true)
      return false;

    // Don't include fields with denyInsert=true when it's an insert form
    if (fieldDefs.denyInsert && options.submitType === "insert")
      return false;

    // Don't include fields with denyUpdate=true when it's an update form
    if (fieldDefs.denyUpdate && options.submitType === "update")
      return false;

    return true;
  });

  // Ensure fields are not added more than once
  fieldList = _.unique(fieldList);

  return fieldList;
});

/*
 * afTemplateName
 *
 * Returns the full template name. In the simplest scenario, this is templateType_templateName
 * as passed in. However, if templateName is not provided, it is looked up in the following
 * manner:
 *
 * 1. autoform.<componentType>.template from the schema (field+type override for all forms)
 * 2. autoform.template from the schema (field override for all forms)
 * 3. template-<componentType> attribute on an ancestor component within the same form (form+type for all fields)
 * 4. template attribute on an ancestor component within the same form (form specificity for all types and fields)
 * 5. Default template for component type, as set by AutoForm.setDefaultTemplateForType
 * 6. Default template, as set by AutoForm.setDefaultTemplate.
 * 7. Built-in default template, currently bootstrap-3.
 */
regHelper('afTemplateName', function afTemplateNameHelper(templateType, templateName) {
  var self = this, result, schemaAutoFormDefs, templateFromAncestor, defaultTemplate;

  var result = templateType + '_' + templateName; // templateName might be undefined, but the result will be the same
  if (Template[result]) {
    return result;
  }

  // If the attributes provided a templateName but that template didn't exist, show a warning
  if (templateName && AutoForm._debug) {
    console.warn(templateType + ': "' + templateName + '" is not a valid template name. Falling back to a different template.');
  }

  // Get `autoform` object from the schema, if present.
  // Skip for quickForm because it renders a form and not a field.
  if (templateType !== 'quickForm' && self.atts && self.atts.name) {
    schemaAutoFormDefs = AutoForm.getSchemaForField(self.atts.name).autoform;
  }

  // Fallback #1: autoform.<componentType>.template from the schema
  if (schemaAutoFormDefs && schemaAutoFormDefs[templateType] && schemaAutoFormDefs[templateType].template && Template[templateType + '_' + schemaAutoFormDefs[templateType].template]) {
    return templateType + '_' + schemaAutoFormDefs[templateType].template;
  }

  // Fallback #2: autoform.template from the schema
  if (schemaAutoFormDefs && schemaAutoFormDefs.template && Template[templateType + '_' + schemaAutoFormDefs.template]) {
    return templateType + '_' + schemaAutoFormDefs.template;
  }

  // Fallback #3: template-<componentType> attribute on an ancestor component within the same form
  templateFromAncestor = AutoForm.findAttribute("template-" + templateType);
  if (templateFromAncestor && Template[templateType + '_' + templateFromAncestor]) {
    return templateType + '_' + templateFromAncestor;
  }

  // Fallback #4: template attribute on an ancestor component within the same form
  templateFromAncestor = AutoForm.findAttribute("template");
  if (templateFromAncestor && Template[templateType + '_' + templateFromAncestor]) {
    return templateType + '_' + templateFromAncestor;
  }

  // Fallback #5: Default template for component type, as set by AutoForm.setDefaultTemplateForType
  defaultTemplate = AutoForm.getDefaultTemplateForType(templateType);
  if (defaultTemplate && Template[templateType + '_' + defaultTemplate]) {
    return templateType + '_' + defaultTemplate;
  }

  // Fallback #6: Default template, as set by AutoForm.setDefaultTemplate
  defaultTemplate = AutoForm.getDefaultTemplate();
  if (defaultTemplate && Template[templateType + '_' + defaultTemplate]) {
    return templateType + '_' + defaultTemplate;
  }

  // Fallback #7: hard-coded default
  return "bootstrap3";
});

/*
 * PRIVATE
 */

function parseOptions(options, helperName) {
  var hash = (options || {}).hash || {};
  // Find the autoform context
  var afContext = AutoForm.find(helperName);
  // Call getDefs for side effect of throwing errors when name is not in schema
  hash.name && AutoForm.Utility.getDefs(afContext.ss, hash.name);
  return _.extend({}, afContext, hash);
}
<|endoftext|>


<commit_before>var app = require('express')()
  , fs = require('fs')
//, http = require('http').Server(app)
  , https = require('https').Server({
      key: fs.readFileSync('/etc/ssl/www_destruct_co.key'),
      cert: fs.readFileSync('/etc/ssl/www_destruct_co.crt'),
      ca: fs.readFileSync('/etc/ssl/www_destruct_co.ca-bundle')
    }, app)
  , io = require('socket.io')(https);

app.get('/', function(req, res){
  res.send('
Hello world
');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

<commit_msg>fixing ssl path<commit_after>var app = require('express')()
  , fs = require('fs')
//, http = require('http').Server(app)
  , https = require('https').Server({
      key: fs.readFileSync('/etc/ssl/www_destruct_co.key'),
      cert: fs.readFileSync('/etc/ssl/www_destruct_co.crt'),
      ca: fs.readFileSync('/etc/ssl/www_destruct_co.ca-bundle')
    }, app)
  , io = require('socket.io')(https);

app.get('/', function(req, res){
  res.send('
Hello world
');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

https.listen(3000, function(){
  console.log('listening on *:3000');
});

<|endoftext|>