<commit_before>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2005-2016 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function() {

"use strict";

var ui = angular.module('axelor.ui');

function BaseCardsCtrl(type, $scope, $element) {

	ui.DSViewCtrl(type, $scope, $element);

	$scope.getRouteOptions = function() {
		return {
			mode: type,
			args: []
		};
	};

	$scope.setRouteOptions = function(options) {
		if (!$scope.isNested) {
			$scope.updateRoute();
		}
	};

	var ds = $scope._dataSource;
	var initialized = false;

	$scope.onShow = function (viewPromise) {

		if (initialized) {
			return $scope.onRefresh();
		}

		initialized = true;

		viewPromise.then(function (meta) {
			$scope.parse(meta.fields, meta.view);
			$scope.$broadcast("on:clear-filter-silent");
		});
	};

	$scope.parse = function (fields, view) {

	};

	$scope.onNew = function () {
		$scope.switchTo('form', function (formScope) {
			formScope.edit(null);
			formScope.setEditable();
			formScope.$broadcast("on:new");
		});
	};

	$scope.onRefresh = function () {
		return $scope.filter({});
	};

	function update(records) {
		$scope.records = records;
	}

	$scope.filter = function(options) {
		var view = $scope.schema;
		var opts = {
			fields: _.pluck($scope.fields, 'name')
		};

		if (options.criteria || options._domains) {
			opts.filter = options;
		}
		if (options.archived !== undefined) {
			opts.archived = options.archived;
		}
		if (view.orderBy) {
			opts.sortBy = view.orderBy.split(',');
		}

		return ds.search(opts).success(update).then(function () {
			return ds.fixPage();
		});
	};

	$scope.pagerText = function() {
		var page = ds._page;
		if (page && page.from !== undefined) {
			if (page.total === 0) return null;
			return _t("{0} to {1} of {2}", page.from + 1, page.to, page.total);
		}
	};

	$scope.onNext = function() {
		var fields = _.pluck($scope.fields, 'name');
		return ds.next(fields).success(update);
	};

	$scope.onPrev = function() {
		var fields = _.pluck($scope.fields, 'name');
		return ds.prev(fields).success(update);
	};
}

ui.controller("CardsCtrl", ['$scope', '$element', function CardsCtrl($scope, $element) {

	BaseCardsCtrl.call(this, 'cards', $scope, $element);

	$scope.viewItems = {};

	$scope.parse = function (fields, view) {
		var viewItems = {};
		_.each(view.items, function (item) {
			if (item.name) {
				viewItems[item.name] = _.extend({}, item, fields[item.name], item.widgetAttrs);
			}
		});
		$scope.viewItems = viewItems;
		$scope.onRefresh();
		$scope.waitForActions(axelor.$adjustSize);
	};

	$scope.onExport = function (full) {
		var fields = full ? [] : _.pluck($scope.viewItems, 'name');
		return $scope._dataSource.export_(fields).success(function(res) {
			var fileName = res.fileName;
			var filePath = 'ws/rest/' + $scope._model + '/export/' + fileName;
			ui.download(filePath, fileName);
		});
	};
}]);

ui.controller("KanbanCtrl", ['$scope', '$element', function KanbanCtrl($scope, $element) {

	BaseCardsCtrl.call(this, 'kanban', $scope, $element);

	$scope.parse = function (fields, view) {
		var columnBy = fields[view.columnBy] || {};
		var columns = _.map(columnBy.selectionList, function (item) {
			return item;
		});

		columns = _.first(columns, 6);

		var first = _.first(columns);
		if (view.onNew) {
			first.canCreate = true;
		}

		var sequenceBy = fields[view.sequenceBy] || {};
		if (["integer", "long"].indexOf(sequenceBy.type) === -1 || ["id", "version"].indexOf(sequenceBy.name) > -1) {
			throw new Error("Invalid sequenceBy field in view: " + view.name);
		}

		$scope.sortableOptions.disabled = !view.draggable;
		$scope.columns = columns;
		$scope.colSpan = "kanban-cs-" + columns.length;
	};

	$scope.move = function (record, to, next, prev) {
		if(!record) {
		    return;
		}
		var view = $scope.schema;
		var rec = _.pick(record, "id", "version", view.sequenceBy);
		var ds = $scope._dataSource._new($scope._model);

		// update columnBy
		rec[view.columnBy] = to;

		// update sequenceBy
		var all = _.compact([prev, rec, next]);
		var offset = _.min(_.pluck(all, view.sequenceBy)) || 0;

		_.each(all, function (item, i) {
			item[view.sequenceBy] = offset + i;
		});

		return ds.saveAll(all).success(function (records) {
			_.each(all, function (item) {
				_.extend(item, ds.get(item.id));
			});
			record.version = rec.version;
		});
	};

	$scope.onRefresh = function () {
		$scope.$broadcast("on:refresh");
	};

	$scope.filter = function(searchFilter) {
		var options = {};
		if (searchFilter.criteria || searchFilter._domains) {
			options = {
				filter: searchFilter
			};
			if (searchFilter.archived !== undefined) {
				options.archived = searchFilter.archived;
			}
			$scope.$broadcast("on:filter", options);
		}
	};

	$scope.sortableOptions = {
		connectWith: ".kanban-card-list",
		items: ".kanban-card",
		tolerance: "pointer",
		stop: function (event, ui) {
			var item = ui.item;
			var sortable = item.sortable;
			var source = sortable.source.scope();
			var target = (sortable.droptarget || $(this)).scope();

			var next = item.next().scope();
			var prev = item.prev().scope();
			if (next) next = next.record;
			if (prev) prev = prev.record;

			var index = sortable.dropindex;
			if (source === target && sortable.index === index) {
				return;
			}

			$scope.move(target.records[index], target.column.value, next, prev);
			$scope.$applyAsync();
		}
	};
}]);

ui.directive('uiKanbanColumn', ["ActionService", function (ActionService) {

	return {
		scope: true,
		link: function (scope, element, attrs) {

			var ds = scope._dataSource._new(scope._model);
			var view = scope.schema;
			var elemMore = element.children(".kanban-more");

			ds._context = _.extend({}, scope._dataSource._context);
			ds._context[view.columnBy] = scope.column.value;
			ds._page.limit = view.limit || 20;

			var domain = "self." + view.columnBy + " = :" + view.columnBy;
			ds._domain = scope._dataSource._domain ? scope._dataSource._domain + " AND " + domain : domain;

			scope.records = [];

			function fetch(options) {
				var opts = _.extend({
					offset: 0,
					sortBy: [view.sequenceBy]
				}, options);
				elemMore.hide();
				return ds.search(opts).success(function (records) {
					scope.records = scope.records.concat(records);
					elemMore.fadeIn('slow');
				});
			}

			scope.hasMore = function () {
				var page = ds._page;
				var next = page.from + page.limit;
				return next < page.total;
			};

			scope.isEmpty = function () {
				return scope.records.length == 0;
			};

			scope.onMore = function () {
				var page = ds._page;
				var next = scope.records.length;
				if (next < page.total) {
					return fetch({
						offset: next
					});
				}
			};

			var onNew = null;

			scope.getContext = function () {
				var ctx = _.extend({}, scope._context);
				ctx._value = scope.newItem;
				return ctx;
			};

			scope.newItem = null;
			scope.onCreate = function () {

				var rec = scope.record = {};
				var view = scope.schema;

				rec[view.columnBy] = scope.column.value;

				if (onNew === null) {
					onNew = ActionService.handler(scope, element, {
						action: view.onNew
					});
				}

				var ds = scope._dataSource;
				var promise = onNew.handle();
				promise.then(function () {
					ds.save(scope.record).success(function (rec) {
						scope.newItem = null;
						scope.records.unshift(rec);
					});
				});
			};

			scope.onEdit = function (record) {
				scope.switchTo('form', function (formScope) {
					if (formScope.canEdit()) {
						formScope.edit(record);
						formScope.setEditable();
					}
				});
			};

			scope.onDelete = function (record) {
				axelor.dialogs.confirm(_t("Do you really want to delete the selected record?"),
				function(confirmed) {
					if (!confirmed) {
						return;
					}
					ds.removeAll([record]).success(function(records, page) {
						var index = scope.records.indexOf(record);
						scope.records.splice(index, 1);
					});
				});
			};

			scope.$on("on:refresh", function (e) {
				scope.newItem = null;
				scope.records.length = 0;
				fetch();
			});

			scope.$on("on:filter", function (e, options) {
				scope.newItem = null;
				scope.records.length = 0;
				return fetch(options);
			});

			element.on("click", ".kanban-card", function (e) {
				if ($(e.target).parents(".kanban-card-menu").size()) {
					return;
				}
				var elem = $(this);
				var record = elem.scope().record;
				scope.onEdit(record);
				scope.applyLater();
			});

			fetch();
		}
	};
}]);

ui.directive('uiCards', function () {

	return function (scope, element, attrs) {

		var onRefresh = scope.onRefresh;
		scope.onRefresh = function () {
			scope.records = null;
			return onRefresh.apply(scope, arguments);
		};

		scope.onEdit = function (record, readonly) {
			var ds = scope._dataSource;
			var page = ds._page;
			page.index = record ? ds._data.indexOf(record) : -1;
			scope.switchTo('form', function (formScope) {
				if (!readonly && formScope.canEdit()) {
					formScope.setEditable();
				}
			});
		};

		scope.onDelete = function (record) {
			axelor.dialogs.confirm(_t("Do you really want to delete the selected record?"),
			function(confirmed) {
				if (!confirmed) {
					return;
				}
				var ds = scope._dataSource;
				ds.removeAll([record]).success(function(records, page) {
					var index = scope.records.indexOf(record);
					scope.records.splice(index, 1);
				});
			});
		};

		element.on("click", ".kanban-card", function (e) {
			if ($(e.target).parents(".kanban-card-menu").size()) {
				return;
			}
			var elem = $(this);
			var record = elem.scope().record;
			scope.onEdit(record, true);
			scope.applyLater();
		});
	};
});

ui.directive('uiCard', ["$compile", function ($compile) {

	return {
		scope: true,
		link: function (scope, element, attrs) {

			var body = element.find(".kanban-card-body");
			var record = scope.record;
			var evalScope = axelor.$evalScope(scope);

			evalScope.record = record;
			evalScope.getContext = scope.getContext = function () {
				var ctx = _.extend({}, scope._context, scope.record);
				ctx._model = scope._model;
				return ctx;
			};

			if (!record.$processed) {
				element.hide();
			}

			function process(record) {
				if (record.$processed) {
					return record;
				}
				record.$processed = true;
				for (var name in record) {
					if (!record.hasOwnProperty(name) || name.indexOf('.') === -1) {
						continue;
					}
					var nested = record;
					var names = name.split('.');
					var head = _.first(names, names.length - 1);
					var last = _.last(names);
					var i, n;
					for (i = 0; i < head.length; i++) {
						n = head[i];
						nested = nested[n] || (nested[n] = {});
					}
					nested[last] = record[name];
				}
				return record;
			}

			evalScope.$watch("record", function (record) {
				_.extend(evalScope, process(record));
			}, true);

			evalScope.$image = function (fieldName, imageName) {
				return ui.formatters.$image(scope, fieldName, imageName);
			};

			evalScope.$fmt = function (fieldName) {
				return ui.formatters.$fmt(scope, fieldName, evalScope[fieldName]);
			};

			var template = (scope.schema.template || "").trim();
			if (template.indexOf('<') !== 0) {
				template = "" + template + "";
			}

			scope.hilite = null;

			$compile(template)(evalScope).appendTo(body);

			var hilites = scope.schema.hilites || [];
			for (var i = 0; i < hilites.length; i++) {
				var hilite = hilites[i];
				if (axelor.$eval(evalScope, hilite.condition, scope.record)) {
					scope.hilite = hilite;
					break;
				}
			}

			if (scope.schema.cardWidth) {
				element.parent().css("width", scope.schema.cardWidth);
			}

			element.fadeIn("slow");
		}
	};
}]);

})();
<commit_msg>Fix click action issue on cards view<commit_after>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2005-2016 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function() {

"use strict";

var ui = angular.module('axelor.ui');

function BaseCardsCtrl(type, $scope, $element) {

	ui.DSViewCtrl(type, $scope, $element);

	$scope.getRouteOptions = function() {
		return {
			mode: type,
			args: []
		};
	};

	$scope.setRouteOptions = function(options) {
		if (!$scope.isNested) {
			$scope.updateRoute();
		}
	};

	var ds = $scope._dataSource;
	var initialized = false;

	$scope.onShow = function (viewPromise) {

		if (initialized) {
			return $scope.onRefresh();
		}

		initialized = true;

		viewPromise.then(function (meta) {
			$scope.parse(meta.fields, meta.view);
			$scope.$broadcast("on:clear-filter-silent");
		});
	};

	$scope.parse = function (fields, view) {

	};

	$scope.onNew = function () {
		$scope.switchTo('form', function (formScope) {
			formScope.edit(null);
			formScope.setEditable();
			formScope.$broadcast("on:new");
		});
	};

	$scope.onRefresh = function () {
		return $scope.filter({});
	};

	function update(records) {
		$scope.records = records;
	}

	$scope.filter = function(options) {
		var view = $scope.schema;
		var opts = {
			fields: _.pluck($scope.fields, 'name')
		};

		if (options.criteria || options._domains) {
			opts.filter = options;
		}
		if (options.archived !== undefined) {
			opts.archived = options.archived;
		}
		if (view.orderBy) {
			opts.sortBy = view.orderBy.split(',');
		}

		return ds.search(opts).success(update).then(function () {
			return ds.fixPage();
		});
	};

	$scope.pagerText = function() {
		var page = ds._page;
		if (page && page.from !== undefined) {
			if (page.total === 0) return null;
			return _t("{0} to {1} of {2}", page.from + 1, page.to, page.total);
		}
	};

	$scope.onNext = function() {
		var fields = _.pluck($scope.fields, 'name');
		return ds.next(fields).success(update);
	};

	$scope.onPrev = function() {
		var fields = _.pluck($scope.fields, 'name');
		return ds.prev(fields).success(update);
	};
}

ui.controller("CardsCtrl", ['$scope', '$element', function CardsCtrl($scope, $element) {

	BaseCardsCtrl.call(this, 'cards', $scope, $element);

	$scope.viewItems = {};

	$scope.parse = function (fields, view) {
		var viewItems = {};
		_.each(view.items, function (item) {
			if (item.name) {
				viewItems[item.name] = _.extend({}, item, fields[item.name], item.widgetAttrs);
			}
		});
		$scope.viewItems = viewItems;
		$scope.onRefresh();
		$scope.waitForActions(axelor.$adjustSize);
	};

	$scope.onExport = function (full) {
		var fields = full ? [] : _.pluck($scope.viewItems, 'name');
		return $scope._dataSource.export_(fields).success(function(res) {
			var fileName = res.fileName;
			var filePath = 'ws/rest/' + $scope._model + '/export/' + fileName;
			ui.download(filePath, fileName);
		});
	};
}]);

ui.controller("KanbanCtrl", ['$scope', '$element', function KanbanCtrl($scope, $element) {

	BaseCardsCtrl.call(this, 'kanban', $scope, $element);

	$scope.parse = function (fields, view) {
		var columnBy = fields[view.columnBy] || {};
		var columns = _.map(columnBy.selectionList, function (item) {
			return item;
		});

		columns = _.first(columns, 6);

		var first = _.first(columns);
		if (view.onNew) {
			first.canCreate = true;
		}

		var sequenceBy = fields[view.sequenceBy] || {};
		if (["integer", "long"].indexOf(sequenceBy.type) === -1 || ["id", "version"].indexOf(sequenceBy.name) > -1) {
			throw new Error("Invalid sequenceBy field in view: " + view.name);
		}

		$scope.sortableOptions.disabled = !view.draggable;
		$scope.columns = columns;
		$scope.colSpan = "kanban-cs-" + columns.length;
	};

	$scope.move = function (record, to, next, prev) {
		if(!record) {
		    return;
		}
		var view = $scope.schema;
		var rec = _.pick(record, "id", "version", view.sequenceBy);
		var ds = $scope._dataSource._new($scope._model);

		// update columnBy
		rec[view.columnBy] = to;

		// update sequenceBy
		var all = _.compact([prev, rec, next]);
		var offset = _.min(_.pluck(all, view.sequenceBy)) || 0;

		_.each(all, function (item, i) {
			item[view.sequenceBy] = offset + i;
		});

		return ds.saveAll(all).success(function (records) {
			_.each(all, function (item) {
				_.extend(item, ds.get(item.id));
			});
			record.version = rec.version;
		});
	};

	$scope.onRefresh = function () {
		$scope.$broadcast("on:refresh");
	};

	$scope.filter = function(searchFilter) {
		var options = {};
		if (searchFilter.criteria || searchFilter._domains) {
			options = {
				filter: searchFilter
			};
			if (searchFilter.archived !== undefined) {
				options.archived = searchFilter.archived;
			}
			$scope.$broadcast("on:filter", options);
		}
	};

	$scope.sortableOptions = {
		connectWith: ".kanban-card-list",
		items: ".kanban-card",
		tolerance: "pointer",
		stop: function (event, ui) {
			var item = ui.item;
			var sortable = item.sortable;
			var source = sortable.source.scope();
			var target = (sortable.droptarget || $(this)).scope();

			var next = item.next().scope();
			var prev = item.prev().scope();
			if (next) next = next.record;
			if (prev) prev = prev.record;

			var index = sortable.dropindex;
			if (source === target && sortable.index === index) {
				return;
			}

			$scope.move(target.records[index], target.column.value, next, prev);
			$scope.$applyAsync();
		}
	};
}]);

ui.directive('uiKanbanColumn', ["ActionService", function (ActionService) {

	return {
		scope: true,
		link: function (scope, element, attrs) {

			var ds = scope._dataSource._new(scope._model);
			var view = scope.schema;
			var elemMore = element.children(".kanban-more");

			ds._context = _.extend({}, scope._dataSource._context);
			ds._context[view.columnBy] = scope.column.value;
			ds._page.limit = view.limit || 20;

			var domain = "self." + view.columnBy + " = :" + view.columnBy;
			ds._domain = scope._dataSource._domain ? scope._dataSource._domain + " AND " + domain : domain;

			scope.records = [];

			function fetch(options) {
				var opts = _.extend({
					offset: 0,
					sortBy: [view.sequenceBy]
				}, options);
				elemMore.hide();
				return ds.search(opts).success(function (records) {
					scope.records = scope.records.concat(records);
					elemMore.fadeIn('slow');
				});
			}

			scope.hasMore = function () {
				var page = ds._page;
				var next = page.from + page.limit;
				return next < page.total;
			};

			scope.isEmpty = function () {
				return scope.records.length == 0;
			};

			scope.onMore = function () {
				var page = ds._page;
				var next = scope.records.length;
				if (next < page.total) {
					return fetch({
						offset: next
					});
				}
			};

			var onNew = null;

			scope.getContext = function () {
				var ctx = _.extend({}, scope._context);
				ctx._value = scope.newItem;
				return ctx;
			};

			scope.newItem = null;
			scope.onCreate = function () {

				var rec = scope.record = {};
				var view = scope.schema;

				rec[view.columnBy] = scope.column.value;

				if (onNew === null) {
					onNew = ActionService.handler(scope, element, {
						action: view.onNew
					});
				}

				var ds = scope._dataSource;
				var promise = onNew.handle();
				promise.then(function () {
					ds.save(scope.record).success(function (rec) {
						scope.newItem = null;
						scope.records.unshift(rec);
					});
				});
			};

			scope.onEdit = function (record) {
				scope.switchTo('form', function (formScope) {
					if (formScope.canEdit()) {
						formScope.edit(record);
						formScope.setEditable();
					}
				});
			};

			scope.onDelete = function (record) {
				axelor.dialogs.confirm(_t("Do you really want to delete the selected record?"),
				function(confirmed) {
					if (!confirmed) {
						return;
					}
					ds.removeAll([record]).success(function(records, page) {
						var index = scope.records.indexOf(record);
						scope.records.splice(index, 1);
					});
				});
			};

			scope.$on("on:refresh", function (e) {
				scope.newItem = null;
				scope.records.length = 0;
				fetch();
			});

			scope.$on("on:filter", function (e, options) {
				scope.newItem = null;
				scope.records.length = 0;
				return fetch(options);
			});

			element.on("click", ".kanban-card", function (e) {
				if ($(e.target).parents(".kanban-card-menu").size()) {
					return;
				}
				var elem = $(this);
				var record = elem.scope().record;
				scope.onEdit(record);
				scope.applyLater();
			});

			fetch();
		}
	};
}]);

ui.directive('uiCards', function () {

	return function (scope, element, attrs) {

		var onRefresh = scope.onRefresh;
		scope.onRefresh = function () {
			scope.records = null;
			return onRefresh.apply(scope, arguments);
		};

		scope.onEdit = function (record, readonly) {
			var ds = scope._dataSource;
			var page = ds._page;
			page.index = record ? ds._data.indexOf(record) : -1;
			scope.switchTo('form', function (formScope) {
				if (!readonly && formScope.canEdit()) {
					formScope.setEditable();
				}
			});
		};

		scope.onDelete = function (record) {
			axelor.dialogs.confirm(_t("Do you really want to delete the selected record?"),
			function(confirmed) {
				if (!confirmed) {
					return;
				}
				var ds = scope._dataSource;
				ds.removeAll([record]).success(function(records, page) {
					var index = scope.records.indexOf(record);
					scope.records.splice(index, 1);
				});
			});
		};

		element.on("click", ".kanban-card", function (e) {
			if ($(e.target).parents(".kanban-card-menu").size() ||
				$(e.target).is('[ng-click],[ui-action-click],button,a,.iswitch,.ibox')) {
				return;
			}
			var elem = $(this);
			var record = elem.scope().record;
			scope.onEdit(record, true);
			scope.applyLater();
		});
	};
});

ui.directive('uiCard', ["$compile", function ($compile) {

	return {
		scope: true,
		link: function (scope, element, attrs) {

			var body = element.find(".kanban-card-body");
			var record = scope.record;
			var evalScope = axelor.$evalScope(scope);

			evalScope.record = record;
			evalScope.getContext = scope.getContext = function () {
				var ctx = _.extend({}, scope._context, scope.record);
				ctx._model = scope._model;
				return ctx;
			};

			if (!record.$processed) {
				element.hide();
			}

			function process(record) {
				if (record.$processed) {
					return record;
				}
				record.$processed = true;
				for (var name in record) {
					if (!record.hasOwnProperty(name) || name.indexOf('.') === -1) {
						continue;
					}
					var nested = record;
					var names = name.split('.');
					var head = _.first(names, names.length - 1);
					var last = _.last(names);
					var i, n;
					for (i = 0; i < head.length; i++) {
						n = head[i];
						nested = nested[n] || (nested[n] = {});
					}
					nested[last] = record[name];
				}
				return record;
			}

			evalScope.$watch("record", function (record) {
				_.extend(evalScope, process(record));
			}, true);

			evalScope.$image = function (fieldName, imageName) {
				return ui.formatters.$image(scope, fieldName, imageName);
			};

			evalScope.$fmt = function (fieldName) {
				return ui.formatters.$fmt(scope, fieldName, evalScope[fieldName]);
			};

			var template = (scope.schema.template || "").trim();
			if (template.indexOf('<') !== 0) {
				template = "" + template + "";
			}

			scope.hilite = null;

			$compile(template)(evalScope).appendTo(body);

			var hilites = scope.schema.hilites || [];
			for (var i = 0; i < hilites.length; i++) {
				var hilite = hilites[i];
				if (axelor.$eval(evalScope, hilite.condition, scope.record)) {
					scope.hilite = hilite;
					break;
				}
			}

			if (scope.schema.cardWidth) {
				element.parent().css("width", scope.schema.cardWidth);
			}

			element.fadeIn("slow");
		}
	};
}]);

})();
<|endoftext|>


