<commit_before>/**
 * 封装支付面板
 */
PayPanel = Ext.extend( Ext.Panel ,{
	feeStore: null ,
	payForm: null,
	feeGrid:null,
	feeData: null,
	constructor: function(){
		// 缴费信息的表单
		this.payForm = new PayForm(this);
		//实例化fee store
		var fields = [
				'fee_sn','busi_name','fee_text','count_text','optr_name','create_time',
				{name: 'real_pay', type: 'int'}, 'create_done_code',
				'prod_sn', 'begin_date','prod_invalid_date','fee_type','buy_num',
				'user_id','acctitem_id','user_type','busi_code'
			]
		this.feeStore = new Ext.data.JsonStore({
			data: [],
			fields: fields
		});
		var lc = langUtils.main("cashPay.pay.columns");
		var bt = langUtils.main("cashPay.pay.buttons");
		this.paySm = new Ext.grid.CheckboxSelectionModel();
		//费用表格
		this.feeGrid = new Ext.grid.GridPanel({
			title: langUtils.main('cashPay.pay._stayTitle'),
			region: 'center',
			border: false,
			sm: this.paySm,
			columns: [
				this.paySm,
			    { header: lc[0], width: 50,renderer: function(v , md, record , i  ){
					return "
取消
";
				}},
				{ header: lc[1], dataIndex: 'busi_name', width: 80},
				{ header: lc[2], dataIndex: 'fee_text',width: 120, renderer:App.qtipValue},
				{ header: lc[3], dataIndex: 'real_pay', width: 70, xtype: 'moneycolumn'},
				{ header: lc[4], dataIndex: 'prod_sn', width: 70},
				{ header: lc[5], dataIndex: 'count_text', width:150, renderer: App.qtipValue},
				{ header: lc[6], dataIndex: 'buy_num', width: 70},
				{ header: lc[7], dataIndex: 'create_time', width: 130},
				{ header: lc[8], dataIndex: 'fee_sn', width: 80},
				{ header: lc[9], dataIndex: 'create_done_code', width: 80}

			],
			ds: this.feeStore,
			listeners: {
				scope: this,
				rowdblclick: this.doRowClick
			}
		});

		this.realPaySm = new Ext.grid.CheckboxSelectionModel();
		this.realFeeStore = new Ext.data.JsonStore({
			fields: fields
		});
		this.realFeeGrid = new Ext.grid.GridPanel({
			title: langUtils.main('cashPay.pay._title'),
			border: false,
			sm: this.realPaySm,
			columns: [
				this.realPaySm,
				{ header: lc[1], dataIndex: 'busi_name', width: 80},
				{ header: lc[2], dataIndex: 'fee_text',width: 120, renderer:App.qtipValue},
				{ header: lc[3], dataIndex: 'real_pay', width: 70, xtype: 'moneycolumn'},
				{ header: lc[4], dataIndex: 'prod_sn', width: 70},
				{ header: lc[5], dataIndex: 'count_text', width:150, renderer: App.qtipValue},
				{ header: lc[6], dataIndex: 'buy_num', width: 70},
				{ header: lc[7], dataIndex: 'create_time', width: 130},
				{ header: lc[8], dataIndex: 'fee_sn', width: 80},
				{ header: lc[9], dataIndex: 'create_done_code', width: 80}

			],
			ds: this.realFeeStore,
			listeners: {
				scope: this,
				rowdblclick: this.doRealRowClick
			}
		});

		PayPanel.superclass.constructor.call(this,{
			id:'PayPanelId',
			border: false,
			layout: 'border',
			items: [

				{
					region: 'center',
					layout: 'border',
					border: false,
					items:[{
						region: 'center',
						layout: 'border',
						items: [this.feeGrid ],
						bbar:['-',
							{text: '确认', iconCls: 'icon-confirm', scope:this, handler: this.doConfirm},'-',
							{text: '移除', iconCls: 'icon-del', scope:this, handler: this.doDelete},'-']
					},
					{
						region: 'south',
						layout: 'fit',
						height: 200,
						items: [this.realFeeGrid ]
					}]
				},{
				region: 'east',
				split: true,
				layout: 'fit',
				width: 230,
				items: this.payForm
			}],
			buttons: [{
				text: bt[0],
				iconCls: 'icon-save',
				width: 100,
				scope: this,
				handler: this.doSave
			}]
		});
		this.loadBaseData();
	},
	loadBaseData: function(){
		// 请求后台的数据
		Ext.Ajax.request({
			scope: this,
			url: Constant.ROOT_PATH + "/core/x/Pay!queryUnPayDetail.action",
			params: {cust_id: App.getCustId()},
			success: function(res, ops){
				var data = Ext.decode(res.responseText);
				this.feeStore.loadData(data["records"]);
				this.feeData = data["simpleObj"];
				Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
				/*var dollar = this.feeData["FEE"]/100.0;
				Ext.getCmp("nfDollar").setValue(dollar);
				Ext.getCmp("nfJianYuan").setValue(0);
				var substrIndex = 1, append = "";
				if(dollar < 0){
					substrIndex = 2;
					append = "-";
				}
				Ext.getCmp("labelDollor").setText(append+ Ext.util.Format.usMoney(dollar).substr(substrIndex));
				var jianYuan = Ext.util.Format.usMoney(dollar * this.feeData["EXC"]);
				Ext.getCmp("LabelJian").setText(append+jianYuan.substr(substrIndex));
				Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
				Ext.getCmp("hdExchange").setValue(this.feeData["EXC"]);*/
			}
		});
	},
	doConfirm: function(){
		var records = this.paySm.getSelections();
		if(records.length > 0){
			if(records.length == this.feeStore.getCount()){
				this.realFeeStore.add(records);
				this.doCalFee();
			}else{
				var recordArray = this.getSameTypeProd(this.feeStore, records);
				this.realFeeStore.add(recordArray);
				this.doCalFee();
			}
		}
	},
	doDelete: function(){
		var records = this.realPaySm.getSelections();
		if(records.length > 0){
			if(records.length == this.realFeeStore.getCount()){
				this.realFeeStore.removeAll();
				this.doCalFee();
			}else{
				var recordArray = this.getSameTypeProd(this.feeStore, records);
				this.realFeeStore.remove(recordArray);
				this.doCalFee();
			}
		}
	},
	doRowClick: function(grid, rowIndex){
		var record = this.feeStore.getAt(rowIndex);
		if(this.realFeeStore.indexOf(record) > 0)
			return;
		var recordArray = this.getSameTypeProd(this.feeStore, record);

		this.realFeeStore.add(recordArray);
		this.doCalFee();
	},
	doRealRowClick: function(grid, rowIndex){
		var record = this.realFeeStore.getAt(rowIndex);
		if(this.realFeeStore.indexOf(record) > 0)
			return;
		var recordArray = this.getSameTypeProd(this.realFeeStore, record);

		this.realFeeStore.remove(recordArray);
		this.doCalFee();
	},
	doCalFee: function(){
		var dollar = 0;
		this.realFeeStore.each(function(record){
			dollar += record.get('real_pay');
		}, this);
		dollar = dollar / 100.0;
		Ext.getCmp("nfDollar").setValue(dollar);
		Ext.getCmp("nfJianYuan").setValue(0);
		var substrIndex = 1, append = "";
		if(dollar < 0){
			substrIndex = 2;
			append = "-";
		}
		Ext.getCmp("labelDollor").setText(append+ Ext.util.Format.usMoney(dollar).substr(substrIndex));
		var jianYuan = Ext.util.Format.usMoney(dollar * this.feeData["EXC"]);
		Ext.getCmp("LabelJian").setText(append+jianYuan.substr(substrIndex));
		Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
		Ext.getCmp("hdExchange").setValue(this.feeData["EXC"]);
	},
	getSameTypeProd: function(store, records){
		var recordArray = [];
		Ext.each(records, function(record){
			var userType = record.get('user_type');
			var prodId = record.get('acctitem_id');
			var userId = record.get('user_id')
			var feeSn = record.get('fee_sn');
			var busiCode = record.get('busi_code');
			if(userType == 'BAND' && prodId){
				//相同用户的宽带订单必须一起支付
				store.each(function(r){
					if(userId == r.get('user_id')){
						recordArray.push(r);
					}
				}, this);
			}else if(busiCode == '1015'){
				//套餐订单，必须一起支付
				store.each(function(r){
					if(r.get('busi_code') == busiCode){
						recordArray.push(r);
					}
				}, this);
			}else{
				//相同用户相同产品必须一起支付
				store.each(function(r){
					if(userId == r.get('user_id') && prodId == r.get('acctitem_id')){
						recordArray.push(r);
					}
				}, this);
			}
		}, this);

		return recordArray;
	},
	deletePay : function() {
		var rec = this.feeGrid.getSelectionModel().getSelected();
		var thiz = this;
		var func = function(flag){
			var comomonParams = App.getValues();
			comomonParams["busiCode"] = "1113";
			var params ={};
			params[CoreConstant.JSON_PARAMS] = Ext.encode(comomonParams);
			Ext.apply(params,{
				fee_sn : rec.get('fee_sn'),
				fee_type : rec.get('fee_type'),
				onlyShowInfo : flag
			});
			var info = "";
			Ext.Ajax.request({
				scope: thiz,
				url: Constant.ROOT_PATH + "/core/x/Pay!cancelUnPayFee.action",
				params: params,
				async : false,
				success: function(res, ops){
					info = Ext.decode(res.responseText);
					if(!flag){
						this.loadBaseData();
						App.getApp().refreshPayInfo(parent);
					}
				}
			});
			return info;
		}
		Confirm( func(true), this ,function(){
			func(false);
		});
	},
	doSaveAndPrint: function(){
		this.doSave(params);
	},
	doSave: function(){
		if(!this.payForm.getForm().isValid()){
			Alert("含有验证不通过的输入项");
			return ;
		}
		Confirm("确定要保存信息吗?", this, function(){
			var params = this.getValues()
			var comomonParams = App.getValues();
			comomonParams["busiCode"] = "1207";
			params[CoreConstant.JSON_PARAMS] = Ext.encode(comomonParams);
			var mb = Show();
			//提交
			Ext.Ajax.request({
				scope: this,
				params: params,
				url: Constant.ROOT_PATH + "/core/x/Pay!savePayNew.action",
				success: function( res, ops){
					var o = Ext.decode( res.responseText );
					mb.hide();
					if(o["exception"]){
						new DebugWindow( o , "btnBusiSave").show();
					} else {
						Alert('支付成功!',function(){
								App.getApp().refreshPayInfo(parent);
								this.success();
							},this);
					}
				}
			});
		});
	},
	getValues: function(){
		var f = this.payForm.getForm();
		var all = f.getValues();
		all["pay.khr"] = all["pay.khr"] * 100;
		all["pay.usd"] = all["pay.usd"] * 100;
		all["pay.cust_id"] = App.getApp().data.custFullInfo.cust.cust_id;
		return all;
	},
	getFee: function(){
		return 0;
	},
	success:function(){
		App.getApp().menu.bigWindow.show({ text: '发票打印',  attrs: {busiCode:'1068',
					url: 'pages/business/pay/Print.jsp?type=through'}} ,{width: 710, height: 460});
	}
});

Ext.onReady(function(){
	var pay = new PayPanel();
	TemplateFactory.gViewport(pay);
});<commit_msg><commit_after>/**
 * 封装支付面板
 */
PayPanel = Ext.extend( Ext.Panel ,{
	feeStore: null ,
	payForm: null,
	feeGrid:null,
	feeData: null,
	constructor: function(){
		// 缴费信息的表单
		this.payForm = new PayForm(this);
		//实例化fee store
		var fields = [
				'fee_sn','busi_name','fee_text','count_text','optr_name','create_time',
				{name: 'real_pay', type: 'int'}, 'create_done_code',
				'prod_sn', 'begin_date','prod_invalid_date','fee_type','buy_num',
				'user_id','acctitem_id','user_type','busi_code'
			]
		this.feeStore = new Ext.data.JsonStore({
			data: [],
			fields: fields
		});
		var lc = langUtils.main("cashPay.pay.columns");
		var bt = langUtils.main("cashPay.pay.buttons");
		this.paySm = new Ext.grid.CheckboxSelectionModel();
		//费用表格
		this.feeGrid = new Ext.grid.GridPanel({
			title: langUtils.main('cashPay.pay._stayTitle'),
			region: 'center',
			border: false,
			sm: this.paySm,
			columns: [
				this.paySm,
			    { header: lc[0], width: 50,renderer: function(v , md, record , i  ){
					return "
取消
";
				}},
				{ header: lc[1], dataIndex: 'busi_name', width: 80},
				{ header: lc[2], dataIndex: 'fee_text',width: 120, renderer:App.qtipValue},
				{ header: lc[3], dataIndex: 'real_pay', width: 70, xtype: 'moneycolumn'},
				{ header: lc[4], dataIndex: 'prod_sn', width: 70},
				{ header: lc[5], dataIndex: 'count_text', width:150, renderer: App.qtipValue},
				{ header: lc[6], dataIndex: 'buy_num', width: 70},
				{ header: lc[7], dataIndex: 'create_time', width: 130},
				{ header: lc[8], dataIndex: 'fee_sn', width: 80},
				{ header: lc[9], dataIndex: 'create_done_code', width: 80}

			],
			ds: this.feeStore,
			listeners: {
				scope: this,
				rowdblclick: this.doRowClick
			}
		});

		this.realPaySm = new Ext.grid.CheckboxSelectionModel();
		this.realFeeStore = new Ext.data.JsonStore({
			fields: fields
		});
		this.realFeeGrid = new Ext.grid.GridPanel({
			title: langUtils.main('cashPay.pay._title'),
			border: false,
			sm: this.realPaySm,
			columns: [
				this.realPaySm,
				{ header: lc[1], dataIndex: 'busi_name', width: 80},
				{ header: lc[2], dataIndex: 'fee_text',width: 120, renderer:App.qtipValue},
				{ header: lc[3], dataIndex: 'real_pay', width: 70, xtype: 'moneycolumn'},
				{ header: lc[4], dataIndex: 'prod_sn', width: 70},
				{ header: lc[5], dataIndex: 'count_text', width:150, renderer: App.qtipValue},
				{ header: lc[6], dataIndex: 'buy_num', width: 70},
				{ header: lc[7], dataIndex: 'create_time', width: 130},
				{ header: lc[8], dataIndex: 'fee_sn', width: 80},
				{ header: lc[9], dataIndex: 'create_done_code', width: 80}

			],
			ds: this.realFeeStore,
			listeners: {
				scope: this,
				rowdblclick: this.doRealRowClick
			}
		});

		PayPanel.superclass.constructor.call(this,{
			id:'PayPanelId',
			border: false,
			layout: 'border',
			items: [

				{
					region: 'center',
					layout: 'border',
					border: false,
					items:[{
						region: 'center',
						layout: 'border',
						items: [this.feeGrid ],
						bbar:['-',
							{text: '确认', iconCls: 'icon-confirm', scope:this, handler: this.doConfirm},'-',
							{text: '移除', iconCls: 'icon-del', scope:this, handler: this.doDelete},'-']
					},
					{
						region: 'south',
						layout: 'fit',
						height: 200,
						items: [this.realFeeGrid ]
					}]
				},{
				region: 'east',
				split: true,
				layout: 'fit',
				width: 230,
				items: this.payForm
			}],
			buttons: [{
				text: bt[0],
				iconCls: 'icon-save',
				width: 100,
				scope: this,
				handler: this.doSave
			}]
		});
		this.loadBaseData();
	},
	loadBaseData: function(){
		// 请求后台的数据
		Ext.Ajax.request({
			scope: this,
			url: Constant.ROOT_PATH + "/core/x/Pay!queryUnPayDetail.action",
			params: {cust_id: App.getCustId()},
			success: function(res, ops){
				var data = Ext.decode(res.responseText);
				this.feeStore.loadData(data["records"]);
				this.feeData = data["simpleObj"];
				Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
				/*var dollar = this.feeData["FEE"]/100.0;
				Ext.getCmp("nfDollar").setValue(dollar);
				Ext.getCmp("nfJianYuan").setValue(0);
				var substrIndex = 1, append = "";
				if(dollar < 0){
					substrIndex = 2;
					append = "-";
				}
				Ext.getCmp("labelDollor").setText(append+ Ext.util.Format.usMoney(dollar).substr(substrIndex));
				var jianYuan = Ext.util.Format.usMoney(dollar * this.feeData["EXC"]);
				Ext.getCmp("LabelJian").setText(append+jianYuan.substr(substrIndex));
				Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
				Ext.getCmp("hdExchange").setValue(this.feeData["EXC"]);*/
			}
		});
	},
	doConfirm: function(){
		var records = this.paySm.getSelections();
		if(records.length > 0){
			if(records.length == this.feeStore.getCount()){
				this.realFeeStore.add(records);
				this.doCalFee();
			}else{
				var recordArray = this.getSameTypeProd(this.feeStore, records);
				this.realFeeStore.add(recordArray);
				this.doCalFee();
			}
		}
	},
	doDelete: function(){
		var records = this.realPaySm.getSelections();
		if(records.length > 0){
			if(records.length == this.realFeeStore.getCount()){
				this.realFeeStore.removeAll();
				this.doCalFee();
			}else{
				var recordArray = this.getSameTypeProd(this.feeStore, records);
				this.realFeeStore.remove(recordArray);
				this.doCalFee();
			}
		}
	},
	doRowClick: function(grid, rowIndex){
		var record = this.feeStore.getAt(rowIndex);
		if(this.realFeeStore.indexOf(record) > 0)
			return;
		var recordArray = this.getSameTypeProd(this.feeStore, record);

		this.realFeeStore.add(recordArray);
		this.doCalFee();
	},
	doRealRowClick: function(grid, rowIndex){
		var record = this.realFeeStore.getAt(rowIndex);
		if(this.realFeeStore.indexOf(record) > 0)
			return;
		var recordArray = this.getSameTypeProd(this.realFeeStore, record);

		this.realFeeStore.remove(recordArray);
		this.doCalFee();
	},
	doCalFee: function(){
		var dollar = 0;
		this.realFeeStore.each(function(record){
			dollar += record.get('real_pay');
		}, this);
		dollar = dollar / 100.0;
		Ext.getCmp("nfDollar").setValue(dollar);
		Ext.getCmp("nfJianYuan").setValue(0);
		var substrIndex = 1, append = "";
		if(dollar < 0){
			substrIndex = 2;
			append = "-";
		}
		Ext.getCmp("labelDollor").setText(append+ Ext.util.Format.usMoney(dollar).substr(substrIndex));
		var jianYuan = Ext.util.Format.usMoney(dollar * this.feeData["EXC"]);
		Ext.getCmp("LabelJian").setText(append+jianYuan.substr(substrIndex));
		Ext.getCmp("labelExchange").setText("1USD=" + this.feeData["EXC"] + "KHR");
		Ext.getCmp("hdExchange").setValue(this.feeData["EXC"]);
	},
	getSameTypeProd: function(store, records){
		var recordArray = [];
		Ext.each(records, function(record){
			var userType = record.get('user_type');
			var prodId = record.get('acctitem_id');
			var userId = record.get('user_id')
			var feeSn = record.get('fee_sn');
			var busiCode = record.get('busi_code');
			if(userType == 'BAND' && prodId){
				//相同用户的宽带订单必须一起支付
				store.each(function(r){
					if(userId == r.get('user_id')){
						recordArray.push(r);
					}
				}, this);
			}else if(busiCode == '1015'){
				//套餐订单，必须一起支付
				store.each(function(r){
					if(r.get('busi_code') == busiCode){
						recordArray.push(r);
					}
				}, this);
			}else{
				//相同用户相同产品必须一起支付
				store.each(function(r){
					if(userId == r.get('user_id') && prodId == r.get('acctitem_id')){
						recordArray.push(r);
					}
				}, this);
			}
		}, this);

		return recordArray;
	},
	deletePay : function() {
		var rec = this.feeGrid.getSelectionModel().getSelected();
		var thiz = this;
		var func = function(flag){
			var comomonParams = App.getValues();
			comomonParams["busiCode"] = "1113";
			var params ={};
			params[CoreConstant.JSON_PARAMS] = Ext.encode(comomonParams);
			Ext.apply(params,{
				fee_sn : rec.get('fee_sn'),
				fee_type : rec.get('fee_type'),
				onlyShowInfo : flag
			});
			var info = "";
			Ext.Ajax.request({
				scope: thiz,
				url: Constant.ROOT_PATH + "/core/x/Pay!cancelUnPayFee.action",
				params: params,
				async : false,
				success: function(res, ops){
					info = Ext.decode(res.responseText);
					if(!flag){
						this.loadBaseData();
						App.getApp().refreshPayInfo(parent);
					}
				}
			});
			return info;
		}
		Confirm( func(true), this ,function(){
			func(false);
		});
	},
	doSaveAndPrint: function(){
		this.doSave(params);
	},
	doSave: function(){
		if(!this.payForm.getForm().isValid()){
			Alert("含有验证不通过的输入项");
			return ;
		}
		Confirm("确定要保存信息吗?", this, function(){
			var params = this.getValues()
			var comomonParams = App.getValues();
			comomonParams["busiCode"] = "1207";
			params[CoreConstant.JSON_PARAMS] = Ext.encode(comomonParams);

			var feeSns = [];
			this.realFeeStore.each(function(record){
				feeSns.push(record.get('fee_sn'));
			},this);
			params['feeSns'] = feeSns;
			console.log(feeSns);

			var mb = Show();
			//提交
			Ext.Ajax.request({
				scope: this,
				params: params,
				url: Constant.ROOT_PATH + "/core/x/Pay!savePayNew.action",
				success: function( res, ops){
					var o = Ext.decode( res.responseText );
					mb.hide();
					if(o["exception"]){
						new DebugWindow( o , "btnBusiSave").show();
					} else {
						Alert('支付成功!',function(){
								App.getApp().refreshPayInfo(parent);
								this.success();
							},this);
					}
				}
			});
		});
	},
	getValues: function(){
		var f = this.payForm.getForm();
		var all = f.getValues();
		all["pay.khr"] = all["pay.khr"] * 100;
		all["pay.usd"] = all["pay.usd"] * 100;
		all["pay.cust_id"] = App.getApp().data.custFullInfo.cust.cust_id;
		return all;
	},
	getFee: function(){
		return 0;
	},
	success:function(){
		App.getApp().menu.bigWindow.show({ text: '发票打印',  attrs: {busiCode:'1068',
					url: 'pages/business/pay/Print.jsp?type=through'}} ,{width: 710, height: 460});
	}
});