<commit_before>import { DEFAULT_ELASTICSEARCH_HOST } from '@/consts'

export const connection = {
  namespaced: true,
  state: {
    activeInstanceIdx: 0,
    instances: [],
    elasticsearchAdapter: null
  },
  mutations: {
    setElasticsearchAdapter (state, adapter) {
      state.elasticsearchAdapter = adapter
    },
    addElasticsearchInstance (state, instance) {
      state.instances.push(instance)
    },
    renameElasticsearchInstance (state, { name, index }) {
      const instance = state.instances[index]
      if (instance) instance.name = name
    },
    removeInstance (state, index) {
      state.instances.splice(index, 1)
      if (index === state.activeInstanceIdx) {
        state.activeInstanceIdx = 0
      } else if (index < state.activeInstanceIdx) {
        state.activeInstanceIdx = state.activeInstanceIdx - 1
      }
      if (state.instances.length === 0) {
        state.instances.push(Object.assign({}, DEFAULT_ELASTICSEARCH_HOST))
      }
    },
    setActiveInstanceIdx (state, index) {
      state.activeInstanceIdx = index
      state.elasticsearchAdapter = null
    }
  },
  getters: {
    activeInstance: state => {
      return state.instances[state.activeInstanceIdx]
    }
  }
}
<commit_msg>dont create default connection when deleting last one<commit_after>export const connection = {
  namespaced: true,
  state: {
    activeInstanceIdx: 0,
    instances: [],
    elasticsearchAdapter: null
  },
  mutations: {
    setElasticsearchAdapter (state, adapter) {
      state.elasticsearchAdapter = adapter
    },
    addElasticsearchInstance (state, instance) {
      state.instances.push(instance)
    },
    renameElasticsearchInstance (state, { name, index }) {
      const instance = state.instances[index]
      if (instance) instance.name = name
    },
    removeInstance (state, index) {
      state.instances.splice(index, 1)
      if (index === state.activeInstanceIdx) {
        state.activeInstanceIdx = 0
      } else if (index < state.activeInstanceIdx) {
        state.activeInstanceIdx = state.activeInstanceIdx - 1
      }
    },
    setActiveInstanceIdx (state, index) {
      state.activeInstanceIdx = index
      state.elasticsearchAdapter = null
    }
  },
  getters: {
    activeInstance: state => {
      return state.instances[state.activeInstanceIdx]
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @module css-prefixes
 * @requires css
 * @requires css-prefixes.json
 * @requires utils
 */
var cssParser = require('css');
var cssPrefixes = rootRequire('lib/css-prefixes.json');

var utils = rootRequire("lib/checks/utils");

var self = this;

exports.name = "css-prefixes";
exports.category = "compatibility";
exports.check = function(checker, browser) {
    var missingPrefixEquivalent = {};
    var mismatchPrefixEquivalent = {};
    browser.on('har', function(har, done) {
        if (har && har.log && har.log.entries) {
            for (var i = 0; i < har.log.entries.length; i++) {
                var entry = har.log.entries[i];
                if (entry.response.status === 200) {
                    var mediaType = utils.mediaTypeName(entry.response.content
                        .mimeType);
                    if (mediaType === "text/css") {
                        var url = entry.request.url;
                        var cssObj = cssParser.parse(entry.response.content
                            .text, {
                                silent: true
                            });
                        for (var j = 0; j < cssObj.stylesheet.rules.length; j++) {
                            var rule = cssObj.stylesheet.rules[j];
                            var prefixedProperties = {};
                            var unprefixedProperties = {};
                            if (rule.declarations) {
                                for (var k = 0; k < rule.declarations.length; k++) {
                                    var decl = rule.declarations[k];
                                    if (decl.property && hasprefix(decl.property)) {
                                        var unprefixed = unprefix(decl.property);
                                        if (!prefixedProperties[unprefixed]) {
                                            prefixedProperties[unprefixed] = {};
                                        }
                                        prefixedProperties[unprefixed][decl
                                            .property
                                        ] = decl;
                                    } else {
                                        unprefixedProperties[decl.property] =
                                            decl;
                                    }
                                }
                            }
                            var prefixed = Object.keys(prefixedProperties);
                            for (var p = 0; p < prefixed.length; p++) {
                                // add the unprefixed decl if it exists
                                if (unprefixedProperties[prefixed[p]]) {
                                    prefixedProperties[prefixed[p]][
                                        prefixed[p]
                                    ] = unprefixedProperties[prefixed[p]];
                                }
                                var props = prefixedProperties[prefixed[p]];
                                var prefixedNames = Object.keys(props);
                                var ref = props[prefixedNames[0]].value;
                                var misMatchFound = false;
                                for (var n = 1; n < prefixedNames.length; n++) {
                                    // are the various unprefixed decl the same?
                                    if (props[prefixedNames[n]].value !==
                                        ref) {
                                        misMatchFound = true;
                                        break;
                                    }
                                }
                                if (misMatchFound) {
                                    if (!mismatchPrefixEquivalent[url]) {
                                        mismatchPrefixEquivalent[url] = [];
                                    }
                                    mismatchPrefixEquivalent[url].push({
                                        rule: stringify(rule),
                                        position: rule.position.start,
                                        prop: prefixed[p],
                                        decls: values(props).map(
                                            stringify)
                                    });
                                }
                                var equivPrefixes = cssPrefixes[prefixed[p]] ?
                                    cssPrefixes[prefixed[p]].values :
                                    undefined;
                                if (equivPrefixes) {
                                    var missing = [];
                                    for (var l = 0; l < equivPrefixes.length; l++) {
                                        if (!props[equivPrefixes[l]]) {
                                            missing.push(equivPrefixes[l]);
                                        }
                                    }
                                    if (missing.length) {
                                        if (!missingPrefixEquivalent[url]) {
                                            missingPrefixEquivalent[url] = [];
                                        }
                                        missingPrefixEquivalent[url].push({
                                            rule: stringify(rule),
                                            position: rule.position.start,
                                            prop: prefixed[p],
                                            missing: missing,
                                            decls: values(props).map(
                                                stringify),
                                            value: values(props)[0].value
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (Object.keys(missingPrefixEquivalent).length) {
                checker.report("missing-prefixes", self.name, self.category, "warning",{
                    missingPrefixes: missingPrefixEquivalent
                });
            }
            if (Object.keys(mismatchPrefixEquivalent).length) {
                checker.report("mismatching-prefixes", self.name,
                    self.category, "warning",{
                        mismatchingPrefixes: mismatchPrefixEquivalent
                    });
            }
        }
        done();
    });
};

function hasprefix(string) {
    return string.match(/^-[^-]*-/);
}

function unprefix(string) {
    return string.replace(/^-[^-]*-/, '');
}

function stringify(obj) {
    var stringified;
    switch (obj.type) {
        case 'rule':
            stringified = obj.selectors.join(', ') + ' {' + '\n';
            for (var i = 0; i < obj.declarations.length; i++) {
                stringified += '  ' + stringify(obj.declarations[i]);
            }
            stringified += "}";
            break;
        case 'declaration':
            stringified = obj.property + ': ' +
                obj.value + ';\n';
            break;
    }
    return stringified;
}

function values(obj) {
    var vals = Object.keys(obj).map(function(key) {
        return obj[key];
    });
    return vals;
}
<commit_msg>don't fail on unavailable css fix #50<commit_after>/**
 * @module css-prefixes
 * @requires css
 * @requires css-prefixes.json
 * @requires utils
 */
var cssParser = require('css');
var cssPrefixes = rootRequire('lib/css-prefixes.json');

var utils = rootRequire("lib/checks/utils");

var self = this;

exports.name = "css-prefixes";
exports.category = "compatibility";
exports.check = function(checker, browser) {
    var missingPrefixEquivalent = {};
    var mismatchPrefixEquivalent = {};
    browser.on('har', function(har, done) {
        if (har && har.log && har.log.entries) {
            for (var i = 0; i < har.log.entries.length; i++) {
                var entry = har.log.entries[i];
                if (entry.response.status === 200) {
                    var mediaType = utils.mediaTypeName(entry.response.content
                        .mimeType);
                    if (mediaType === "text/css") {
                        if (entry.response.content.text === undefined) {
                            // not sure why that happens
                            // but cssparser breaks on undefined
                            continue;
                        }

                        var url = entry.request.url;
                        var cssObj = cssParser.parse(entry.response.content
                            .text, {
                                silent: true
                            });
                        for (var j = 0; j < cssObj.stylesheet.rules.length; j++) {
                            var rule = cssObj.stylesheet.rules[j];
                            var prefixedProperties = {};
                            var unprefixedProperties = {};
                            if (rule.declarations) {
                                for (var k = 0; k < rule.declarations.length; k++) {
                                    var decl = rule.declarations[k];
                                    if (decl.property && hasprefix(decl.property)) {
                                        var unprefixed = unprefix(decl.property);
                                        if (!prefixedProperties[unprefixed]) {
                                            prefixedProperties[unprefixed] = {};
                                        }
                                        prefixedProperties[unprefixed][decl
                                            .property
                                        ] = decl;
                                    } else {
                                        unprefixedProperties[decl.property] =
                                            decl;
                                    }
                                }
                            }
                            var prefixed = Object.keys(prefixedProperties);
                            for (var p = 0; p < prefixed.length; p++) {
                                // add the unprefixed decl if it exists
                                if (unprefixedProperties[prefixed[p]]) {
                                    prefixedProperties[prefixed[p]][
                                        prefixed[p]
                                    ] = unprefixedProperties[prefixed[p]];
                                }
                                var props = prefixedProperties[prefixed[p]];
                                var prefixedNames = Object.keys(props);
                                var ref = props[prefixedNames[0]].value;
                                var misMatchFound = false;
                                for (var n = 1; n < prefixedNames.length; n++) {
                                    // are the various unprefixed decl the same?
                                    if (props[prefixedNames[n]].value !==
                                        ref) {
                                        misMatchFound = true;
                                        break;
                                    }
                                }
                                if (misMatchFound) {
                                    if (!mismatchPrefixEquivalent[url]) {
                                        mismatchPrefixEquivalent[url] = [];
                                    }
                                    mismatchPrefixEquivalent[url].push({
                                        rule: stringify(rule),
                                        position: rule.position.start,
                                        prop: prefixed[p],
                                        decls: values(props).map(
                                            stringify)
                                    });
                                }
                                var equivPrefixes = cssPrefixes[prefixed[p]] ?
                                    cssPrefixes[prefixed[p]].values :
                                    undefined;
                                if (equivPrefixes) {
                                    var missing = [];
                                    for (var l = 0; l < equivPrefixes.length; l++) {
                                        if (!props[equivPrefixes[l]]) {
                                            missing.push(equivPrefixes[l]);
                                        }
                                    }
                                    if (missing.length) {
                                        if (!missingPrefixEquivalent[url]) {
                                            missingPrefixEquivalent[url] = [];
                                        }
                                        missingPrefixEquivalent[url].push({
                                            rule: stringify(rule),
                                            position: rule.position.start,
                                            prop: prefixed[p],
                                            missing: missing,
                                            decls: values(props).map(
                                                stringify),
                                            value: values(props)[0].value
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (Object.keys(missingPrefixEquivalent).length) {
                checker.report("missing-prefixes", self.name, self.category, "warning",{
                    missingPrefixes: missingPrefixEquivalent
                });
            }
            if (Object.keys(mismatchPrefixEquivalent).length) {
                checker.report("mismatching-prefixes", self.name,
                    self.category, "warning",{
                        mismatchingPrefixes: mismatchPrefixEquivalent
                    });
            }
        }
        done();
    });
};

function hasprefix(string) {
    return string.match(/^-[^-]*-/);
}

function unprefix(string) {
    return string.replace(/^-[^-]*-/, '');
}

function stringify(obj) {
    var stringified;
    switch (obj.type) {
        case 'rule':
            stringified = obj.selectors.join(', ') + ' {' + '\n';
            for (var i = 0; i < obj.declarations.length; i++) {
                stringified += '  ' + stringify(obj.declarations[i]);
            }
            stringified += "}";
            break;
        case 'declaration':
            stringified = obj.property + ': ' +
                obj.value + ';\n';
            break;
    }
    return stringified;
}

function values(obj) {
    var vals = Object.keys(obj).map(function(key) {
        return obj[key];
    });
    return vals;
}
<|endoftext|>


<commit_before>function(body) {
    return Object.keys(body).map(function(name) {
        var market = body[name]
        var pair = name.split('_')
        return {
            market: {
                base: pair[0],
                quote: pair[1]
            },
            asks: market.asks,
            bids: market.bids
        }
    })
}
<commit_msg>poloniex results are in quote-base<commit_after>function(body) {
    return Object.keys(body).map(function(name) {
        var market = body[name]
        var pair = name.split('_')
        return {
            market: {
                base: pair[1],
                quote: pair[0]
            },
            asks: market.asks,
            bids: market.bids
        }
    })
}
<|endoftext|>


<commit_before>var async       = require('async'),
    urlParser   = require('url'),
    Resource    = require('./Resource'),
    EventEmitter = require('eventemitter3');

/**
 * Manages the state and loading of multiple resources to load.
 *
 * @class
 * @param [baseUrl=''] {string} The base url for all resources loaded by this loader.
 * @param [concurrency=10] {number} The number of resources to load concurrently.
 */
function Loader(baseUrl, concurrency) {
    EventEmitter.call(this);

    concurrency = concurrency || 10;

    /**
     * The base url for all resources loaded by this loader.
     *
     * @member {string}
     */
    this.baseUrl = baseUrl || '';

    /**
     * The progress percent of the loader going through the queue.
     *
     * @member {number}
     */
    this.progress = 0;

    /**
     * Loading state of the loader, true if it is currently loading resources.
     *
     * @member {boolean}
     */
    this.loading = false;

    /**
     * The percentage of total progress that a single resource represents.
     *
     * @member {number}
     */
    this._progressChunk = 0;

    /**
     * The middleware to run before loading each resource.
     *
     * @member {function[]}
     */
    this._beforeMiddleware = [];

    /**
     * The middleware to run after loading each resource.
     *
     * @member {function[]}
     */
    this._afterMiddleware = [];

    /**
     * The `_loadResource` function bound with this object context.
     *
     * @private
     * @member {function}
     */
    this._boundLoadResource = this._loadResource.bind(this);

    /**
     * The `_onLoad` function bound with this object context.
     *
     * @private
     * @member {function}
     */
    this._boundOnLoad = this._onLoad.bind(this);

    /**
     * The resource buffer that fills until `load` is called to start loading resources.
     *
     * @private
     * @member {Resource[]}
     */
    this._buffer = [];

    /**
     * Used to track load completion.
     *
     * @private
     * @member {number}
     */
    this._numToLoad = 0;

    /**
     * The resources waiting to be loaded.
     *
     * @private
     * @member {Resource[]}
     */
    this._queue = async.queue(this._boundLoadResource, concurrency);

    /**
     * All the resources for this loader keyed by name.
     *
     * @member {object<string, Resource>}
     */
    this.resources = {};

    /**
     * Emitted once per loaded or errored resource.
     *
     * @event progress
     * @memberof Loader#
     */

    /**
     * Emitted once per errored resource.
     *
     * @event error
     * @memberof Loader#
     */

    /**
     * Emitted once per loaded resource.
     *
     * @event load
     * @memberof Loader#
     */

    /**
     * Emitted when the loader begins to process the queue.
     *
     * @event start
     * @memberof Loader#
     */

    /**
     * Emitted when the queued resources all load.
     *
     * @event complete
     * @memberof Loader#
     */
}

Loader.prototype = Object.create(EventEmitter.prototype);
Loader.prototype.constructor = Loader;
module.exports = Loader;

/**
 * Adds a resource (or multiple resources) to the loader queue.
 *
 * This function can take a wide variety of different parameters. The only thing that is always
 * required the url to load. All the following will work:
 *
 * ```js
 * loader
 *     // normal param syntax
 *     .add('key', 'http://...', function () {})
 *     .add('http://...', function () {})
 *     .add('http://...')
 *
 *     // object syntax
 *     .add({
 *         name: 'key2',
 *         url: 'http://...'
 *     }, function () {})
 *     .add({
 *         url: 'http://...'
 *     }, function () {})
 *     .add({
 *         name: 'key3',
 *         url: 'http://...'
 *         onComplete: function () {}
 *     })
 *     .add({
 *         url: 'https://...',
 *         onComplete: function () {},
 *         crossOrigin: true
 *     })
 *
 *     // you can also pass an array of objects or urls or both
 *     .add([
 *         { name: 'key4', url: 'http://...', onComplete: function () {} },
 *         { url: 'http://...', onComplete: function () {} },
 *         'http://...'
 *     ]);
 * ```
 *
 * @alias enqueue
 * @param [name] {string} The name of the resource to load, if not passed the url is used.
 * @param url {string} The url for this resource, relative to the baseUrl of this loader.
 * @param [options] {object} The options for the load.
 * @param [options.crossOrigin] {boolean} Is this request cross-origin? Default is to determine automatically.
 * @param [options.loadType=Resource.LOAD_TYPE.XHR] {Resource.XHR_LOAD_TYPE} How should this resource be loaded?
 * @param [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] {Resource.XHR_RESPONSE_TYPE} How should the data being
 *      loaded be interpreted when using XHR?
 * @param [callback] {function} Function to call when this specific resource completes loading.
 * @return {Loader}
 */
Loader.prototype.add = Loader.prototype.enqueue = function (name, url, options, cb) {
    // special case of an array of objects or urls
    if (Array.isArray(name)) {
        for (var i = 0; i < name.length; ++i) {
            this.add(name[i]);
        }

        return this;
    }

    // if an object is passed instead of params
    if (typeof name === 'object') {
        cb = url || name.callback || name.onComplete;
        options = name;
        url = name.url;
        name = name.name || name.key || name.url;
    }

    // case where no name is passed shift all args over by one.
    if (typeof url !== 'string') {
        cb = options;
        options = url;
        url = name;
    }

    // now that we shifted make sure we have a proper url.
    if (typeof url !== 'string') {
        throw new Error('No url passed to add resource to loader.');
    }

    // options are optional so people might pass a function and no options
    if (typeof options === 'function') {
        cb = options;
        options = null;
    }

    // check if resource already exists.
    if (this.resources[name]) {
        throw new Error('Resource with name "' + name + '" already exists.');
    }

    // add base url if this isn't an absolute url
    url = this._handleBaseUrl(url);

    // create the store the resource
    this.resources[name] = new Resource(name, url, options);

    if (typeof cb === 'function') {
        this.resources[name].once('afterMiddleware', cb);
    }

    this._numToLoad++;

    // if already loading add it to the worker queue
    if (this._queue.started) {
        this._queue.push(this.resources[name]);
        this._progressChunk = (100 - this.progress) / (this._queue.length() + this._queue.running());
    }
    // otherwise buffer it to be added to the queue later
    else {
        this._buffer.push(this.resources[name]);
        this._progressChunk = 100 / this._buffer.length;
    }

    return this;
};

Loader.prototype._handleBaseUrl = function (url) {
    var parsedUrl = urlParser.parse(url);

    // absolute url, just use it as is.
    if (parsedUrl.protocol || parsedUrl.pathname.indexOf('//') === 0) {
        return url;
    }

    // if baseUrl doesn't end in slash and url doesn't start with slash, then add a slash inbetween
    if (
        this.baseUrl.length &&
        this.baseUrl.lastIndexOf('/') !== this.baseUrl.length - 1 &&
        url.charAt(0) !== '/'
    ) {
        return this.baseUrl + '/' + url;
    }
    else {
        return this.baseUrl + url;
    }
};

/**
 * Sets up a middleware function that will run *before* the
 * resource is loaded.
 *
 * @alias pre
 * @param middleware {function} The middleware function to register.
 * @return {Loader}
 */
Loader.prototype.before = Loader.prototype.pre = function (fn) {
    this._beforeMiddleware.push(fn);

    return this;
};

/**
 * Sets up a middleware function that will run *after* the
 * resource is loaded.
 *
 * @alias use
 * @param middleware {function} The middleware function to register.
 * @return {Loader}
 */
Loader.prototype.after = Loader.prototype.use = function (fn) {
    this._afterMiddleware.push(fn);

    return this;
};

/**
 * Resets the queue of the loader to prepare for a new load.
 *
 * @return {Loader}
 */
Loader.prototype.reset = function () {
    // this.baseUrl = baseUrl || '';

    this.progress = 0;

    this.loading = false;

    this._progressChunk = 0;

    // this._beforeMiddleware.length = 0;
    // this._afterMiddleware.length = 0;

    this._buffer.length = 0;

    this._numToLoad = 0;

    this._queue.kill();
    this._queue.started = false;

    this.resources = {};
};

/**
 * Starts loading the queued resources.
 *
 * @fires start
 * @param [callback] {function} Optional callback that will be bound to the `complete` event.
 * @return {Loader}
 */
Loader.prototype.load = function (cb) {
    // register complete callback if they pass one
    if (typeof cb === 'function') {
        this.once('complete', cb);
    }

    // if the queue has already started we are done here
    if (this._queue.started) {
        return this;
    }

    // notify of start
    this.emit('start', this);

    // start the internal queue
    for (var i = 0; i < this._buffer.length; ++i) {
        this._queue.push(this._buffer[i]);
    }

    // empty the buffer
    this._buffer.length = 0;

    return this;
};

/**
 * Loads a single resource.
 *
 * @fires progress
 * @private
 */
Loader.prototype._loadResource = function (resource, dequeue) {
    var self = this;

    resource._dequeue = dequeue;

    this._runMiddleware(resource, this._beforeMiddleware, function () {
        // resource.on('progress', self.emit.bind(self, 'progress'));

        resource.load(self._boundOnLoad);
    });
};

/**
 * Called once each resource has loaded.
 *
 * @fires complete
 * @private
 */
Loader.prototype._onComplete = function () {
    this.emit('complete', this, this.resources);
};

/**
 * Called each time a resources is loaded.
 *
 * @fires progress
 * @fires error
 * @fires load
 * @private
 */
Loader.prototype._onLoad = function (resource) {
    this.progress += this._progressChunk;

    this.emit('progress', this, resource);

    // run middleware, this *must* happen before dequeue so sub-assets get added properly
    this._runMiddleware(resource, this._afterMiddleware, function () {
        resource.emit('afterMiddleware', resource);

        this._numToLoad--;

        // do completion check
        if (this._numToLoad === 0) {
            this.progress = 100;
            this._onComplete();
        }

        if (resource.error) {
            this.emit('error', resource.error, this, resource);
        }
        else {
            this.emit('load', this, resource);
        }
    });

    // remove this resource from the async queue
    resource._dequeue();
};

/**
 * Run middleware functions on a resource.
 *
 * @private
 */
Loader.prototype._runMiddleware = function (resource, fns, cb) {
    var self = this;

    async.eachSeries(fns, function (fn, next) {
        fn.call(self, resource, next);
    }, cb.bind(this, resource));
};

Loader.LOAD_TYPE = Resource.LOAD_TYPE;
Loader.XHR_READY_STATE = Resource.XHR_READY_STATE;
Loader.XHR_RESPONSE_TYPE = Resource.XHR_RESPONSE_TYPE;
<commit_msg>moved complete after error or load<commit_after>var async       = require('async'),
    urlParser   = require('url'),
    Resource    = require('./Resource'),
    EventEmitter = require('eventemitter3');

/**
 * Manages the state and loading of multiple resources to load.
 *
 * @class
 * @param [baseUrl=''] {string} The base url for all resources loaded by this loader.
 * @param [concurrency=10] {number} The number of resources to load concurrently.
 */
function Loader(baseUrl, concurrency) {
    EventEmitter.call(this);

    concurrency = concurrency || 10;

    /**
     * The base url for all resources loaded by this loader.
     *
     * @member {string}
     */
    this.baseUrl = baseUrl || '';

    /**
     * The progress percent of the loader going through the queue.
     *
     * @member {number}
     */
    this.progress = 0;

    /**
     * Loading state of the loader, true if it is currently loading resources.
     *
     * @member {boolean}
     */
    this.loading = false;

    /**
     * The percentage of total progress that a single resource represents.
     *
     * @member {number}
     */
    this._progressChunk = 0;

    /**
     * The middleware to run before loading each resource.
     *
     * @member {function[]}
     */
    this._beforeMiddleware = [];

    /**
     * The middleware to run after loading each resource.
     *
     * @member {function[]}
     */
    this._afterMiddleware = [];

    /**
     * The `_loadResource` function bound with this object context.
     *
     * @private
     * @member {function}
     */
    this._boundLoadResource = this._loadResource.bind(this);

    /**
     * The `_onLoad` function bound with this object context.
     *
     * @private
     * @member {function}
     */
    this._boundOnLoad = this._onLoad.bind(this);

    /**
     * The resource buffer that fills until `load` is called to start loading resources.
     *
     * @private
     * @member {Resource[]}
     */
    this._buffer = [];

    /**
     * Used to track load completion.
     *
     * @private
     * @member {number}
     */
    this._numToLoad = 0;

    /**
     * The resources waiting to be loaded.
     *
     * @private
     * @member {Resource[]}
     */
    this._queue = async.queue(this._boundLoadResource, concurrency);

    /**
     * All the resources for this loader keyed by name.
     *
     * @member {object<string, Resource>}
     */
    this.resources = {};

    /**
     * Emitted once per loaded or errored resource.
     *
     * @event progress
     * @memberof Loader#
     */

    /**
     * Emitted once per errored resource.
     *
     * @event error
     * @memberof Loader#
     */

    /**
     * Emitted once per loaded resource.
     *
     * @event load
     * @memberof Loader#
     */

    /**
     * Emitted when the loader begins to process the queue.
     *
     * @event start
     * @memberof Loader#
     */

    /**
     * Emitted when the queued resources all load.
     *
     * @event complete
     * @memberof Loader#
     */
}

Loader.prototype = Object.create(EventEmitter.prototype);
Loader.prototype.constructor = Loader;
module.exports = Loader;

/**
 * Adds a resource (or multiple resources) to the loader queue.
 *
 * This function can take a wide variety of different parameters. The only thing that is always
 * required the url to load. All the following will work:
 *
 * ```js
 * loader
 *     // normal param syntax
 *     .add('key', 'http://...', function () {})
 *     .add('http://...', function () {})
 *     .add('http://...')
 *
 *     // object syntax
 *     .add({
 *         name: 'key2',
 *         url: 'http://...'
 *     }, function () {})
 *     .add({
 *         url: 'http://...'
 *     }, function () {})
 *     .add({
 *         name: 'key3',
 *         url: 'http://...'
 *         onComplete: function () {}
 *     })
 *     .add({
 *         url: 'https://...',
 *         onComplete: function () {},
 *         crossOrigin: true
 *     })
 *
 *     // you can also pass an array of objects or urls or both
 *     .add([
 *         { name: 'key4', url: 'http://...', onComplete: function () {} },
 *         { url: 'http://...', onComplete: function () {} },
 *         'http://...'
 *     ]);
 * ```
 *
 * @alias enqueue
 * @param [name] {string} The name of the resource to load, if not passed the url is used.
 * @param url {string} The url for this resource, relative to the baseUrl of this loader.
 * @param [options] {object} The options for the load.
 * @param [options.crossOrigin] {boolean} Is this request cross-origin? Default is to determine automatically.
 * @param [options.loadType=Resource.LOAD_TYPE.XHR] {Resource.XHR_LOAD_TYPE} How should this resource be loaded?
 * @param [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] {Resource.XHR_RESPONSE_TYPE} How should the data being
 *      loaded be interpreted when using XHR?
 * @param [callback] {function} Function to call when this specific resource completes loading.
 * @return {Loader}
 */
Loader.prototype.add = Loader.prototype.enqueue = function (name, url, options, cb) {
    // special case of an array of objects or urls
    if (Array.isArray(name)) {
        for (var i = 0; i < name.length; ++i) {
            this.add(name[i]);
        }

        return this;
    }

    // if an object is passed instead of params
    if (typeof name === 'object') {
        cb = url || name.callback || name.onComplete;
        options = name;
        url = name.url;
        name = name.name || name.key || name.url;
    }

    // case where no name is passed shift all args over by one.
    if (typeof url !== 'string') {
        cb = options;
        options = url;
        url = name;
    }

    // now that we shifted make sure we have a proper url.
    if (typeof url !== 'string') {
        throw new Error('No url passed to add resource to loader.');
    }

    // options are optional so people might pass a function and no options
    if (typeof options === 'function') {
        cb = options;
        options = null;
    }

    // check if resource already exists.
    if (this.resources[name]) {
        throw new Error('Resource with name "' + name + '" already exists.');
    }

    // add base url if this isn't an absolute url
    url = this._handleBaseUrl(url);

    // create the store the resource
    this.resources[name] = new Resource(name, url, options);

    if (typeof cb === 'function') {
        this.resources[name].once('afterMiddleware', cb);
    }

    this._numToLoad++;

    // if already loading add it to the worker queue
    if (this._queue.started) {
        this._queue.push(this.resources[name]);
        this._progressChunk = (100 - this.progress) / (this._queue.length() + this._queue.running());
    }
    // otherwise buffer it to be added to the queue later
    else {
        this._buffer.push(this.resources[name]);
        this._progressChunk = 100 / this._buffer.length;
    }

    return this;
};

Loader.prototype._handleBaseUrl = function (url) {
    var parsedUrl = urlParser.parse(url);

    // absolute url, just use it as is.
    if (parsedUrl.protocol || parsedUrl.pathname.indexOf('//') === 0) {
        return url;
    }

    // if baseUrl doesn't end in slash and url doesn't start with slash, then add a slash inbetween
    if (
        this.baseUrl.length &&
        this.baseUrl.lastIndexOf('/') !== this.baseUrl.length - 1 &&
        url.charAt(0) !== '/'
    ) {
        return this.baseUrl + '/' + url;
    }
    else {
        return this.baseUrl + url;
    }
};

/**
 * Sets up a middleware function that will run *before* the
 * resource is loaded.
 *
 * @alias pre
 * @param middleware {function} The middleware function to register.
 * @return {Loader}
 */
Loader.prototype.before = Loader.prototype.pre = function (fn) {
    this._beforeMiddleware.push(fn);

    return this;
};

/**
 * Sets up a middleware function that will run *after* the
 * resource is loaded.
 *
 * @alias use
 * @param middleware {function} The middleware function to register.
 * @return {Loader}
 */
Loader.prototype.after = Loader.prototype.use = function (fn) {
    this._afterMiddleware.push(fn);

    return this;
};

/**
 * Resets the queue of the loader to prepare for a new load.
 *
 * @return {Loader}
 */
Loader.prototype.reset = function () {
    // this.baseUrl = baseUrl || '';

    this.progress = 0;

    this.loading = false;

    this._progressChunk = 0;

    // this._beforeMiddleware.length = 0;
    // this._afterMiddleware.length = 0;

    this._buffer.length = 0;

    this._numToLoad = 0;

    this._queue.kill();
    this._queue.started = false;

    this.resources = {};
};

/**
 * Starts loading the queued resources.
 *
 * @fires start
 * @param [callback] {function} Optional callback that will be bound to the `complete` event.
 * @return {Loader}
 */
Loader.prototype.load = function (cb) {
    // register complete callback if they pass one
    if (typeof cb === 'function') {
        this.once('complete', cb);
    }

    // if the queue has already started we are done here
    if (this._queue.started) {
        return this;
    }

    // notify of start
    this.emit('start', this);

    // start the internal queue
    for (var i = 0; i < this._buffer.length; ++i) {
        this._queue.push(this._buffer[i]);
    }

    // empty the buffer
    this._buffer.length = 0;

    return this;
};

/**
 * Loads a single resource.
 *
 * @fires progress
 * @private
 */
Loader.prototype._loadResource = function (resource, dequeue) {
    var self = this;

    resource._dequeue = dequeue;

    this._runMiddleware(resource, this._beforeMiddleware, function () {
        // resource.on('progress', self.emit.bind(self, 'progress'));

        resource.load(self._boundOnLoad);
    });
};

/**
 * Called once each resource has loaded.
 *
 * @fires complete
 * @private
 */
Loader.prototype._onComplete = function () {
    this.emit('complete', this, this.resources);
};

/**
 * Called each time a resources is loaded.
 *
 * @fires progress
 * @fires error
 * @fires load
 * @private
 */
Loader.prototype._onLoad = function (resource) {
    this.progress += this._progressChunk;

    this.emit('progress', this, resource);

    // run middleware, this *must* happen before dequeue so sub-assets get added properly
    this._runMiddleware(resource, this._afterMiddleware, function () {
        resource.emit('afterMiddleware', resource);

        this._numToLoad--;

        if (resource.error) {
            this.emit('error', resource.error, this, resource);
        }
        else {
            this.emit('load', this, resource);
        }

        // do completion check
        if (this._numToLoad === 0) {
            this.progress = 100;
            this._onComplete();
        }
    });

    // remove this resource from the async queue
    resource._dequeue();
};

/**
 * Run middleware functions on a resource.
 *
 * @private
 */
Loader.prototype._runMiddleware = function (resource, fns, cb) {
    var self = this;

    async.eachSeries(fns, function (fn, next) {
        fn.call(self, resource, next);
    }, cb.bind(this, resource));
};

Loader.LOAD_TYPE = Resource.LOAD_TYPE;
Loader.XHR_READY_STATE = Resource.XHR_READY_STATE;
Loader.XHR_RESPONSE_TYPE = Resource.XHR_RESPONSE_TYPE;
<|endoftext|>


<commit_before>"use strict";

// A helper for preloading image files
var Preloader = {

  // Coin images
  coinImages: ["images/coins/coin_heads.png", "images/coins/coin_tails.png"],

  // Die images
  dieImages: _.range(1, 7).map(function (value) {
    return "images/dice/die_" + value + ".png";
  }),

  // Card images
  cardImages: ["c", "d", "h", "s"].reduce(function (memo, suit) {
    return memo.concat(_.range(1, 14).map(function (value) {
      return "images/cards/" + suit + value + ".png";
    }));
  }, []).concat["images/cards/jb.png", "images/cards/jr.png"],

  // Bring all of the image types together
  images: [].concat(Preloader.coinImages, Preloader.dieImages, Preloader.cardImages),

  // Preloads all images on the page by adding them to an invisible container
  // tag
  preload: function () {
    var preload_html = _.template($("#preloader-template").html(),
                                  { images: Preloader.images});
    $("

").appendTo("body").hide().html(preload_html);
  }

};<commit_msg>Fix a syntax error<commit_after>"use strict";

// A helper for preloading image files
var Preloader = {

  // Coin images
  coinImages: ["images/coins/coin_heads.png", "images/coins/coin_tails.png"],

  // Die images
  dieImages: _.range(1, 7).map(function (value) {
    return "images/dice/die_" + value + ".png";
  }),

  // Card images
  cardImages: ["c", "d", "h", "s"].reduce(function (memo, suit) {
    return memo.concat(_.range(1, 14).map(function (value) {
      return "images/cards/" + suit + value + ".png";
    }));
  }, []).concat(["images/cards/jb.png", "images/cards/jr.png"]),

  // Bring all of the image types together
  images: [].concat(Preloader.coinImages, Preloader.dieImages, Preloader.cardImages),

  // Preloads all images on the page by adding them to an invisible container
  // tag
  preload: function () {
    var preload_html = _.template($("#preloader-template").html(),
                                  { images: Preloader.images});
    $("

").appendTo("body").hide().html(preload_html);
  }

};<|endoftext|>


<commit_before>/*global $, jQuery, alert, console, error, success, endless, ajax, templateHelper, Routing, appLocale, exports, module, require, define*/
/*jslint nomen: true */ /* Tolerate dangling _ in identifiers */
/*jslint vars: true */ /* Tolerate many var statements per function */
/*jslint white: true */
/*jslint browser: true */
/*jslint devel: true */ /* Assume console, alert, ... */
/*jslint windows: true */ /* Assume Windows */
/*jslint maxerr: 100 */ /* Maximum number of errors */

/*
 * library dependencies:
 *      jquery 1.8.3
 *      jquery tokeninput 9
 *      fos-routing
 * external dependencies:
 *      appLocale
 */

// FansWorld tagify plugin 2.2 allow only suggested tags
// 2.1 function que retorna array de elementos seleccionados
// 2.0 tags texto con auto id, labels as values
// 1.4 fix FB.ui popup
// 1.5 add 'user' type to tagifier
// 1.6 missing comma
// 1.8 prepopulate
// 1.9 (con auto tag de perfiles (user, idol, team))

$(document).ready(function () {

    "use strict";

    // Create the defaults once
    var pluginName = "fwTagify";
    var defaults = {
        theme: 'fansworld',
        queryParam: 'text',
        preventDuplicates: true,
        propertyToSearch: 'label',
        team: {
            selected: []
        },
        idol: {
            selected: []
        },
        user: {
            selected: []
        },
        text: {
            selected: []
        },
        magic: null,
        suggestionsOnly: false,
        prePopulate: [],
        action: null,
        dataSource: null,
        onEntityAdd: function(entity) {},
        onEntityDelete: function(entity) {}
    };

    // The actual plugin constructor
    function Plugin(element, options) {
        this.element = element;
        // jQuery has an extend method which merges the contents of two or
        // more objects, storing the result in the first object. The first object
        // is generally empty as we don't want to alter the default options for
        // future instances of the plugin
        this.options = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this._version = '2.2';
        this.init();
    }

    Plugin.prototype = {
        init: function () {
            // Place initialization logic here
            // You already have access to the DOM element and
            // the options via the instance, e.g. this.element
            // and this.options
            var that = this;
            var i;
            //that.options.dataSource = Routing.generate(appLocale + '_tag_ajaxmatch');
            that.options.magic = parseInt(Math.random() * 9999);
            that.options[that.options.magic] = {
                team: {
                    selected: []
                },
                idol: {
                    selected: []
                },
                user: {
                    selected: []
                },
                text: {
                    selected: []
                }
            };
            that.options.dataSource = Routing.generate(appLocale + $(that.element).attr('data-route'));
            that.options.action = $(that.element).attr('data-action');

            // Precargo tags autogenerados
            var pre = $("#form_prepopulate").val();
            if(typeof(pre) !== 'undefined' && pre.length > 0) {
                pre.split(',').forEach(function(val) {
                    if(val.length > 0) {
                        var tagInfo = val.split(':');
                        var item = {
                            id: tagInfo[0],
                            label: tagInfo[2],
                            value: tagInfo[2],
                            result: {
                                id: tagInfo[0],
                                type: tagInfo[1].toLowerCase()
                            }
                        };
                        that.options.prePopulate.push(item);
                    }
                });
            }
            // Si estoy en un profile base agrego el tag automaticamente
            if ($(".profile_head").length > 0) {
                var profile_type = $(".profile_head").attr("data-profile-type");
                var profile_title = $(".profile_head").attr("data-profile-title");
                var profile_id = $(".profile_head").attr("data-profile-id");
                var item = {
                    id: profile_id,
                    label: profile_title,
                    value: profile_title,
                    result: {
                        id: profile_id,
                        type: profile_type.toLowerCase()
                    }
                };
                console.log("creating auto tag for type: %s, title: %s. id: %s", profile_type, profile_title, profile_id)
                that.options.prePopulate.push(item);
            }
            $(that.element).tagit({
                availableTags: that.options.sampleTags,
                suggestionsOnly: that.options.suggestionsOnly,
                allowSpaces: true,
                // This will make Tag-it submit a single form value, as a comma-delimited field.
                autocomplete: {
                    source: function( request, response ) {
                        console.log("tagit llama autocomplete request.term: " + request.term);
                        $.ajax({
                            url: that.options.dataSource,
                            dataType: "JSON",
                            type: 'GET',
                            data: {
                                'text': request.term
                            },
                            success: function( data ) {
                                response( $.map( data, function( item ) {
                                    if(item.result.type === 'tag') {
                                        item.result.type = 'text';
                                    }
                                    return {
                                        label: item.label, //+ (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                                        value: item.value,
                                        extraData: item.result
                                    };
                                }));
                            }
                        });
                    },
                    minLength: 1
                },
                singleField: true,
                singleFieldNode: $(that.element),
                afterTagAdded: function(evt, ui) {
                    if (!ui.duringInitialization) {
                        that.addEntityItem({label: ui.tagLabel, result: ui.extra});
                    }
                },
                afterTagRemoved: function(evt, ui) {
                    if (!ui.duringInitialization) {
                        that.deleteEntityItem({label: ui.tagLabel, result: ui.tag.data('extra')});
                    }
                }
            });

            for(i = 0; i < that.options.prePopulate.length; i += 1) {
                if (that.options.prePopulate.hasOwnProperty(i)) {
                    var item  = that.options.prePopulate[i];
                    $(that.element).tagit('createTag', item.value, null, null, item.result);
                }
            }
        },
        addEntityItem: function (item) {
            var that = this;
            item.result.type = item.result.type || 'text'; // override to custom tag 'text'
            //that.options[that.options.magic].selected.push(item);
            var a = that.options[that.options.magic];
            a[item.result.type].selected.push(item);
            //that.options[item.result.type].selected.push(item);
            //that.options[this.options.magic].selected.push(item);
            that.updateInput('#form_' + that.options.action + item.result.type, a[item.result.type].selected);
            console.log("will add: " + JSON.stringify(item) + " to: #form_" + that.options.action + item.result.type);
        },
        deleteEntityItem: function(item) {
            var that = this;
            var fields = that.options[that.options.magic];
            var tags = fields[item.result.type].selected;
            var i = null;
            item.result.type = item.result.type || 'text'; // override to custom tag 'text'

            window.ff = fields;
            for (i in tags) {
                if (tags.hasOwnProperty(i)) {
                    var compare = parseInt(tags[i].result.id, 10);
                    if(parseInt(item.result.id, 10) === compare) {
                        delete tags[i];
                        break;
                    }
                }
            }
            that.updateInput('#form_' + that.options.action + item.result.type, fields[item.result.type].selected);
            console.log("will del: " + JSON.stringify(item) + " to: #form_" + that.options.action + item.result.type);
        },
        updateInput: function(inputSelector, list) {
            var i, str = '';
            for (i in list) {
                if (list.hasOwnProperty(i)) {
                    // TODO add hasProperty check
                    if(list[i].result.type === 'text') {
                        str += list[i].label + ',';
                    } else {
                        str += list[i].result.id + ',';
                    }
                }
            }
            $(inputSelector).val(str);
        },
        getAllTags: function() {
            var that = this;
            return that.options[that.options.magic];
        },
        getVersion: function() {
            return this._version;
        }
    };
    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === "object" || !options)
        {
            return this.each(function () {
                // Only allow the plugin to be instantiated once.
                if (!$.data(this, pluginName)) {
                    // Pass options to Plugin constructor, and store Plugin
                    // instance in the elements jQuery data object.
                    $.data(this, pluginName, new Plugin(this, options));
                }
            });
        }
    };
});

// FansWorld sharify plugin 1.0
$(document).ready(function () {

    "use strict";
    // Create the defaults once
    var pluginName = "fwSharify";
    var defaults = {
        fb: false,
        tw: false,
        fw: true,
        onShare: function() {},
        onUnShare: function() {}
    };

    // The actual plugin constructor
    function Plugin(element, options) {
        this.element = element;
        // jQuery has an extend method which merges the contents of two or
        // more objects, storing the result in the first object. The first object
        // is generally empty as we don't want to alter the default options for
        // future instances of the plugin
        this.options = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }
    Plugin.prototype = {
        init: function () {
            var that = this;
            $(that.element).on('click', function() {
                $(that.element).toggleClass('active');
                if ($(this).hasClass('fb')) { that.facebookMiddleware(); }
                if ($(this).hasClass('tw')) { that.twitterMiddleware(); }
                if ($(this).hasClass('fw')) { that.fansworldMiddleware(); }
            });
            that.updateInputValues();
        },
        updateInputValues: function(){
            var that = this;
            $('#form_fb').val(that.options.fb);
            $('#form_tw').val(that.options.tw);
            $('#form_fw').val(that.options.fw);
        },
        facebookMiddleware: function(){
            var that = this;
            if ($(that.element).hasClass('active')) {
                that.options.fb = true;
                FB.ui({
                    method: 'permissions.request',
                    'perms': window.FBperms,
                    'display': 'popup',
                    'response_type': 'signed_request',
                    'fbconnect': 1,
                    'next': 'http://' + location.host + Routing.generate(appLocale + '_' + 'facebook_jstoken')
                },
                function(response) {
                    console.log(response);
                });
            } else {
                that.options.fb = false;
            }
        },
        twitterMiddleware: function(){
            var that = this;
            if($(that.element).hasClass('active')) {
                that.options.tw = true;
                window.open(Routing.generate(appLocale + '_' + 'twitter_redirect'), 'fw_twit_link', 'menubar=no,status=no,toolbar=no,width=500,height=300');
            } else {
                that.options.tw = false;
            }
        },
        fansworldMiddleware: function(){
            var that = this;
            if($(that.element).hasClass('active')) {
                that.options.fw = true;
            } else {
                that.options.fw = false;
            }
        }
    };
    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === "object" || !options)
        {
            return this.each(function () {
                // Only allow the plugin to be instantiated once.
                if (!$.data(this, "plugin_" + pluginName)) {
                    // Pass options to Plugin constructor, and store Plugin
                    // instance in the elements jQuery data object.
                    $.data(this, "plugin_" + pluginName, new Plugin(this, options));
                }
            });
        }
    };
});<commit_msg>fwTagify permite tagger sin feed<commit_after>/*global $, jQuery, alert, console, error, success, endless, ajax, templateHelper, Routing, appLocale, exports, module, require, define*/
/*jslint nomen: true */ /* Tolerate dangling _ in identifiers */
/*jslint vars: true */ /* Tolerate many var statements per function */
/*jslint white: true */
/*jslint browser: true */
/*jslint devel: true */ /* Assume console, alert, ... */
/*jslint windows: true */ /* Assume Windows */
/*jslint maxerr: 100 */ /* Maximum number of errors */

/*
 * library dependencies:
 *      jquery 1.8.3
 *      jquery tokeninput 9
 *      fos-routing
 * external dependencies:
 *      appLocale
 */

// FansWorld tagify plugin 2.2 allow only suggested tags
// 2.1 function que retorna array de elementos seleccionados
// 2.0 tags texto con auto id, labels as values
// 1.4 fix FB.ui popup
// 1.5 add 'user' type to tagifier
// 1.6 missing comma
// 1.8 prepopulate
// 1.9 (con auto tag de perfiles (user, idol, team))

$(document).ready(function () {

    "use strict";

    // Create the defaults once
    var pluginName = "fwTagify";
    var defaults = {
        theme: 'fansworld',
        queryParam: 'text',
        preventDuplicates: true,
        propertyToSearch: 'label',
        team: {
            selected: []
        },
        idol: {
            selected: []
        },
        user: {
            selected: []
        },
        text: {
            selected: []
        },
        magic: null,
        suggestionsOnly: false,
        prePopulate: [],
        action: null,
        dataSource: null,
        onEntityAdd: function(entity) {},
        onEntityDelete: function(entity) {}
    };

    // The actual plugin constructor
    function Plugin(element, options) {
        this.element = element;
        // jQuery has an extend method which merges the contents of two or
        // more objects, storing the result in the first object. The first object
        // is generally empty as we don't want to alter the default options for
        // future instances of the plugin
        this.options = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this._version = '2.2';
        this.init();
    }

    Plugin.prototype = {
        init: function () {
            // Place initialization logic here
            // You already have access to the DOM element and
            // the options via the instance, e.g. this.element
            // and this.options
            var that = this;
            var i;
            //that.options.dataSource = Routing.generate(appLocale + '_tag_ajaxmatch');
            that.options.magic = parseInt(Math.random() * 9999);
            that.options[that.options.magic] = {
                team: {
                    selected: []
                },
                idol: {
                    selected: []
                },
                user: {
                    selected: []
                },
                text: {
                    selected: []
                }
            };
            var route = $(that.element).attr('data-route');
            if(typeof route !== 'undefined') {
                that.options.dataSource = Routing.generate(appLocale + $(that.element).attr('data-route'));
            }
            that.options.action = $(that.element).attr('data-action');

            // Precargo tags autogenerados
            var pre = $("#form_prepopulate").val();
            if(typeof(pre) !== 'undefined' && pre.length > 0) {
                pre.split(',').forEach(function(val) {
                    if(val.length > 0) {
                        var tagInfo = val.split(':');
                        var item = {
                            id: tagInfo[0],
                            label: tagInfo[2],
                            value: tagInfo[2],
                            result: {
                                id: tagInfo[0],
                                type: tagInfo[1].toLowerCase()
                            }
                        };
                        that.options.prePopulate.push(item);
                    }
                });
            }
            // Si estoy en un profile base agrego el tag automaticamente
            if ($(".profile_head").length > 0) {
                var profile_type = $(".profile_head").attr("data-profile-type");
                var profile_title = $(".profile_head").attr("data-profile-title");
                var profile_id = $(".profile_head").attr("data-profile-id");
                var item = {
                    id: profile_id,
                    label: profile_title,
                    value: profile_title,
                    result: {
                        id: profile_id,
                        type: profile_type.toLowerCase()
                    }
                };
                console.log("creating auto tag for type: %s, title: %s. id: %s", profile_type, profile_title, profile_id)
                that.options.prePopulate.push(item);
            }
            var tagParams = {
                availableTags: that.options.sampleTags,
                suggestionsOnly: that.options.suggestionsOnly,
                allowSpaces: true,
                singleField: true,
                singleFieldNode: $(that.element),
                afterTagAdded: function(evt, ui) {
                    if (!ui.duringInitialization) {
                        that.addEntityItem({label: ui.tagLabel, result: ui.extra});
                    }
                },
                afterTagRemoved: function(evt, ui) {
                    if (!ui.duringInitialization) {
                        that.deleteEntityItem({label: ui.tagLabel, result: ui.tag.data('extra')});
                    }
                }
            };

            if(that.options.dataSource) {
                tagParams.autocomplete = {
                    source: function( request, response ) {
                        console.log("tagit llama autocomplete request.term: " + request.term);
                        $.ajax({
                            url: that.options.dataSource,
                            dataType: "JSON",
                            type: 'GET',
                            data: {
                                'text': request.term
                            },
                            success: function( data ) {
                                response( $.map( data, function( item ) {
                                    if(item.result.type === 'tag') {
                                        item.result.type = 'text';
                                    }
                                    return {
                                        label: item.label, //+ (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                                        value: item.value,
                                        extraData: item.result
                                    };
                                }));
                            }
                        });
                    },
                    minLength: 1
                };
            }
            $(that.element).tagit(tagParams);

            for(i = 0; i < that.options.prePopulate.length; i += 1) {
                if (that.options.prePopulate.hasOwnProperty(i)) {
                    var item  = that.options.prePopulate[i];
                    $(that.element).tagit('createTag', item.value, null, null, item.result);
                }
            }
        },
        addEntityItem: function (item) {
            var that = this;
            item.result.type = item.result.type || 'text'; // override to custom tag 'text'
            //that.options[that.options.magic].selected.push(item);
            var a = that.options[that.options.magic];
            a[item.result.type].selected.push(item);
            //that.options[item.result.type].selected.push(item);
            //that.options[this.options.magic].selected.push(item);
            that.updateInput('#form_' + that.options.action + item.result.type, a[item.result.type].selected);
            console.log("will add: " + JSON.stringify(item) + " to: #form_" + that.options.action + item.result.type);
        },
        deleteEntityItem: function(item) {
            var that = this;
            var fields = that.options[that.options.magic];
            var tags = fields[item.result.type].selected;
            var i = null;
            item.result.type = item.result.type || 'text'; // override to custom tag 'text'

            window.ff = fields;
            for (i in tags) {
                if (tags.hasOwnProperty(i)) {
                    var compare = parseInt(tags[i].result.id, 10);
                    if(parseInt(item.result.id, 10) === compare) {
                        delete tags[i];
                        break;
                    }
                }
            }
            that.updateInput('#form_' + that.options.action + item.result.type, fields[item.result.type].selected);
            console.log("will del: " + JSON.stringify(item) + " to: #form_" + that.options.action + item.result.type);
        },
        updateInput: function(inputSelector, list) {
            var i, str = '';
            for (i in list) {
                if (list.hasOwnProperty(i)) {
                    // TODO add hasProperty check
                    if(list[i].result.type === 'text') {
                        str += list[i].label + ',';
                    } else {
                        str += list[i].result.id + ',';
                    }
                }
            }
            $(inputSelector).val(str);
        },
        getAllTags: function() {
            var that = this;
            return that.options[that.options.magic];
        },
        getVersion: function() {
            return this._version;
        }
    };
    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === "object" || !options)
        {
            return this.each(function () {
                // Only allow the plugin to be instantiated once.
                if (!$.data(this, pluginName)) {
                    // Pass options to Plugin constructor, and store Plugin
                    // instance in the elements jQuery data object.
                    $.data(this, pluginName, new Plugin(this, options));
                }
            });
        }
    };
});

// FansWorld sharify plugin 1.0
$(document).ready(function () {

    "use strict";
    // Create the defaults once
    var pluginName = "fwSharify";
    var defaults = {
        fb: false,
        tw: false,
        fw: true,
        onShare: function() {},
        onUnShare: function() {}
    };

    // The actual plugin constructor
    function Plugin(element, options) {
        this.element = element;
        // jQuery has an extend method which merges the contents of two or
        // more objects, storing the result in the first object. The first object
        // is generally empty as we don't want to alter the default options for
        // future instances of the plugin
        this.options = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }
    Plugin.prototype = {
        init: function () {
            var that = this;
            $(that.element).on('click', function() {
                $(that.element).toggleClass('active');
                if ($(this).hasClass('fb')) { that.facebookMiddleware(); }
                if ($(this).hasClass('tw')) { that.twitterMiddleware(); }
                if ($(this).hasClass('fw')) { that.fansworldMiddleware(); }
            });
            that.updateInputValues();
        },
        updateInputValues: function(){
            var that = this;
            $('#form_fb').val(that.options.fb);
            $('#form_tw').val(that.options.tw);
            $('#form_fw').val(that.options.fw);
        },
        facebookMiddleware: function(){
            var that = this;
            if ($(that.element).hasClass('active')) {
                that.options.fb = true;
                FB.ui({
                    method: 'permissions.request',
                    'perms': window.FBperms,
                    'display': 'popup',
                    'response_type': 'signed_request',
                    'fbconnect': 1,
                    'next': 'http://' + location.host + Routing.generate(appLocale + '_' + 'facebook_jstoken')
                },
                function(response) {
                    console.log(response);
                });
            } else {
                that.options.fb = false;
            }
        },
        twitterMiddleware: function(){
            var that = this;
            if($(that.element).hasClass('active')) {
                that.options.tw = true;
                window.open(Routing.generate(appLocale + '_' + 'twitter_redirect'), 'fw_twit_link', 'menubar=no,status=no,toolbar=no,width=500,height=300');
            } else {
                that.options.tw = false;
            }
        },
        fansworldMiddleware: function(){
            var that = this;
            if($(that.element).hasClass('active')) {
                that.options.fw = true;
            } else {
                that.options.fw = false;
            }
        }
    };
    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function (options) {
        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === "object" || !options)
        {
            return this.each(function () {
                // Only allow the plugin to be instantiated once.
                if (!$.data(this, "plugin_" + pluginName)) {
                    // Pass options to Plugin constructor, and store Plugin
                    // instance in the elements jQuery data object.
                    $.data(this, "plugin_" + pluginName, new Plugin(this, options));
                }
            });
        }
    };
});<|endoftext|>