Ext.onReady(function(){
	var pay = new PayPanel();
	TemplateFactory.gViewport(pay);
});<|endoftext|>


<commit_before>'use strict'
module.exports = function (doc, req) {
  var r
  req.form.creator = req.userCtx.name
  req.form.createdAt = new Date().toISOString()
  req.form.ponderation = parseFloat(req.form.ponderation)
  req.form.descriptif = req.form.descriptif.trim()
  req.form.theme = req.form.theme.trim()

  if (doc) {
    req.form.updatedAt = new Date().toISOString()
    for (r in req.form) { doc[r] = req.form[r] }
    return [doc, JSON.stringify(doc, null, ' ')]
  }

  req.form._id = req.uuid
  return [req.form, JSON.stringify(req.form, null, ' ')]
}
<commit_msg>bugfix: only set createdAt on creation.<commit_after>'use strict'
module.exports = function (doc, req) {
  var r
  req.form.creator = req.userCtx.name
  req.form.ponderation = parseFloat(req.form.ponderation)
  req.form.descriptif = req.form.descriptif.trim()
  req.form.theme = req.form.theme.trim()

  if (doc) {
    req.form.updatedAt = new Date().toISOString()
    for (r in req.form) { doc[r] = req.form[r] }
    return [doc, JSON.stringify(doc, null, ' ')]
  }
  req.form.createdAt = new Date().toISOString()
  req.form._id = req.uuid
  return [req.form, JSON.stringify(req.form, null, ' ')]
}
<|endoftext|>


<commit_before>function onAuthCallback() {

    var code = codeInfo["code"]

    var codeInfo = getCodeFromUrl();
    if (!codeInfo) {
        alert("failed to receive auth code (the token to get the token)");
        return
    }

    var code = codeInfo["code"]
    jQuery.get("https://lively-kernel.org/lively4-auth/github_accesstoken?code=" + code,
               function(data, status, xhr) {
                   var authInfo = parseAuthInfoFromUrl(data)
                   window.opener.githubAuth.onAuthenticated(window.uuid, authInfo);
                   window.close()
               })

}

function getCodeFromUrl() {
  if (window.location.search) {
    var authResponse = window.location.search.substring(1);
    var authInfo = JSON.parse(
      '{"' + authResponse.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
      function(key, value) { return key === "" ? value : decodeURIComponent(value); });
    return authInfo;
  }
}

function getAuthInfoFromUrl() {
  if (window.location.hash) {
    var authResponse = window.location.hash.substring(1);
    var authInfo = JSON.parse(
      '{"' + authResponse.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
      function(key, value) { return key === "" ? value : decodeURIComponent(value); });
    return authInfo;
  }
}
<commit_msg>draft ace editor<commit_after>function onAuthCallback() {

    var code = codeInfo["code"]

    var codeInfo = getCodeFromUrl();
    if (!codeInfo) {
        alert("failed to receive auth code (the token to get the token)");
        return
    }

    var code = codeInfo["code"]
    alert("code: " + code)
    jQuery.get("https://lively-kernel.org/lively4-auth/github_accesstoken?code=" + code,
              function(data, status, xhr) {
                var authInfo = parseAuthInfoFromUrl(data)
                window.opener.githubAuth.onAuthenticated(window.uuid, authInfo);
                window.close()
              },
              ).fail(function(err) {
                alert("Getting the key from Github failed: " + err)
              })

}

function getCodeFromUrl() {
  if (window.location.search) {
    var authResponse = window.location.search.substring(1);
    var authInfo = JSON.parse(
      '{"' + authResponse.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
      function(key, value) { return key === "" ? value : decodeURIComponent(value); });
    return authInfo;
  }
}

function getAuthInfoFromUrl() {
  if (window.location.hash) {
    var authResponse = window.location.hash.substring(1);
    var authInfo = JSON.parse(
      '{"' + authResponse.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
      function(key, value) { return key === "" ? value : decodeURIComponent(value); });
    return authInfo;
  }
}
<|endoftext|>


<commit_before><commit_msg>Update spect.js<commit_after><|endoftext|>


<commit_before>/**
 * The InputManager handles DOM events for use in games.
 * @name InputManager
 * @constructor InputManager
 */

define([
  './GameAction',
  './MouseAction',
  './TouchAction',
  './utils/insideCanvas',
  'dcl',
  'dcl/bases/Mixer',
  'dcl/mixins/Cleanup',
  'dojo/has',
  'dojo/on',
  'lodash',
  'hammer',
  'dojo/domReady!'
], function(GameAction, MouseAction, TouchAction, insideCanvas, dcl, Mixer, Cleanup, has, on, _, hammer){

  'use strict';

  function position(node){
    var boundingRect = node.getBoundingClientRect();
    return {
      x: boundingRect.left,
      y: boundingRect.top
    };
  }

  function getComputedStyle(node){
    return window.getComputedStyle(node, null) || {};
  }

  function toPixel(value){
    return parseFloat(value) || 0;
  }

  function getMarginExtents(node){
    var style = getComputedStyle(node);
    var l = toPixel(style.marginLeft);
    var t = toPixel(style.marginTop);
    var r = toPixel(style.marginRight);
    var b = toPixel(style.marginBottom);
    return {
      w: l + r,
      h: t + b
    };
  }

  return dcl([Mixer, Cleanup], {
    /**
     * Object of keyActions being listened for
     * @type {Array}
     * @memberOf InputManager#
     * @default
     */
    keyActions: null,
    /**
     * The MouseAction to keep track of the mouse's state
     * @type {MouseAction}
     * @memberOf InputManager#
     * @default
     */
    mouseAction: null,
    /**
     * The TouchAction to keep track of touch events
     * @type {TouchAction}
     * @memberOf InputManager#
     * @default
     */
    touchAction: null,
    /**
     * The HTML5 canvas on which to listen for events
     * @type {Canvas}
     * @memberOf InputManager#
     * @default
     */
    canvas: null,
    /**
     * Whether or not to listen for mouse events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     * @deprecated Mouse is always handled, use emulateMouse to specify how to handle it
     */
    handleMouse: true,
    /**
     * Whether or not to listen for touch events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     * @deprecated Touch is always handled, use emulateMouse to specify how to handle it
     */
    handleTouch: true,
    /**
     * Whether or not to listen for keyboard events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     */
    handleKeys: true,
    /**
     * The DOM element that contains the game's canvas
     * @type {Element}
     * @memberOf InputManager#
     * @default
     */
    gameArea: null,
    /**
     * The percentage (0 to 1.0) of the height and width the canvas should use to fill in its container DOM element
     * @type {Number}
     * @memberOf InputManager#
     * @default
     */
    canvasPercentage: null,
    /**
     * Emulate mouse events when using touch
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     */
    emulateMouse: true,

    /**
     * Instance of Hammer.js - You can pass in a Hammer() constructor with options to customize your Hammer instance
     * @type {Object}
     * @memberOf InputManager#
     * @default Hammer instance, bound to document, with prevent_default: true, drag_max_touches: 0, and hold: false
     */
    hammer: null,

    /**
     * Allows you to bind other Hammer.js events (such as Swipe or Doubletap);
     * Warning: Only set flags or variables in this handler, otherwise your game might become slow
     * @function
     * @memberOf InputManager#
     * @param  {String} gesture The gesture to bind
     * @param  {Function} handler Event handler callback
     * @return {Object} Object containing the remove function for removing the event.
     */
    on: function(gesture, handler){
      var hammer = this.hammer;
      var removeCleanup = this.removeCleanup;

      hammer.on(gesture, handler);
      var cleanup = this.pushCleanup([gesture, handler], function(args){
        hammer.off.apply(hammer, args);
      });

      return {
        remove: function(){
          removeCleanup(cleanup);
          cleanup();
        }
      };
    },

    constructor: function(){
      _.bindAll(this);

      if(!this.hammer){
        this.hammer = hammer(document, {
          prevent_default: true,
          drag_max_touches: 0,
          // Hold uses setTimeout which is very bad for performance
          // TODO: Do we want to allow this to be overridden?
          hold: false
        });
      }

      if(!this.keyActions){
        this.keyActions = {};
      }

      function cleanup(handler){
        handler.remove();
      }

      if(this.handleKeys){
        this.pushCleanup(on(document, 'keydown', this.keydown), cleanup);
        this.pushCleanup(on(document, 'keyup', this.keyup), cleanup);
      }

      if(this.emulateMouse){
        this.on('touch', this.mousedown);
        this.on('drag', this.mousemove);
        this.on('release', this.mouseup);
        if(!this.mouseAction){
          this.mouseAction = new MouseAction();
        }
      } else {
        this.on('touch', this.touchstart);
        this.on('drag', this.touchmove);
        this.on('release', this.touchend);
        if(!this.touchAction){
          this.touchAction = new TouchAction();
        }
      }

      if(this.gameArea && this.canvasPercentage){
        this.pushCleanup(on(window, 'resize', this.resize), cleanup);
        this.pushCleanup(on(window, 'orientationchange', this.resize), cleanup);
      }
    },

    /**
     * Determine whether a point is within the InputManager's canvas
     * @function
     * @memberOf InputManager#
     * @param  {Point} point Point to test
     * @return {Boolean} Whether or not the point is inside this InputManager's canvas
     */
    insideCanvas: function(point){
      return insideCanvas(point, this.canvas);
    },

    /**
     * Maps a GameAction to a specific key. The key codes are defined in dojo.keys.
     * If the key already has a GameAction mapped to it, the new GameAction overwrites it.
     * @function
     * @memberOf InputManager#
     * @param {GameAction} gameAction the GameAction to map
     * @param {Object} keyCode dojo.keys key code, or character
     */
    mapToKey: function(gameAction, keyCode){
      this.keyActions[keyCode] = gameAction;
    },

    /**
     * Adds a GameAction to a key
     * @function
     * @memberOf InputManager#
     * @param {Object} keyCode Key character or dojo/keys key code
     * @param {Boolean=} initialPressOnly Do only one fire of the action per keypress
     * @return {GameAction} GameAction that is mapped to keyCode
     */
    addKeyAction: function(keyCode, initialPressOnly){
      var ga = new GameAction();
      if(initialPressOnly){
        ga.behavior = ga.statics.DETECT_INITAL_PRESS_ONLY;
      }
      this.mapToKey(ga,keyCode);

      return ga;
    },

    /**
     * Called upon mouseup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseUp: function(e) {
      this.mouseup(e);
    },

    /**
     * Called upon mouseup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mouseup: function(e){
      this.mouseAction.release(this.normalizePoint(e.gesture.touches[0]));
    },

    /**
     * Called upon mousedown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseDown: function(e){
      this.mousedown(e);
    },

    /**
     * Called upon mousedown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mousedown: function(e){
      // Ensure mouse has been released
      this.mouseAction.release(null);
      var currentPoint = this.normalizePoint(e.gesture.touches[0]);
      this.mouseAction.insideCanvas = this.insideCanvas(currentPoint);
      this.mouseAction.press(currentPoint);
    },

    /**
     * Called upon mousemove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseMove: function(e){
      this.mousemove(e);
    },

    /**
     * Called upon mousemove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mousemove: function(e){
      var evt = e.gesture ? e.gesture.touches[0] : e;
      this.mouseAction.position = this.normalizePoint(evt);
    },

    /**
     * Called upon touchstart event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchStart: function(e){
      this.touchstart(e);
    },

    /**
     * Called upon touchstart event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchstart: function(e){
      // Ensure touch has been released
      this.touchAction.release(null);
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.insideCanvas = _.some(currentPoints, this.insideCanvas);
      this.touchAction.press(currentPoints);
    },

    /**
     * Called upon touchend event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchEnd: function(e){
      this.touchend(e);
    },

    /**
     * Called upon touchend event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchend: function(e){
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.release(currentPoints);
    },

    /**
     * Called upon touchmove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchMove: function(e){
      this.touchmove(e);
    },

    /**
     * Called upon touchmove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchmove: function(e){
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.positions = currentPoints;
      if(this.touchAction.startPositions){
        e.preventDefault();
      }
    },

    /**
     * Retrieves the GameAction associated with the keyCode on the event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @return {GameAction|null} The GameAction associated with the keyCode else null
     */
    getKeyAction: function(e) {
      if (this.keyActions) {
        return this.keyActions[e.keyCode] || this.keyActions[String.fromCharCode(e.keyCode)];
      } else {
        return null;
      }
    },

    /**
     * Called upon keypress event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use keydown instead - same syntax as normal event handling
     */
    keyPressed: function(e) {
      this.keydown(e);
    },

    /**
     * Called upon keydown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    keyDown: function(e){
      this.keydown(e);
    },

    /**
     * Called upon keydown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    keydown: function(e) {
      var gameAction = this.getKeyAction(e);
      if (gameAction && !gameAction.isPressed()) {
        gameAction.press();
      }
    },

    /**
     * Called upon keyup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use keyup instead - same syntax as normal event handling
     */
    keyReleased: function(e){
      this.keyup(e);
    },

    /**
     * Called upon keyup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    keyup: function(e) {
      var gameAction = this.getKeyAction(e);
      if (gameAction) {
        gameAction.release();
      }
    },

    /**
     * Used to get a normalized point out of an Event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} evt Event object
     * @return {Point} Normalized point
     * @deprecated Deprecated in favor of normalizePoint function (Same functionality, different name)
     */
    getMouseLoc: function(evt){
      return this.normalizePoint(evt);
    },

    /**
     * Used to get a normalized point out of an Event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} evt Event object
     * @return {Point} Normalized point
     */
    normalizePoint: function(evt){
      var coordsM = position(this.canvas);
      if(this.zoomRatio){
        return {
          x: Math.round((evt.clientX - coordsM.x) / this.zoomRatio),
          y: Math.round((evt.clientY - coordsM.y) / this.zoomRatio)
        };
      }else{
        return {
          x: Math.round(evt.clientX - coordsM.x),
          y: Math.round(evt.clientY - coordsM.y)
        };
      }
    },

    /**
     * Used to resize the canvas
     * @function
     * @memberOf InputManager#
     */
    resize: function(){
      if(this.gameArea && this.canvasPercentage && this.canvas){
        var canvasWidth = this.canvas.width;
        var canvasHeight = this.canvas.height;

        var bodyMargins = getMarginExtents(document.body);

        var newWidth = window.innerWidth - bodyMargins.w;
        var newHeight = window.innerHeight - bodyMargins.h;

        var widthToHeight = canvasWidth / canvasHeight;
        var newWidthToHeight = newWidth / newHeight;

        var newWidthStyle = '';
        var newHeightStyle = '';
        if (newWidthToHeight > widthToHeight) {
          newWidth = newHeight * widthToHeight;
          newWidthStyle = newWidth + 'px';
          newHeightStyle = newHeight + 'px';
        } else {
          newWidthStyle = newWidth + 'px';
          newHeightStyle = Math.round(newWidth / widthToHeight) + 'px';
        }

        this.zoomRatio = newWidth / canvasWidth * this.canvasPercentage;

        this.gameArea.style.width = newWidthStyle;
        this.gameArea.style.height = newHeightStyle;

        var canvasPercentageStyle = Math.floor(this.canvasPercentage * 100) + '%';
        this.canvas.style.width = canvasPercentageStyle;
        this.canvas.style.height = canvasPercentageStyle;
        this.canvas.style.display = 'block';
        this.canvas.style.marginLeft = 'auto';
        this.canvas.style.marginRight = 'auto';
      }
    }
  });

});
<commit_msg>turn off prevent_default in hammer<commit_after>/**
 * The InputManager handles DOM events for use in games.
 * @name InputManager
 * @constructor InputManager
 */

define([
  './GameAction',
  './MouseAction',
  './TouchAction',
  './utils/insideCanvas',
  'dcl',
  'dcl/bases/Mixer',
  'dcl/mixins/Cleanup',
  'dojo/has',
  'dojo/on',
  'lodash',
  'hammer',
  'dojo/domReady!'
], function(GameAction, MouseAction, TouchAction, insideCanvas, dcl, Mixer, Cleanup, has, on, _, hammer){

  'use strict';

  function position(node){
    var boundingRect = node.getBoundingClientRect();
    return {
      x: boundingRect.left,
      y: boundingRect.top
    };
  }

  function getComputedStyle(node){
    return window.getComputedStyle(node, null) || {};
  }

  function toPixel(value){
    return parseFloat(value) || 0;
  }

  function getMarginExtents(node){
    var style = getComputedStyle(node);
    var l = toPixel(style.marginLeft);
    var t = toPixel(style.marginTop);
    var r = toPixel(style.marginRight);
    var b = toPixel(style.marginBottom);
    return {
      w: l + r,
      h: t + b
    };
  }

  return dcl([Mixer, Cleanup], {
    /**
     * Object of keyActions being listened for
     * @type {Array}
     * @memberOf InputManager#
     * @default
     */
    keyActions: null,
    /**
     * The MouseAction to keep track of the mouse's state
     * @type {MouseAction}
     * @memberOf InputManager#
     * @default
     */
    mouseAction: null,
    /**
     * The TouchAction to keep track of touch events
     * @type {TouchAction}
     * @memberOf InputManager#
     * @default
     */
    touchAction: null,
    /**
     * The HTML5 canvas on which to listen for events
     * @type {Canvas}
     * @memberOf InputManager#
     * @default
     */
    canvas: null,
    /**
     * Whether or not to listen for mouse events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     * @deprecated Mouse is always handled, use emulateMouse to specify how to handle it
     */
    handleMouse: true,
    /**
     * Whether or not to listen for touch events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     * @deprecated Touch is always handled, use emulateMouse to specify how to handle it
     */
    handleTouch: true,
    /**
     * Whether or not to listen for keyboard events
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     */
    handleKeys: true,
    /**
     * The DOM element that contains the game's canvas
     * @type {Element}
     * @memberOf InputManager#
     * @default
     */
    gameArea: null,
    /**
     * The percentage (0 to 1.0) of the height and width the canvas should use to fill in its container DOM element
     * @type {Number}
     * @memberOf InputManager#
     * @default
     */
    canvasPercentage: null,
    /**
     * Emulate mouse events when using touch
     * @type {Boolean}
     * @memberOf InputManager#
     * @default
     */
    emulateMouse: true,

    /**
     * Instance of Hammer.js - You can pass in a Hammer() constructor with options to customize your Hammer instance
     * @type {Object}
     * @memberOf InputManager#
     * @default Hammer instance, bound to document, with prevent_default: true, drag_max_touches: 0, and hold: false
     */
    hammer: null,

    /**
     * Allows you to bind other Hammer.js events (such as Swipe or Doubletap);
     * Warning: Only set flags or variables in this handler, otherwise your game might become slow
     * @function
     * @memberOf InputManager#
     * @param  {String} gesture The gesture to bind
     * @param  {Function} handler Event handler callback
     * @return {Object} Object containing the remove function for removing the event.
     */
    on: function(gesture, handler){
      var hammer = this.hammer;
      var removeCleanup = this.removeCleanup;

      hammer.on(gesture, handler);
      var cleanup = this.pushCleanup([gesture, handler], function(args){
        hammer.off.apply(hammer, args);
      });

      return {
        remove: function(){
          removeCleanup(cleanup);
          cleanup();
        }
      };
    },

    constructor: function(){
      _.bindAll(this);

      if(!this.hammer){
        this.hammer = hammer(document, {
          // prevent_default: false,
          drag_max_touches: 0,
          // Hold uses setTimeout which is very bad for performance
          // TODO: Do we want to allow this to be overridden?
          hold: false
        });
      }

      if(!this.keyActions){
        this.keyActions = {};
      }

      function cleanup(handler){
        handler.remove();
      }

      if(this.handleKeys){
        this.pushCleanup(on(document, 'keydown', this.keydown), cleanup);
        this.pushCleanup(on(document, 'keyup', this.keyup), cleanup);
      }

      if(this.emulateMouse){
        this.on('touch', this.mousedown);
        this.on('drag', this.mousemove);
        this.on('release', this.mouseup);
        if(!this.mouseAction){
          this.mouseAction = new MouseAction();
        }
      } else {
        this.on('touch', this.touchstart);
        this.on('drag', this.touchmove);
        this.on('release', this.touchend);
        if(!this.touchAction){
          this.touchAction = new TouchAction();
        }
      }

      if(this.gameArea && this.canvasPercentage){
        this.pushCleanup(on(window, 'resize', this.resize), cleanup);
        this.pushCleanup(on(window, 'orientationchange', this.resize), cleanup);
      }
    },

    /**
     * Determine whether a point is within the InputManager's canvas
     * @function
     * @memberOf InputManager#
     * @param  {Point} point Point to test
     * @return {Boolean} Whether or not the point is inside this InputManager's canvas
     */
    insideCanvas: function(point){
      return insideCanvas(point, this.canvas);
    },

    /**
     * Maps a GameAction to a specific key. The key codes are defined in dojo.keys.
     * If the key already has a GameAction mapped to it, the new GameAction overwrites it.
     * @function
     * @memberOf InputManager#
     * @param {GameAction} gameAction the GameAction to map
     * @param {Object} keyCode dojo.keys key code, or character
     */
    mapToKey: function(gameAction, keyCode){
      this.keyActions[keyCode] = gameAction;
    },

    /**
     * Adds a GameAction to a key
     * @function
     * @memberOf InputManager#
     * @param {Object} keyCode Key character or dojo/keys key code
     * @param {Boolean=} initialPressOnly Do only one fire of the action per keypress
     * @return {GameAction} GameAction that is mapped to keyCode
     */
    addKeyAction: function(keyCode, initialPressOnly){
      var ga = new GameAction();
      if(initialPressOnly){
        ga.behavior = ga.statics.DETECT_INITAL_PRESS_ONLY;
      }
      this.mapToKey(ga,keyCode);

      return ga;
    },

    /**
     * Called upon mouseup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseUp: function(e) {
      this.mouseup(e);
    },

    /**
     * Called upon mouseup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mouseup: function(e){
      this.mouseAction.release(this.normalizePoint(e.gesture.touches[0]));
    },

    /**
     * Called upon mousedown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseDown: function(e){
      this.mousedown(e);
    },

    /**
     * Called upon mousedown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mousedown: function(e){
      // Ensure mouse has been released
      this.mouseAction.release(null);
      var currentPoint = this.normalizePoint(e.gesture.touches[0]);
      this.mouseAction.insideCanvas = this.insideCanvas(currentPoint);
      this.mouseAction.press(currentPoint);
    },

    /**
     * Called upon mousemove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    mouseMove: function(e){
      this.mousemove(e);
    },

    /**
     * Called upon mousemove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    mousemove: function(e){
      var evt = e.gesture ? e.gesture.touches[0] : e;
      this.mouseAction.position = this.normalizePoint(evt);
    },

    /**
     * Called upon touchstart event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchStart: function(e){
      this.touchstart(e);
    },

    /**
     * Called upon touchstart event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchstart: function(e){
      // Ensure touch has been released
      this.touchAction.release(null);
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.insideCanvas = _.some(currentPoints, this.insideCanvas);
      this.touchAction.press(currentPoints);
    },

    /**
     * Called upon touchend event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchEnd: function(e){
      this.touchend(e);
    },

    /**
     * Called upon touchend event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchend: function(e){
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.release(currentPoints);
    },

    /**
     * Called upon touchmove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    touchMove: function(e){
      this.touchmove(e);
    },

    /**
     * Called upon touchmove event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    touchmove: function(e){
      var currentPoints = _.map(e.gesture.touches, this.normalizePoint);
      this.touchAction.positions = currentPoints;
      if(this.touchAction.startPositions){
        e.preventDefault();
      }
    },

    /**
     * Retrieves the GameAction associated with the keyCode on the event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @return {GameAction|null} The GameAction associated with the keyCode else null
     */
    getKeyAction: function(e) {
      if (this.keyActions) {
        return this.keyActions[e.keyCode] || this.keyActions[String.fromCharCode(e.keyCode)];
      } else {
        return null;
      }
    },

    /**
     * Called upon keypress event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use keydown instead - same syntax as normal event handling
     */
    keyPressed: function(e) {
      this.keydown(e);
    },

    /**
     * Called upon keydown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use the lowercase name instead - same syntax as normal event handling
     */
    keyDown: function(e){
      this.keydown(e);
    },

    /**
     * Called upon keydown event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    keydown: function(e) {
      var gameAction = this.getKeyAction(e);
      if (gameAction && !gameAction.isPressed()) {
        gameAction.press();
      }
    },

    /**
     * Called upon keyup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     * @deprecated Use keyup instead - same syntax as normal event handling
     */
    keyReleased: function(e){
      this.keyup(e);
    },

    /**
     * Called upon keyup event
     * @function
     * @memberOf InputManager#
     * @param  {Event} e Event object
     */
    keyup: function(e) {
      var gameAction = this.getKeyAction(e);
      if (gameAction) {
        gameAction.release();
      }
    },

    /**
     * Used to get a normalized point out of an Event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} evt Event object
     * @return {Point} Normalized point
     * @deprecated Deprecated in favor of normalizePoint function (Same functionality, different name)
     */
    getMouseLoc: function(evt){
      return this.normalizePoint(evt);
    },

    /**
     * Used to get a normalized point out of an Event object
     * @function
     * @memberOf InputManager#
     * @param  {Event} evt Event object
     * @return {Point} Normalized point
     */
    normalizePoint: function(evt){
      var coordsM = position(this.canvas);
      if(this.zoomRatio){
        return {
          x: Math.round((evt.clientX - coordsM.x) / this.zoomRatio),
          y: Math.round((evt.clientY - coordsM.y) / this.zoomRatio)
        };
      }else{
        return {
          x: Math.round(evt.clientX - coordsM.x),
          y: Math.round(evt.clientY - coordsM.y)
        };
      }
    },

    /**
     * Used to resize the canvas
     * @function
     * @memberOf InputManager#
     */
    resize: function(){
      if(this.gameArea && this.canvasPercentage && this.canvas){
        var canvasWidth = this.canvas.width;
        var canvasHeight = this.canvas.height;

        var bodyMargins = getMarginExtents(document.body);

        var newWidth = window.innerWidth - bodyMargins.w;
        var newHeight = window.innerHeight - bodyMargins.h;

        var widthToHeight = canvasWidth / canvasHeight;
        var newWidthToHeight = newWidth / newHeight;

        var newWidthStyle = '';
        var newHeightStyle = '';
        if (newWidthToHeight > widthToHeight) {
          newWidth = newHeight * widthToHeight;
          newWidthStyle = newWidth + 'px';
          newHeightStyle = newHeight + 'px';
        } else {
          newWidthStyle = newWidth + 'px';
          newHeightStyle = Math.round(newWidth / widthToHeight) + 'px';
        }

        this.zoomRatio = newWidth / canvasWidth * this.canvasPercentage;

        this.gameArea.style.width = newWidthStyle;
        this.gameArea.style.height = newHeightStyle;

        var canvasPercentageStyle = Math.floor(this.canvasPercentage * 100) + '%';
        this.canvas.style.width = canvasPercentageStyle;
        this.canvas.style.height = canvasPercentageStyle;
        this.canvas.style.display = 'block';
        this.canvas.style.marginLeft = 'auto';
        this.canvas.style.marginRight = 'auto';
      }
    }
  });

});
<|endoftext|>


<commit_before> 'use strict';
  var _ = require('lodash');
  moj.Modules.FormErrors = {
    init: function() {
      _.bindAll(this, 'postToFormErrors', 'onAjaxSuccess', 'onAjaxError');
      this.bindEvents();
      this.loadTemplates();
    },

    bindEvents: function() {
      $('form')
        .on('submit', this.postToFormErrors)
        // Focus back on summary if field-error is focused and escape key is pressed
        .on('keyup', function(e) {
          var $target = $(e.target);
          if(e.keyCode === 27 && ($target.is('.govuk-form-group--error') || $target.parent().is('.govuk-form-group--error'))) {
            $target.closest('form').find('> .alert').focus();
          }
        })
        .on('blur', '.form-group', function(e) {
          $(e.target).removeAttr('tabindex');
        });

      $('[type=submit]').on('click', function(e) {
        var $target = $(e.target);
        $target.closest('form').attr('submit-name', $target.attr('name'));
      });

      // Focus on field with error
      $('#content').on('click', '.error-summary a', function(e) {
        e.preventDefault();
        var targetId = e.target.href.replace(/.*#/, '#');
        if(targetId.length < 2) {
          return;
        }
        var $target = $(targetId);

        $('html, body').animate({
          scrollTop: $target.offset().top - 20
        }, 300, function() {
          $target.attr('tabindex', -1).focus();
        });
      });
    },

    postToFormErrors: function(e) {
      this.$form = $(e.target);

      // Return if button has a name, which is attached as form attribute on click
      // (assuming secondary buttons)
      if(this.$form.attr('submit-name') ||
         this.$form.attr('method') && this.$form.attr('method').toLowerCase() === 'get') {
        return;
      }

      if (this.$form.length) {
        e.preventDefault();
        e.stopPropagation();
        $.ajax({
          type: 'POST',
          url: '',
          contentType: 'application/x-www-form-urlencoded',
          data: this.$form.serialize()
        })
        .done(this.onAjaxSuccess)
        .fail(this.onAjaxError);
      }
    },

    onAjaxSuccess: function(data) {
      if (data.redirect) {
        window.location.href = data.redirect;
      }
      if (data.field_errors) {
        this.loadErrors(data.field_errors);
        var errorBanner = $('.govuk-error-summary:visible:first');

        if(!errorBanner.length) {
          return;
        }

        $('html, body').animate({
          scrollTop: errorBanner.offset().top - 20
        }, 300, function() {
          errorBanner.attr({'tabindex': -1}).focus();
        });
      }
      if (data.non_field_errors.length) {
        $('#non-field-error-ajax .alert-message').text(data.non_field_errors[0]);
        $('#non-field-error-ajax').show();
      }
      else {
        $('#non-field-error-ajax').hide();
      }
    },

    onAjaxError: function() {
      this.$form.off('submit');
      this.$form.submit();
    },

    formatErrors: function(errors) {
      var errorFields = {};

      (function fieldName (errorsObj, prefix) {
        prefix = (typeof prefix === 'undefined') ? '' : prefix + '-';
        for (var key in errorsObj) {
          var field = prefix + key;
          if ($.isArray(errorsObj[key])) {
            errorFields[field] = errorsObj[key];
          } else {
            fieldName(errorsObj[key], field);
          }
        }
      })(errors);

      return errorFields;
    },

    createErrorSummary: function(unattachedErrors) {
      var errorSummary = [];

      // Loop through errors on the page to retain the fields order
      $('.govuk-form-group--error, .govuk-form-group--error>fieldset').map(function() {
        var $this = $(this);

        if(!this.id || $this.hasClass('s-hidden') || $this.parent().hasClass('s-hidden')) {
          return;
        }
        var name = this.id.replace(/^field-/, '');

        var labelField = $this.find('#field-label-' + name);

        var errorText = $this.find('#error-' + name + " .cla-error-message").text();

        $this.find(' .govuk-input')
          .not('.govuk-form-group--error .govuk-radios__conditional .govuk-input')
          .addClass("govuk-input--error");
        $this.find(' .govuk-select')
          .not('.govuk-form-group--error .govuk-radios__conditional .govuk-select')
          .addClass("govuk-select--error");

        if (labelField.parents(".cla-currency-by-frequency").length) {
          labelField = labelField.parents(".cla-currency-by-frequency").children("legend");

          $this.find(' .govuk-input').filter(function () {
            return ($(this).val() && Number($(this).val()) > 0)
          })
          .removeClass("govuk-input--error");

          $this.find(' .govuk-select').filter(function () {
            return ($(this).val())
          })
          .removeClass("govuk-select--error")
        }

        if (errorText) {
          var labelText = errorText;
        } else {
          var labelText = labelField.text().replace(/if yes, /i,"").replace(/os ydych, /i,"").replace(/os oes, /i,"").trim();
          //above lines are stripping the "if yes" (and Welsh variants) from the error summary.

          labelText = labelText.charAt(0).toUpperCase() + labelText.substr(1);
          //Ensures the first letter is uppercase.
        }

        errorSummary.push({
          label: labelText,
          name: name,
          errors: $this.find('> .govuk-error-message > .cla-error-message').map(function() {
            return $(this).text();
          })
        });
      });

      _.each(unattachedErrors, function(error) {
        errorSummary.push({
          errors: [error]
        });
      });

      return errorSummary;
    },

    loadErrors: function(errors) {
      var errorFields = this.formatErrors(errors);
      var self = this;
      var unattachedErrors = [];

      this.clearErrors();

      function insertError($afterElement, errors, fieldName) {
        $afterElement.after(self.fieldError({
          errors: errors,
          fieldName: fieldName
        }));
      }

      function addSimpleErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }

        $('#field-' + fieldName)
          .attr({
            'aria-invalid': true,
            'aria-describedby': 'error-' + fieldName
          })
          .closest('.govuk-form-group').addClass('govuk-form-group--error');

        var label = $('#field-label-' + fieldName);

        if (label.parents(".cla-currency-by-frequency").length) {
          label = label.parents(".cla-currency-by-frequency").children("legend");
        }

        if(!label.length) {
          unattachedErrors = _.extend(unattachedErrors, errors);
        } else if(label.parent().children('.govuk-hint').length) {
          insertError(label.parent().children('.govuk-hint'), errors, fieldName);
        } else if(label.is('legend')) {
          insertError(label, errors, fieldName);
        } else {
          insertError(label.closest('.form-group-label'), errors, fieldName);
        }
      }

      function addSubformErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }
        _.each(errors, function(subformErrors) {
          addErrors(subformErrors[1], fieldName + '-' + subformErrors[0]);
        });
      }

      function addRepeatedFieldErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }
        // Multiple forms (e.g. properties)
        _.each(errors, function(errors) {
          _.each(errors._errors, function(subformErrors, subformFieldName) {
            addErrors(subformErrors, fieldName + '-' + errors._index + '-' + subformFieldName);
          });
        });
      }

      function addErrors(errors, fieldName) {
        addSimpleErrors(_.filter(errors, _.isString), fieldName);
        addSubformErrors(_.filter(errors, _.isArray), fieldName);
        addRepeatedFieldErrors(_.filter(errors, function(error) {
          return _.isObject(error) && !_.isArray(error);
        }), fieldName);
      }

      _.each(errorFields, addErrors);

      if(this.$form.data('error-banner') !== false) {
        this.$form.closest('main').prepend(this.mainFormError({ errors: this.createErrorSummary(unattachedErrors)}));
      }

      // Report to GA about form errors
      var errorFieldNames = _.keys(errorFields);
      if(!window.ga) {
        return;
      }
      window.ga('send', 'event', 'form-errors',
        window.location.pathname,
        errorFieldNames.join('|'),
        errorFieldNames.length
      );
    },

    loadTemplates: function() {
      this.mainFormError = _.template($('#mainFormError').html());
      this.fieldError = _.template($('#fieldError').html());
    },

    clearErrors: function() {
      $('.govuk-error-message').remove();
      $('.form-row.field-error').remove();
      $('form>.alert.alert-error').remove();
      $('.govuk-error-summary').remove();
      $('.form-error')
        .removeClass('form-error')
        .removeAttr('aria-invalid');
      $('.govuk-form-group--error')
        .removeClass('govuk-form-group--error')
        .removeAttr('aria-invalid');
      $(".govuk-input--error")
        .removeClass("govuk-input--error");
      $(".govuk-select--error")
        .removeClass("govuk-select--error");
    }
  };
<commit_msg>Make form ajax use form action as its destination<commit_after> 'use strict';
  var _ = require('lodash');
  moj.Modules.FormErrors = {
    init: function() {
      _.bindAll(this, 'postToFormErrors', 'onAjaxSuccess', 'onAjaxError');
      this.bindEvents();
      this.loadTemplates();
    },

    bindEvents: function() {
      $('form')
        .on('submit', this.postToFormErrors)
        // Focus back on summary if field-error is focused and escape key is pressed
        .on('keyup', function(e) {
          var $target = $(e.target);
          if(e.keyCode === 27 && ($target.is('.govuk-form-group--error') || $target.parent().is('.govuk-form-group--error'))) {
            $target.closest('form').find('> .alert').focus();
          }
        })
        .on('blur', '.form-group', function(e) {
          $(e.target).removeAttr('tabindex');
        });

      $('[type=submit]').on('click', function(e) {
        var $target = $(e.target);
        $target.closest('form').attr('submit-name', $target.attr('name'));
      });

      // Focus on field with error
      $('#content').on('click', '.error-summary a', function(e) {
        e.preventDefault();
        var targetId = e.target.href.replace(/.*#/, '#');
        if(targetId.length < 2) {
          return;
        }
        var $target = $(targetId);

        $('html, body').animate({
          scrollTop: $target.offset().top - 20
        }, 300, function() {
          $target.attr('tabindex', -1).focus();
        });
      });
    },

    postToFormErrors: function(e) {
      this.$form = $(e.target);

      // Return if button has a name, which is attached as form attribute on click
      // (assuming secondary buttons)
      if(this.$form.attr('submit-name') ||
         this.$form.attr('method') && this.$form.attr('method').toLowerCase() === 'get') {
        return;
      }

      if (this.$form.length) {
        e.preventDefault();
        e.stopPropagation();
        $.ajax({
          type: 'POST',
          url: this.$form.attr('action'),
          contentType: 'application/x-www-form-urlencoded',
          data: this.$form.serialize()
        })
        .done(this.onAjaxSuccess)
        .fail(this.onAjaxError);
      }
    },

    onAjaxSuccess: function(data) {
      if (data.redirect) {
        window.location.href = data.redirect;
      }
      if (data.field_errors) {
        this.loadErrors(data.field_errors);
        var errorBanner = $('.govuk-error-summary:visible:first');

        if(!errorBanner.length) {
          return;
        }

        $('html, body').animate({
          scrollTop: errorBanner.offset().top - 20
        }, 300, function() {
          errorBanner.attr({'tabindex': -1}).focus();
        });
      }
      if (data.non_field_errors.length) {
        $('#non-field-error-ajax .alert-message').text(data.non_field_errors[0]);
        $('#non-field-error-ajax').show();
      }
      else {
        $('#non-field-error-ajax').hide();
      }
    },

    onAjaxError: function() {
      this.$form.off('submit');
      this.$form.submit();
    },

    formatErrors: function(errors) {
      var errorFields = {};

      (function fieldName (errorsObj, prefix) {
        prefix = (typeof prefix === 'undefined') ? '' : prefix + '-';
        for (var key in errorsObj) {
          var field = prefix + key;
          if ($.isArray(errorsObj[key])) {
            errorFields[field] = errorsObj[key];
          } else {
            fieldName(errorsObj[key], field);
          }
        }
      })(errors);

      return errorFields;
    },

    createErrorSummary: function(unattachedErrors) {
      var errorSummary = [];

      // Loop through errors on the page to retain the fields order
      $('.govuk-form-group--error, .govuk-form-group--error>fieldset').map(function() {
        var $this = $(this);

        if(!this.id || $this.hasClass('s-hidden') || $this.parent().hasClass('s-hidden')) {
          return;
        }
        var name = this.id.replace(/^field-/, '');

        var labelField = $this.find('#field-label-' + name);

        var errorText = $this.find('#error-' + name + " .cla-error-message").text();

        $this.find(' .govuk-input')
          .not('.govuk-form-group--error .govuk-radios__conditional .govuk-input')
          .addClass("govuk-input--error");
        $this.find(' .govuk-select')
          .not('.govuk-form-group--error .govuk-radios__conditional .govuk-select')
          .addClass("govuk-select--error");

        if (labelField.parents(".cla-currency-by-frequency").length) {
          labelField = labelField.parents(".cla-currency-by-frequency").children("legend");

          $this.find(' .govuk-input').filter(function () {
            return ($(this).val() && Number($(this).val()) > 0)
          })
          .removeClass("govuk-input--error");

          $this.find(' .govuk-select').filter(function () {
            return ($(this).val())
          })
          .removeClass("govuk-select--error")
        }

        if (errorText) {
          var labelText = errorText;
        } else {
          var labelText = labelField.text().replace(/if yes, /i,"").replace(/os ydych, /i,"").replace(/os oes, /i,"").trim();
          //above lines are stripping the "if yes" (and Welsh variants) from the error summary.

          labelText = labelText.charAt(0).toUpperCase() + labelText.substr(1);
          //Ensures the first letter is uppercase.
        }

        errorSummary.push({
          label: labelText,
          name: name,
          errors: $this.find('> .govuk-error-message > .cla-error-message').map(function() {
            return $(this).text();
          })
        });
      });

      _.each(unattachedErrors, function(error) {
        errorSummary.push({
          errors: [error]
        });
      });

      return errorSummary;
    },

    loadErrors: function(errors) {
      var errorFields = this.formatErrors(errors);
      var self = this;
      var unattachedErrors = [];

      this.clearErrors();

      function insertError($afterElement, errors, fieldName) {
        $afterElement.after(self.fieldError({
          errors: errors,
          fieldName: fieldName
        }));
      }

      function addSimpleErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }

        $('#field-' + fieldName)
          .attr({
            'aria-invalid': true,
            'aria-describedby': 'error-' + fieldName
          })
          .closest('.govuk-form-group').addClass('govuk-form-group--error');

        var label = $('#field-label-' + fieldName);

        if (label.parents(".cla-currency-by-frequency").length) {
          label = label.parents(".cla-currency-by-frequency").children("legend");
        }

        if(!label.length) {
          unattachedErrors = _.extend(unattachedErrors, errors);
        } else if(label.parent().children('.govuk-hint').length) {
          insertError(label.parent().children('.govuk-hint'), errors, fieldName);
        } else if(label.is('legend')) {
          insertError(label, errors, fieldName);
        } else {
          insertError(label.closest('.form-group-label'), errors, fieldName);
        }
      }

      function addSubformErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }
        _.each(errors, function(subformErrors) {
          addErrors(subformErrors[1], fieldName + '-' + subformErrors[0]);
        });
      }

      function addRepeatedFieldErrors(errors, fieldName) {
        if(!errors.length) {
          return;
        }
        // Multiple forms (e.g. properties)
        _.each(errors, function(errors) {
          _.each(errors._errors, function(subformErrors, subformFieldName) {
            addErrors(subformErrors, fieldName + '-' + errors._index + '-' + subformFieldName);
          });
        });
      }

      function addErrors(errors, fieldName) {
        addSimpleErrors(_.filter(errors, _.isString), fieldName);
        addSubformErrors(_.filter(errors, _.isArray), fieldName);
        addRepeatedFieldErrors(_.filter(errors, function(error) {
          return _.isObject(error) && !_.isArray(error);
        }), fieldName);
      }

      _.each(errorFields, addErrors);

      if(this.$form.data('error-banner') !== false) {
        this.$form.closest('main').prepend(this.mainFormError({ errors: this.createErrorSummary(unattachedErrors)}));
      }

      // Report to GA about form errors
      var errorFieldNames = _.keys(errorFields);
      if(!window.ga) {
        return;
      }
      window.ga('send', 'event', 'form-errors',
        window.location.pathname,
        errorFieldNames.join('|'),
        errorFieldNames.length
      );
    },

    loadTemplates: function() {
      this.mainFormError = _.template($('#mainFormError').html());
      this.fieldError = _.template($('#fieldError').html());
    },

    clearErrors: function() {
      $('.govuk-error-message').remove();
      $('.form-row.field-error').remove();
      $('form>.alert.alert-error').remove();
      $('.govuk-error-summary').remove();
      $('.form-error')
        .removeClass('form-error')
        .removeAttr('aria-invalid');
      $('.govuk-form-group--error')
        .removeClass('govuk-form-group--error')
        .removeAttr('aria-invalid');
      $(".govuk-input--error")
        .removeClass("govuk-input--error");
      $(".govuk-select--error")
        .removeClass("govuk-select--error");
    }
  };
<|endoftext|>


<commit_before>'use strict';

/* global isEmpty, setupPopovers, openClick:true, openWindowToggle, moveButtons,
fullClick, openFiltersToggle, buttonOpen, buttonClose */

app.controller('ResultsCtrl', ['$scope', 'tempData', 'business', '$filter', '$timeout', '$location', function ($scope, tempData, Business, $filter, $timeout, $location) {
  // So far we're using the tempData factory, but we could easily change this
  // to use the localCache factory that has more functions and capabilities
  // and then combine it with our business factory since that was their original
  // purpose.
  tempData.restoreState();

  // Set up the results controller's variables.
  $scope._scopename         = 'results';
  $scope.searchGroup        = tempData.getData();
  $scope.searchKey          = null;
  $scope.searchCode         = null;
  $scope.searchTitle        = null;
  $scope.searchDescription  = null;
  $scope.details            = null;
  $scope.isPage1            = true;
  $scope.showSearch         = false;
  $scope.showWatchButton    = false;
  $scope.showDetails        = false;
  $scope.orderProp          = '';
  $scope.query              = '';
  $scope.noDataMessage      = 'You have filtered out all of the results.';
  $scope.filters            = Business.getFilters();
  $scope.total              = Business.getData();
  $scope.watches            = Business.getWatches();

  // These variables are used for the pagination
  $scope.filteredTotal  = $scope.total;
  $scope.data           = $scope.total;
  $scope.rowsPerPage    = 10;
  $scope.pageNumber     = 1;
  $scope.maxPageNumber  = Math.ceil($scope.data.length / $scope.rowsPerPage);

  // currently this is a hack that grabs a short description and adds it to the
  // component information
  _.each($scope.data, function(item){
    item.shortdescription = item.description.match(/^(.*?)[.?!]\s/)[1] + '.';
  });

  /*******************************************************************************
  * This is used to initialize the scope title, key, and code. Once we have a
  * database, this is most likely where we'll do the first pull for data.
  *
  * TODO:: Add query prameters capabilities for this page so that we don't have
  * to rely on the local/session storrage to pass us the search key
  *
  * TODO:: When we do start using actual transfered searches from the main page
  * we need to initialize checks on the filters that were sent to us from that
  * page (or we need to disable the filter all together)
  *******************************************************************************/
  if (!isEmpty($scope.searchGroup)) {
    // grab all of the keys in the filters
    var keys = _.pluck($scope.filters, 'key');

    if (_.contains(keys, $scope.searchGroup[0].key)) {
      // if the search group is based on one of those filters do this
      $scope.searchKey          = $scope.searchGroup[0].key;
      $scope.searchCode         = $scope.searchGroup[0].code;
      $scope.showSearch         = true;
      $scope.searchTitle        =  _.where(_.where($scope.filters, {'key': $scope.searchGroup[0].key})[0].collection, {'code': $scope.searchGroup[0].code})[0].type;
      $scope.searchDescription  =  _.where(_.where($scope.filters, {'key': $scope.searchGroup[0].key})[0].collection, {'code': $scope.searchGroup[0].code})[0].desc;
    } else if ($scope.searchGroup[0].key === 'search') {
      // Otherwise check to see if it is a search
      $scope.searchKey          = 'DOALLSEARCH';
      $scope.showSearch         = true;
      $scope.searchTitle        = $scope.searchGroup[0].code;
      $scope.searchDescription  = 'Search resutls based on the search key: ' + $scope.searchGroup[0].code;
    } else {
      // In this case, our tempData object exists, but has no useable data
      $scope.searchKey          = 'DOALLSEARCH';
      $scope.showSearch         = true;
      $scope.searchTitle        = 'All';
      $scope.searchDescription  = 'Search all results';
    }
  } else {
    // In this case, our tempData doesn't exist
    $scope.searchKey          = 'DOALLSEARCH';
    $scope.showSearch         = true;
    $scope.searchTitle        = 'All';
    $scope.searchDescription  = 'Search all results';
  }

  /*******************************************************************************
  * This function watches for the view content loaded event and runs a timeout
  * function to handle the initial movement of the display buttons.
  *******************************************************************************/
  $scope.$on('$viewContentLoaded', function(){
    $timeout(function() {
      moveButtons($('#showPageRight'), $('.page1'));
      moveButtons($('#showPageLeft'), $('.page2'));
      if (fullClick === 0) {
        if ($(window).width() >= 768) {
          openFiltersToggle();
        }
      }
    }, 100);
  });

  /***************************************************************
  * This function is used to watch the pagenumber variable. When it changes
  * we need to readjust the pagination
  ***************************************************************/
  $scope.$watch('pageNumber',function(val, old){ /* jshint unused:false */
    $scope.pageNumber = parseInt(val);
    if ($scope.pageNumber < 1) {
      $scope.pageNumber = 1;
    }
    if ($scope.pageNumber > $scope.maxPageNumber) {
      $scope.pageNumber = $scope.maxPageNumber;
    }

    var page = $scope.pageNumber;
    if (page < 1 || page === '' || isNaN(page) || page === null){
      page = 1;
    }

    $scope.data = $scope.filteredTotal.slice(((page - 1) * $scope.rowsPerPage), (page * $scope.rowsPerPage));
    $scope.applyFilters();

  });

  /***************************************************************
  * This function is used to watch the rowsPerPage variable. When it changes
  * we need to adjust pagination
  ***************************************************************/
  $scope.$watch('rowsPerPage',function(val, old){ /* jshint unused:false */
    var rowPP = $scope.rowsPerPage;
    if (rowPP < 1 || rowPP === '' || isNaN(rowPP) || rowPP === null){
      rowPP = 1;
    }
    $scope.pageNumber = 1;
    $scope.maxPageNumber = Math.ceil($scope.filteredTotal.length / rowPP);
    $scope.applyFilters();
  });

  /***************************************************************
  * This function is used to watch the orderProp variable. When it changes
  * re-filter the data
  ***************************************************************/
  $scope.$watch('orderProp',function(val, old){ /* jshint unused:false */
    $scope.applyFilters();
  });

  /***************************************************************
  * This function is used to watch the query variable. When it changes
  * re-filter the data
  ***************************************************************/
  $scope.$watch('query',function(val, old){ /* jshint unused:false */
    $scope.applyFilters();
  });

  /***************************************************************
  * This funciton calls the global buttonOpen function that handles page
  * flyout animations according to the state to open the details
  ***************************************************************/
  $scope.doButtonOpen = function() {
    buttonOpen();
  };

  /***************************************************************
  * This funciton calls the global buttonClose function that handles page
  * flyout animations according to the state to close the details
  ***************************************************************/
  $scope.doButtonClose =  function() {
    buttonClose();
  };

  /***************************************************************
  * This function handles toggleing filter checks per filter heading click.
  ***************************************************************/
  $scope.toggleChecks = function(collection){
    var master = false;
    var found = _.where(collection, {'checked': true});

    if (!isEmpty(found)) {
      if (found.length !== collection.length) {
        master = true;
      } else {
        master = false;
      }
    } else {
      master = true;
    }
    _.each(collection, function(item){
      item.checked = master;
    });
    $scope.applyFilters();
  };

  /***************************************************************
  * This function updates the details when a component title is clicked on
  ***************************************************************/
  $scope.updateDetails = function(id){
    $scope.showWatchButton = !!!(_.where($scope.watches, {'id': id}).length);
    if (!openClick) {
      buttonOpen();
    }
    var temp =  _.where($scope.data, {'id': id})[0];
    if (temp)
    {
      $scope.details = temp;
    }
    $scope.showDetails = true;
  };

  /***************************************************************
  * This function adds a component to the watch list and toggles the buttons
  ***************************************************************/
  $scope.addToWatches = function(id){
    var a = _.findWhere($scope.watches, {'id': id});
    if (a === undefined  || isEmpty(a)) {
      $scope.watches.push({'id': id, 'watched': true});
    }
    $scope.showWatchButton = false;
    Business.setWatches($scope.watches);
  };

  /***************************************************************
  * This function removes a component to the watch list and toggles the buttons
  ***************************************************************/
  $scope.removeFromWatches = function(id){
    var a = _.findWhere($scope.watches, {'id': id});

    if (a !== undefined  && !isEmpty(a)) {
      $scope.watches.splice(_.indexOf($scope.watches, a), 1);
    }

    $scope.showWatchButton = true;
    Business.setWatches($scope.watches);
  };

  /***************************************************************
  * This function does the route redirection to the user profile path in order
  * to allow the user to view their watches.
  ***************************************************************/
  $scope.viewWatches = function () {
    $location.path('/userprofile');
  };

  /***************************************************************
  * This function applies the filters that have been given to us to filter the
  * data with
  ***************************************************************/
  $scope.applyFilters = function() {

    var results =
    // We must use recursive filtering or we will get incorrect results
    // the order DOES matter here.
    $filter('orderBy')
    ($filter('componentFilter')
      ($filter('filter')($scope.total, $scope.query),
    // filter the data by the query and return the result to the componentFilter input
    $scope.filters),
    // then use the componentFilter returned data as the input to the order-by filter
    $scope.orderProp);

    // make sure we reset the data and then copy over the results
    $scope.filteredTotal = [''];
    $scope.filteredTotal = results;

    // Do the math required to assure that we have a valid page number and
    // maxPageNumber
    $scope.maxPageNumber = Math.ceil($scope.filteredTotal.length / $scope.rowsPerPage);
    if (($scope.pageNumber - 1) * $scope.rowsPerPage >= $scope.filteredTotal.length) {
      $scope.pageNumber = 1;
    }

    // Set the data that will be displayed to the first 'n' results of the filtered data
    $scope.data = $scope.filteredTotal.slice((($scope.pageNumber - 1) * $scope.rowsPerPage), ($scope.pageNumber * $scope.rowsPerPage));

    // after a slight wait, reapply the popovers for the results ratings.
    $timeout(function() {
      setupPopovers();
    }, 300);
  };
}]);

<commit_msg>Added adjustments for filters and also set up title slightly differently to handle modal clicks.<commit_after>'use strict';

/* global isEmpty, setupPopovers, openClick:true, openWindowToggle, moveButtons,
fullClick, openFiltersToggle, buttonOpen, buttonClose */

app.controller('ResultsCtrl', ['$scope', 'tempData', 'business', '$filter', '$timeout', '$location', function ($scope, tempData, Business, $filter, $timeout, $location) {
  // So far we're using the tempData factory, but we could easily change this
  // to use the localCache factory that has more functions and capabilities
  // and then combine it with our business factory since that was their original
  // purpose.
  tempData.restoreState();

  // Set up the results controller's variables.
  $scope._scopename         = 'results';
  $scope.searchGroup        = tempData.getData();
  $scope.searchKey          = null;
  $scope.searchCode         = null;
  $scope.searchTitle        = null;
  $scope.searchDescription  = null;
  $scope.details            = null;
  $scope.isPage1            = true;
  $scope.showSearch         = false;
  $scope.showWatchButton    = false;
  $scope.showDetails        = false;
  $scope.orderProp          = '';
  $scope.query              = '';
  $scope.noDataMessage      = 'You have filtered out all of the results.';
  $scope.filters            = Business.getFilters();
  $scope.total              = Business.getData();
  $scope.watches            = Business.getWatches();

  // These variables are used for the pagination
  $scope.filteredTotal  = $scope.total;
  $scope.data           = $scope.total;
  $scope.rowsPerPage    = 10;
  $scope.pageNumber     = 1;
  $scope.maxPageNumber  = Math.ceil($scope.data.length / $scope.rowsPerPage);

  // currently this is a hack that grabs a short description and adds it to the
  // component information
  _.each($scope.data, function(item){
    item.shortdescription = item.description.match(/^(.*?)[.?!]\s/)[1] + '.';
  });

  /***************************************************************
  * This function removes the inherent filter (if you click on apps, types no longer applies etc)
  ***************************************************************/
  var adjustFilters = function() {
    $scope.filters = _.reject($scope.filters, function(item) {
      return item.key === $scope.searchGroup[0].key;
    });
  }

  /*******************************************************************************
  * This is used to initialize the scope title, key, and code. Once we have a
  * database, this is most likely where we'll do the first pull for data.
  *
  * TODO:: Add query prameters capabilities for this page so that we don't have
  * to rely on the local/session storrage to pass us the search key
  *
  * TODO:: When we do start using actual transfered searches from the main page
  * we need to initialize checks on the filters that were sent to us from that
  * page (or we need to disable the filter all together)
  *******************************************************************************/
  if (!isEmpty($scope.searchGroup)) {
    // grab all of the keys in the filters
    var keys = _.pluck($scope.filters, 'key');

    if (_.contains(keys, $scope.searchGroup[0].key)) {
      // if the search group is based on one of those filters do this
      $scope.searchKey          = $scope.searchGroup[0].key;
      $scope.searchCode         = $scope.searchGroup[0].code;
      $scope.showSearch         = true;
      $scope.searchGroupItem    = _.where($scope.filters, {'key': $scope.searchGroup[0].key})[0];
      $scope.searchColItem      = _.where($scope.searchGroupItem.collection, {'code': $scope.searchGroup[0].code})[0];
      $scope.searchType         = $scope.searchGroupItem.name;
      $scope.searchTitle        = $scope.searchType + ', ' + $scope.searchColItem.type;
      $scope.searchDescription  = $scope.searchColItem.desc;
      adjustFilters();
    } else if ($scope.searchGroup[0].key === 'search') {
      // Otherwise check to see if it is a search
      $scope.searchKey          = 'DOALLSEARCH';
      $scope.showSearch         = true;
      $scope.searchTitle        = $scope.searchGroup[0].code;
      $scope.searchDescription  = 'Search resutls based on the search key: ' + $scope.searchGroup[0].code;
    } else {
      // In this case, our tempData object exists, but has no useable data
      $scope.searchKey          = 'DOALLSEARCH';
      $scope.showSearch         = true;
      $scope.searchTitle        = 'All';
      $scope.searchDescription  = 'Search all results';
    }
  } else {
    // In this case, our tempData doesn't exist
    $scope.searchKey          = 'DOALLSEARCH';
    $scope.showSearch         = true;
    $scope.searchTitle        = 'All';
    $scope.searchDescription  = 'Search all results';
  }

  /*******************************************************************************
  * This function watches for the view content loaded event and runs a timeout
  * function to handle the initial movement of the display buttons.
  *******************************************************************************/
  $scope.$on('$viewContentLoaded', function(){
    $timeout(function() {
      moveButtons($('#showPageRight'), $('.page1'));
      moveButtons($('#showPageLeft'), $('.page2'));
      if (fullClick === 0) {
        if ($(window).width() >= 768) {
          openFiltersToggle();
        }
      }
    }, 100);
  });

  /***************************************************************
  * This function is used to watch the pagenumber variable. When it changes
  * we need to readjust the pagination
  ***************************************************************/
  $scope.$watch('pageNumber',function(val, old){ /* jshint unused:false */
    $scope.pageNumber = parseInt(val);
    if ($scope.pageNumber < 1) {
      $scope.pageNumber = 1;
    }
    if ($scope.pageNumber > $scope.maxPageNumber) {
      $scope.pageNumber = $scope.maxPageNumber;
    }

    var page = $scope.pageNumber;
    if (page < 1 || page === '' || isNaN(page) || page === null){
      page = 1;
    }

    $scope.data = $scope.filteredTotal.slice(((page - 1) * $scope.rowsPerPage), (page * $scope.rowsPerPage));
    $scope.applyFilters();

  });

  /***************************************************************
  * This function is used to watch the rowsPerPage variable. When it changes
  * we need to adjust pagination
  ***************************************************************/
  $scope.$watch('rowsPerPage',function(val, old){ /* jshint unused:false */
    var rowPP = $scope.rowsPerPage;
    if (rowPP < 1 || rowPP === '' || isNaN(rowPP) || rowPP === null){
      rowPP = 1;
    }
    $scope.pageNumber = 1;
    $scope.maxPageNumber = Math.ceil($scope.filteredTotal.length / rowPP);
    $scope.applyFilters();
  });

  /***************************************************************
  * This function is used to watch the orderProp variable. When it changes
  * re-filter the data
  ***************************************************************/
  $scope.$watch('orderProp',function(val, old){ /* jshint unused:false */
    $scope.applyFilters();
  });

  /***************************************************************
  * This function is used to watch the query variable. When it changes
  * re-filter the data
  ***************************************************************/
  $scope.$watch('query',function(val, old){ /* jshint unused:false */
    $scope.applyFilters();
  });

  /***************************************************************
  * This funciton calls the global buttonOpen function that handles page
  * flyout animations according to the state to open the details
  ***************************************************************/
  $scope.doButtonOpen = function() {
    buttonOpen();
  };

  /***************************************************************
  * This funciton calls the global buttonClose function that handles page
  * flyout animations according to the state to close the details
  ***************************************************************/
  $scope.doButtonClose =  function() {
    buttonClose();
  };

  /***************************************************************
  * This function handles toggleing filter checks per filter heading click.
  ***************************************************************/
  $scope.toggleChecks = function(collection){
    var master = false;
    var found = _.where(collection, {'checked': true});

    if (!isEmpty(found)) {
      if (found.length !== collection.length) {
        master = true;
      } else {
        master = false;
      }
    } else {
      master = true;
    }
    _.each(collection, function(item){
      item.checked = master;
    });
    $scope.applyFilters();
  };

  /***************************************************************
  * This function updates the details when a component title is clicked on
  ***************************************************************/
  $scope.updateDetails = function(id){
    $scope.showWatchButton = !!!(_.where($scope.watches, {'id': id}).length);
    if (!openClick) {
      buttonOpen();
    }
    var temp =  _.where($scope.data, {'id': id})[0];
    if (temp)
    {
      $scope.details = temp;
    }
    $scope.showDetails = true;
  };

  /***************************************************************
  * This function adds a component to the watch list and toggles the buttons
  ***************************************************************/
  $scope.addToWatches = function(id){
    var a = _.findWhere($scope.watches, {'id': id});
    if (a === undefined  || isEmpty(a)) {
      $scope.watches.push({'id': id, 'watched': true});
    }
    $scope.showWatchButton = false;
    Business.setWatches($scope.watches);
  };

  /***************************************************************
  * This function removes a component to the watch list and toggles the buttons
  ***************************************************************/
  $scope.removeFromWatches = function(id){
    var a = _.findWhere($scope.watches, {'id': id});

    if (a !== undefined  && !isEmpty(a)) {
      $scope.watches.splice(_.indexOf($scope.watches, a), 1);
    }

    $scope.showWatchButton = true;
    Business.setWatches($scope.watches);
  };

  /***************************************************************
  * This function does the route redirection to the user profile path in order
  * to allow the user to view their watches.
  ***************************************************************/
  $scope.viewWatches = function () {
    $location.path('/userprofile');
  };

  /***************************************************************
  * This function applies the filters that have been given to us to filter the
  * data with
  ***************************************************************/
  $scope.applyFilters = function() {

    var results =
    // We must use recursive filtering or we will get incorrect results
    // the order DOES matter here.
    $filter('orderBy')
    ($filter('componentFilter')
      ($filter('filter')($scope.total, $scope.query),
    // filter the data by the query and return the result to the componentFilter input
    $scope.filters),
    // then use the componentFilter returned data as the input to the order-by filter
    $scope.orderProp);

    // make sure we reset the data and then copy over the results
    $scope.filteredTotal = [''];
    $scope.filteredTotal = results;

    // Do the math required to assure that we have a valid page number and
    // maxPageNumber
    $scope.maxPageNumber = Math.ceil($scope.filteredTotal.length / $scope.rowsPerPage);
    if (($scope.pageNumber - 1) * $scope.rowsPerPage >= $scope.filteredTotal.length) {
      $scope.pageNumber = 1;
    }

    // Set the data that will be displayed to the first 'n' results of the filtered data
    $scope.data = $scope.filteredTotal.slice((($scope.pageNumber - 1) * $scope.rowsPerPage), ($scope.pageNumber * $scope.rowsPerPage));

    // after a slight wait, reapply the popovers for the results ratings.
    $timeout(function() {
      setupPopovers();
    }, 300);
  };
}]);

<|endoftext|>