<commit_before>$( document ).ready(function() {

    qrcode.callback = revealUrl;

	var imageLoader = document.getElementById('js-qr-input');
    imageLoader.addEventListener('change', handleImage, false);
	var canvas = document.getElementById('qr-canvas');
	var ctx = canvas.getContext('2d');

	function handleImage(e){
	    var reader = new FileReader();
	    reader.onload = function(event){
	        var img = new Image();
	        img.onload = function(){
	            canvas.width = img.width;
	            canvas.height = img.height;
	            ctx.drawImage(img,0,0);
	        }
	        img.src = event.target.result;
	        qrcode.decode(event.target.result);
	        $('#js-scan-btn').button('reset')
	    }
	    reader.readAsDataURL(e.target.files[0]);
	}

	function revealUrl(data) {
	    window.location.replace(data);
	  }

    $('#js-scan-btn').click(function(){
    	$("#js-qr-input").click();
    });

    $("#js-qr-input").change(function() {
        $('#js-scan-btn').button('loading');

    });

});<commit_msg>init 2<commit_after>$( document ).ready(function() {

    qrcode.callback = revealUrl;

	var imageLoader = document.getElementById('js-qr-input');
    imageLoader.addEventListener('change', handleImage, false);
	var canvas = document.getElementById('qr-canvas');
	var ctx = canvas.getContext('2d');

	function handleImage(e){
	    var reader = new FileReader();
	    $('#js-scan-btn').button('loading');
	    reader.onload = function(event){
	        var img = new Image();
	        img.onload = function(){
	            canvas.width = img.width;
	            canvas.height = img.height;
	            ctx.drawImage(img,0,0);
	        }
	        img.src = event.target.result;
	        qrcode.decode(event.target.result);
	        $('#js-scan-btn').button('reset')
	    }
	    reader.readAsDataURL(e.target.files[0]);
	}

	function revealUrl(data) {
	    window.location.replace(data);
	  }

    $('#js-scan-btn').click(function(){
    	$("#js-qr-input").click();
    });

});<|endoftext|>


<commit_before><commit_msg>cartService: implemented getCart and getTotalPrice<commit_after>var fikrimuhalStaj = angular.module('fikrimuhalStaj');

fikrimuhalStaj.factory('cartService', [function loginService() {

    var mockCartItems = [
        {'id': 5, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': 9100, 'discountedPrice': 90},
        {'id': 415, 'name': "kazak", 'price': 100, 'amount': 2, 'subPrice': 8100, 'discountedPrice': 80},
        {'id': 435, 'name': "kazak", 'price': 100, 'amount': 3, 'subPrice': 7100, 'discountedPrice': 700},
        {'id': 455, 'name': "kazak", 'price': 100, 'amount': 4, 'subPrice': 6100, 'discountedPrice': 600},
        {'id': 456, 'name': "kazak", 'price': 100, 'amount': 5, 'subPrice': 5100, 'discountedPrice': 500},
        {'id': 4545, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': 4100, 'discountedPrice': 400},
        {'id': 458, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': 3100, 'discountedPrice': 300},
        {'id': 459, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': 2100, 'discountedPrice': 200},
        {'id': 451, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': 1100, 'discountedPrice': 100},
        {'id': 453, 'name': "kazak", 'price': 100, 'amount': 1, 'subPrice': -100, 'discountedPrice': 1100}
    ];
    var cartItems = mockCartItems;

    function TODO () {
        console.log("Not Implemented Yet");
    }

    function getCart() {
        return cartItems;
    }

    function getTotalPrice() {
        return _.map(getCart(), "price").reduce(function (sum, price) {
            return sum + price;
        });
    }

    return {
        'getCart': getCart,
        'getTotalPrice': getTotalPrice,
        'getDiscountedPrice': TODO
    }
}]);
<|endoftext|>


<commit_before>/*!
 * FullCalendar v2.2.5 UoA Calendar Plugin
 * (c) 2015 University of Auckland
 */

var sOptions;

function getSourceOptions() {
	return sOptions;
}
(function(factory) {
	if (typeof define === 'function' && define.amd) {
		define([ 'jquery' ], factory);
	}
	else {
		factory(jQuery);
	}
})(function($) {

var fc = $.fullCalendar;
var applyAll = fc.applyAll;

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

fc.sourceNormalizers.push(function(sourceOptions) {
	var uoaCalendarId = sourceOptions.uoaCalendarId;
	var uoaCalendarHost = sourceOptions.uoaCalendarHost;
	var uoaCalendarPort = sourceOptions.uoaCalendarPort;
	var url = sourceOptions.url;
	var match;

    if(!uoaCalendarHost)
        sourceOptions.uoaCalendarHost = window.location.protocol + '//' + window.location.hostname;
    else if(uoaCalendarHost.substring(0,7) != "https://" && uoaCalendarHost.substring(0,6)!= "http://")
    	sourceOptions.uoaCalendarHost = "http://" + uoaCalendarHost;

    if(!uoaCalendarPort)
        sourceOptions.uoaCalendarPort = 8000;

	// Use the Url parameter if none was specified
	if (!uoaCalendarId) {
		uoaCalendarId = getParameterByName('uoaCalendarId');
	}

	if (uoaCalendarId) {

		sourceOptions.uoaCalendarId = uoaCalendarId;
	}
	sOptions = $.extend(sOptions, sourceOptions);
});

fc.sourceFetchers.push(function(sourceOptions, start, end, timezone) {
	if (sourceOptions.uoaCalendarId) {
		var test = transformOptions(sourceOptions, start, end, timezone, this); // `this` is the calendar
		return test;
	}
});

function transformOptions(sourceOptions, start, end, timezone, calendar) {
	var url = sourceOptions.uoaCalendarHost + ':' + sourceOptions.uoaCalendarPort +  '/calendars/' + sourceOptions.uoaCalendarId + '/find_events/'; // jsonp
	var apiKey = sourceOptions.uoaCalendarApiToken || calendar.options.uoaCalendarApiToken;
	var success = sourceOptions.success;
	var data;
	var timezoneArg; // populated when a specific timezone. escaped to Google's liking

	function reportError(message, apiErrorObjs) {
		var errorObjs = apiErrorObjs || [ { message: message } ]; // to be passed into error handlers
		var consoleObj = window.console;
		var consoleWarnFunc = consoleObj ? (consoleObj.warn || consoleObj.log) : null;

		// call error handlers
		(sourceOptions.uoaCalendarError || $.noop).apply(calendar, errorObjs);
		(calendar.options.uoaCalendarError || $.noop).apply(calendar, errorObjs);

		// print error to debug console
		if (consoleWarnFunc) {
			consoleWarnFunc.apply(consoleObj, [ message ].concat(apiErrorObjs || []));
		}
	}

	if (!apiKey) {
		console.log("'uoaCalendarApiToken' has not been specified. User authentication won't be sent in the request!");
	}

	// The API expects an ISO8601 datetime with a time and timezone part.
	// Since the calendar's timezone offset isn't always known, request the date in UTC and pad it by a day on each
	// side, guaranteeing we will receive all events in the desired range, albeit a superset.
	// .utc() will set a zone and give it a 00:00:00 time.
	if (!start.hasZone()) {
		start = start.clone().utc().add(-1, 'day');
	}
	if (!end.hasZone()) {
		end = end.clone().utc().add(1, 'day');
	}

	// when sending timezone names to Google, only accepts underscores, not spaces
	if (timezone && timezone != 'local') {
		timezoneArg = timezone.replace(' ', '_');
	}

	data = $.extend({}, sourceOptions.data || {}, {
		startAfter: start.format(),
		endBefore: end.format()
	});

	headers = {'Content-Type': 'application/json; charset=utf-8'}
	if(apiKey)
		$.extend(headers, {'Authorization': 'JWT ' + apiKey });

	return $.extend({}, sourceOptions, {
		headers: headers,
		uoaCalendarId: null, // prevents source-normalizing from happening again
		url: url,
		data: data,
		success: function(data) {
			var events = [];
			var successArgs;
			var successRes;

			if (data.error) {
				reportError('UoA Calendar API: ' + data.error.message, data.error.errors);
			}
			else if (data) {
				$.each(data, function(i, entry) {
					var url = entry.htmlLink;

					// make the URLs for each event show times in the correct timezone
					if (timezoneArg) {
						//url = injectQsComponent(url, 'ctz=' + timezoneArg);
					}

					events.push({
						id: entry.id,
						calendar: sourceOptions.uoaCalendarId,
						title: entry.title,
						description: entry.description,
						location: entry.location,
						summary: entry.summary,
						lastUpdate: entry.lastUpdate,
						start: entry.start, // try timed. will fall back to all-day
						end: entry.end, // same
						status: entry.status,
						reminder: entry.reminder,
						todo: entry.todo,
						allDay: entry.allDay,
						url: entry.url
					});
				});

				// call the success handler(s) and allow it to return a new events array
				successArgs = [ events ].concat(Array.prototype.slice.call(arguments, 1)); // forward other jq args
				successRes = applyAll(success, this, successArgs);
				if ($.isArray(successRes)) {
					return successRes;
				}
			}

			return events;
		}
	});
}

// Injects a string like "arg=value" into the querystring of a URL
function injectQsComponent(url, component) {
	// inject it after the querystring but before the fragment
	return url.replace(/(\?.*?)?(#|$)/, function(whole, qs, hash) {
		return (qs ? qs + '&' : '?') + component + hash;
	});
}

});<commit_msg>Update uoacal.js<commit_after>/*!
 * FullCalendar v2.2.5 UoA Calendar Plugin
 * (c) 2015 University of Auckland
 */

var sOptions;

function getSourceOptions() {
	return sOptions;
}
(function(factory) {
	if (typeof define === 'function' && define.amd) {
		define([ 'jquery' ], factory);
	}
	else {
		factory(jQuery);
	}
})(function($) {

var fc = $.fullCalendar;
var applyAll = fc.applyAll;

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

fc.sourceNormalizers.push(function(sourceOptions) {
	var uoaCalendarId = sourceOptions.uoaCalendarId;
	var uoaCalendarHost = sourceOptions.uoaCalendarHost;
	var uoaCalendarPort = sourceOptions.uoaCalendarPort;
	var url = sourceOptions.url;
	var match;

    if(!uoaCalendarHost)
        sourceOptions.uoaCalendarHost = window.location.protocol + '//' + window.location.hostname;
    else if(uoaCalendarHost.substring(0,7) != "https://" && uoaCalendarHost.substring(0,6)!= "http://")
    	sourceOptions.uoaCalendarHost = "http://" + uoaCalendarHost;

    if(!uoaCalendarPort)
        sourceOptions.uoaCalendarPort = 80;

	// Use the Url parameter if none was specified
	if (!uoaCalendarId) {
		uoaCalendarId = getParameterByName('uoaCalendarId');
	}

	if (uoaCalendarId) {

		sourceOptions.uoaCalendarId = uoaCalendarId;
	}
	sOptions = $.extend(sOptions, sourceOptions);
});

fc.sourceFetchers.push(function(sourceOptions, start, end, timezone) {
	if (sourceOptions.uoaCalendarId) {
		var test = transformOptions(sourceOptions, start, end, timezone, this); // `this` is the calendar
		return test;
	}
});

function transformOptions(sourceOptions, start, end, timezone, calendar) {
	var url = sourceOptions.uoaCalendarHost + ':' + sourceOptions.uoaCalendarPort +  '/calendars/' + sourceOptions.uoaCalendarId + '/find_events/'; // jsonp
	var apiKey = sourceOptions.uoaCalendarApiToken || calendar.options.uoaCalendarApiToken;
	var success = sourceOptions.success;
	var data;
	var timezoneArg; // populated when a specific timezone. escaped to Google's liking

	function reportError(message, apiErrorObjs) {
		var errorObjs = apiErrorObjs || [ { message: message } ]; // to be passed into error handlers
		var consoleObj = window.console;
		var consoleWarnFunc = consoleObj ? (consoleObj.warn || consoleObj.log) : null;

		// call error handlers
		(sourceOptions.uoaCalendarError || $.noop).apply(calendar, errorObjs);
		(calendar.options.uoaCalendarError || $.noop).apply(calendar, errorObjs);

		// print error to debug console
		if (consoleWarnFunc) {
			consoleWarnFunc.apply(consoleObj, [ message ].concat(apiErrorObjs || []));
		}
	}

	if (!apiKey) {
		console.log("'uoaCalendarApiToken' has not been specified. User authentication won't be sent in the request!");
	}

	// The API expects an ISO8601 datetime with a time and timezone part.
	// Since the calendar's timezone offset isn't always known, request the date in UTC and pad it by a day on each
	// side, guaranteeing we will receive all events in the desired range, albeit a superset.
	// .utc() will set a zone and give it a 00:00:00 time.
	if (!start.hasZone()) {
		start = start.clone().utc().add(-1, 'day');
	}
	if (!end.hasZone()) {
		end = end.clone().utc().add(1, 'day');
	}

	// when sending timezone names to Google, only accepts underscores, not spaces
	if (timezone && timezone != 'local') {
		timezoneArg = timezone.replace(' ', '_');
	}

	data = $.extend({}, sourceOptions.data || {}, {
		startAfter: start.format(),
		endBefore: end.format()
	});

	headers = {'Content-Type': 'application/json; charset=utf-8'}
	if(apiKey)
		$.extend(headers, {'Authorization': 'JWT ' + apiKey });

	return $.extend({}, sourceOptions, {
		headers: headers,
		uoaCalendarId: null, // prevents source-normalizing from happening again
		url: url,
		data: data,
		success: function(data) {
			var events = [];
			var successArgs;
			var successRes;

			if (data.error) {
				reportError('UoA Calendar API: ' + data.error.message, data.error.errors);
			}
			else if (data) {
				$.each(data, function(i, entry) {
					var url = entry.htmlLink;

					// make the URLs for each event show times in the correct timezone
					if (timezoneArg) {
						//url = injectQsComponent(url, 'ctz=' + timezoneArg);
					}

					events.push({
						id: entry.id,
						calendar: sourceOptions.uoaCalendarId,
						title: entry.title,
						description: entry.description,
						location: entry.location,
						summary: entry.summary,
						lastUpdate: entry.lastUpdate,
						start: entry.start, // try timed. will fall back to all-day
						end: entry.end, // same
						status: entry.status,
						reminder: entry.reminder,
						todo: entry.todo,
						allDay: entry.allDay,
						url: entry.url
					});
				});

				// call the success handler(s) and allow it to return a new events array
				successArgs = [ events ].concat(Array.prototype.slice.call(arguments, 1)); // forward other jq args
				successRes = applyAll(success, this, successArgs);
				if ($.isArray(successRes)) {
					return successRes;
				}
			}

			return events;
		}
	});
}

// Injects a string like "arg=value" into the querystring of a URL
function injectQsComponent(url, component) {
	// inject it after the querystring but before the fragment
	return url.replace(/(\?.*?)?(#|$)/, function(whole, qs, hash) {
		return (qs ? qs + '&' : '?') + component + hash;
	});
}

});
<|endoftext|>


<commit_before>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {
	"use strict";
	var path = require('path');

	function awsNodeBroker(n) {
		RED.nodes.createNode(this, n);
		this.clientId = n.clientId;
		var self = this;

		this.connect = function(clientId, reconnect, callback) {
			clientId = clientId || n.clientId;
			clientId = clientId.trim();
			var awsCerts = n.awscerts || ".";
			if (!self.device || reconnect) {
				self.log("Attempt to connect to " + n.mode + " with " + clientId + " from: " + awsCerts);
				if (n.mode == "shadow") {
					self.device = require('aws-iot-device-sdk').thingShadow({
						keyPath : path.join(awsCerts, '/' + clientId + '-private.pem.key'),
						certPath : path.join(awsCerts, '/' + clientId + '-certificate.pem.crt'),
						caPath : path.join(awsCerts, '/root-CA.crt'),
						clientId : clientId,
						region : n.region,
						protocol: 'mqtts'
					});
				} else {
					self.device = require('aws-iot-device-sdk').device({
						keyPath : path.join(awsCerts, '/' + clientId + '-private.pem.key'),
						certPath : path.join(awsCerts, '/' + clientId + '-certificate.pem.crt'),
						caPath : path.join(awsCerts, '/root-CA.crt'),
						clientId : clientId,
						region : n.region,
						protocol: 'mqtts'
					});
				}
				if (self.device) {
					self.device.on('connect', function() {
						callback('connected');
					});
					self.device.on('reconnect', function() {
						callback('reconnected');
					});
					self.device.on('error', function(error) {
						callback('error', error);
					});
					self.device.on('offline', function() {
						callback('offline');
					});
				}
				callback('created');
			} else if (self.device) {
				callback('ready');
			}
		};

		self.on('close', function() {
			self.log("closed " + self.clientId + " ok");
			if (self.device) {
				if (n.mode == "shadow") {
					self.device.unregister(self.clientId);
					self.device.end();
				} else {
					self.device.end();
				}
			}

		});
	}

	RED.nodes.registerType("aws-iot-device", awsNodeBroker);

	function awsMqttNodeIn(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);
		var self = this;
		var options = {
			qos: parseInt(n.qos) || 0
		};
		if (self.awsIot) {
			self.status({
				fill : "yellow",
				shape : "ring",
				text : "subscribing..."
			});
			self.awsIot.connect(null, null, function(event, error) {
				if (event == "created") {
					self.awsIot.device.unsubscribe(n.topic);
					self.awsIot.device.subscribe(n.topic, options, function(error, granted) {
						if (!error) {
							self.status({
								fill : "green",
								shape : "ring",
								text : "subscribed"
							});
							self.awsIot.device.on('message', function(topic, payload) {
								if ( typeof payload === "string") {
								} else {
									payload = payload.toString();
								}
								console.log("RECV<", topic, payload);
								self.send({
									topic : topic,
									payload : payload
								});
							});
						} else {
							self.status({
								fill : "error",
								shape : "ring",
								text : error.message
							});
						}
					});
				}
			});
		} else {
			self.error("aws-mqtt in is not configured");
			self.status({
				fill : "red",
				shape : "ring",
				text : "not configured"
			});
		}
	}

	RED.nodes.registerType("aws-mqtt in", awsMqttNodeIn);

	function awsMqttNodeOut(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);
		var self = this;
		var options = {
			qos: parseInt(n.qos) || 0
		};
		self.on("input", function(msg) {
			if (self.awsIot) {
				self.awsIot.connect(msg.clientId, msg.reconnect, function(event, error) {
					if ((event == "ready" || event == "created")) {
						if (!Buffer.isBuffer(msg.payload)) {
							if ( typeof msg.payload === "object") {
								msg.payload = JSON.stringify(msg.payload);
							} else if ( typeof msg.payload !== "string") {
								msg.payload = msg.payload.toString();
							}
							msg.payload = new Buffer(msg.payload, "utf-8");
						}
						self.status({
							fill : "blue",
							shape : "ring",
							text : "sending..."
						});
						console.log("SEND>", msg.topic || n.topic, msg.payload);
						self.awsIot.device.publish(msg.topic || n.topic, msg.payload, options, function(error) {
							if (error) {
								self.status({
									fill : "red",
									shape : "ring",
									text : error.message
								});
							} else {
								self.status({
									fill : "green",
									shape : "ring",
									text : "done"
								});
							}
						});
					}
				});
			} else {
				self.error("aws-mqtt out is not configured");
				self.status({
					fill : "red",
					shape : "ring",
					text : "not configured"
				});
			}
		});
	}

	RED.nodes.registerType("aws-mqtt out", awsMqttNodeOut);

	function awsThingShadowNodeFunc(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);

		var self = this;
		self.on("input", function(msg) {
			if (self.awsIot) {
				self.awsIot.connect(msg.clientId, msg.reconnect, function(event, error) {
					if (event == "created") {
						self.awsIot.device.unregister(self.awsIot.clientId);
						self.awsIot.device.register(self.awsIot.clientId, {
							ignoreDeltas : true,
							persistentSubscribe : true
						});
						if (n.method == 'get') {
							self.clientToken = self.awsIot.device[n.method](self.awsIot.clientId);
						} else {
							self.clientToken = self.awsIot.device[n.method](self.awsIot.clientId, msg.payload);
						}
						self.awsIot.device.on('message', function(topic, payload) {
							self.log('onMessage: ' + topic + ", " + payload.toString());
							self.send({
								type : 'message',
								topic : topic,
								payload : JSON.parse(payload.toString())
							});
						});
						self.awsIot.device.on('delta', function(thingName, stateObject) {
							self.log('onDelta ' + thingName + ': ' + JSON.stringify(stateObject));
							self.send({
								type : 'delta',
								name : thingName,
								payload : stateObject
							});
						});
						self.awsIot.device.on('status', function(thingName, status, clientToken, stateObject) {
							if (self.clientToken == clientToken) {
								self.log('onStatus: ' + thingName + ", clientToken: " + self.clientToken);
								self.send({
									type : 'status',
									name : thingName,
									token : clientToken,
									payload : {
										status : status,
										stateObject : stateObject,
									}
								});
							}
						});
						self.awsIot.device.on('timeout', function(thingName, clientToken) {
							if (self.clientToken == clientToken) {
								self.send({
									type : 'timeout',
									name : thingName,
									token : clientToken,
									payload : {
									}
								});
							}
						});
					}
				});

			} else {
				self.error("aws-thing shadow is not configured");
			}
		});
	}

	RED.nodes.registerType("aws-thing", awsThingShadowNodeFunc);
};
<commit_msg>set pointer to null<commit_after>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {
	"use strict";
	var path = require('path');

	function awsNodeBroker(n) {
		RED.nodes.createNode(this, n);
		this.clientId = n.clientId;
		var self = this;

		this.connect = function(clientId, reconnect, callback) {
			clientId = clientId || n.clientId;
			clientId = clientId.trim();
			var awsCerts = n.awscerts || ".";
			if (!self.device || reconnect) {
				self.log("Attempt to connect to " + n.mode + " with " + clientId + " from: " + awsCerts);
				if (n.mode == "shadow") {
					self.device = require('aws-iot-device-sdk').thingShadow({
						keyPath : path.join(awsCerts, '/' + clientId + '-private.pem.key'),
						certPath : path.join(awsCerts, '/' + clientId + '-certificate.pem.crt'),
						caPath : path.join(awsCerts, '/root-CA.crt'),
						clientId : clientId,
						region : n.region,
						protocol: 'mqtts'
					});
				} else {
					self.device = require('aws-iot-device-sdk').device({
						keyPath : path.join(awsCerts, '/' + clientId + '-private.pem.key'),
						certPath : path.join(awsCerts, '/' + clientId + '-certificate.pem.crt'),
						caPath : path.join(awsCerts, '/root-CA.crt'),
						clientId : clientId,
						region : n.region,
						protocol: 'mqtts'
					});
				}
				if (self.device) {
					self.device.on('connect', function() {
						callback('connected');
					});
					self.device.on('reconnect', function() {
						callback('reconnected');
					});
					self.device.on('error', function(error) {
						callback('error', error);
					});
					self.device.on('offline', function() {
						callback('offline');
					});
				}
				callback('created');
			} else if (self.device) {
				callback('ready');
			}
		};

		self.on('close', function() {
			self.log("closed " + self.clientId + " ok");
			if (self.device) {
				if (n.mode == "shadow") {
					self.device.unregister(self.clientId);
					self.device.end();
				} else {
					self.device.end();
				}
			}
			self.device = null;
		});
	}

	RED.nodes.registerType("aws-iot-device", awsNodeBroker);

	function awsMqttNodeIn(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);
		var self = this;
		var options = {
			qos: parseInt(n.qos) || 0
		};
		if (self.awsIot) {
			self.status({
				fill : "yellow",
				shape : "ring",
				text : "subscribing..."
			});
			self.awsIot.connect(null, null, function(event, error) {
				if (event == "created") {
					self.awsIot.device.unsubscribe(n.topic);
					self.awsIot.device.subscribe(n.topic, options, function(error, granted) {
						if (!error) {
							self.status({
								fill : "green",
								shape : "ring",
								text : "subscribed"
							});
							self.awsIot.device.on('message', function(topic, payload) {
								if ( typeof payload === "string") {
								} else {
									payload = payload.toString();
								}
								console.log("RECV<", topic, payload);
								self.send({
									topic : topic,
									payload : payload
								});
							});
						} else {
							self.status({
								fill : "error",
								shape : "ring",
								text : error.message
							});
						}
					});
				}
			});
		} else {
			self.error("aws-mqtt in is not configured");
			self.status({
				fill : "red",
				shape : "ring",
				text : "not configured"
			});
		}
	}

	RED.nodes.registerType("aws-mqtt in", awsMqttNodeIn);

	function awsMqttNodeOut(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);
		var self = this;
		var options = {
			qos: parseInt(n.qos) || 0
		};
		self.on("input", function(msg) {
			if (self.awsIot) {
				self.awsIot.connect(msg.clientId, msg.reconnect, function(event, error) {
					if ((event == "ready" || event == "created")) {
						if (!Buffer.isBuffer(msg.payload)) {
							if ( typeof msg.payload === "object") {
								msg.payload = JSON.stringify(msg.payload);
							} else if ( typeof msg.payload !== "string") {
								msg.payload = msg.payload.toString();
							}
							msg.payload = new Buffer(msg.payload, "utf-8");
						}
						self.status({
							fill : "blue",
							shape : "ring",
							text : "sending..."
						});
						console.log("SEND>", msg.topic || n.topic, msg.payload);
						self.awsIot.device.publish(msg.topic || n.topic, msg.payload, options, function(error) {
							if (error) {
								self.status({
									fill : "red",
									shape : "ring",
									text : error.message
								});
							} else {
								self.status({
									fill : "green",
									shape : "ring",
									text : "done"
								});
							}
						});
					}
				});
			} else {
				self.error("aws-mqtt out is not configured");
				self.status({
					fill : "red",
					shape : "ring",
					text : "not configured"
				});
			}
		});
	}

	RED.nodes.registerType("aws-mqtt out", awsMqttNodeOut);

	function awsThingShadowNodeFunc(n) {
		RED.nodes.createNode(this, n);
		this.myDevice = n.device;
		this.awsIot = RED.nodes.getNode(this.myDevice);

		var self = this;
		self.on("input", function(msg) {
			if (self.awsIot) {
				self.awsIot.connect(msg.clientId, msg.reconnect, function(event, error) {
					if (event == "created") {
						self.awsIot.device.unregister(self.awsIot.clientId);
						self.awsIot.device.register(self.awsIot.clientId, {
							ignoreDeltas : true,
							persistentSubscribe : true
						});
						if (n.method == 'get') {
							self.clientToken = self.awsIot.device[n.method](self.awsIot.clientId);
						} else {
							self.clientToken = self.awsIot.device[n.method](self.awsIot.clientId, msg.payload);
						}
						self.awsIot.device.on('message', function(topic, payload) {
							self.log('onMessage: ' + topic + ", " + payload.toString());
							self.send({
								type : 'message',
								topic : topic,
								payload : JSON.parse(payload.toString())
							});
						});
						self.awsIot.device.on('delta', function(thingName, stateObject) {
							self.log('onDelta ' + thingName + ': ' + JSON.stringify(stateObject));
							self.send({
								type : 'delta',
								name : thingName,
								payload : stateObject
							});
						});
						self.awsIot.device.on('status', function(thingName, status, clientToken, stateObject) {
							if (self.clientToken == clientToken) {
								self.log('onStatus: ' + thingName + ", clientToken: " + self.clientToken);
								self.send({
									type : 'status',
									name : thingName,
									token : clientToken,
									payload : {
										status : status,
										stateObject : stateObject,
									}
								});
							}
						});
						self.awsIot.device.on('timeout', function(thingName, clientToken) {
							if (self.clientToken == clientToken) {
								self.send({
									type : 'timeout',
									name : thingName,
									token : clientToken,
									payload : {
									}
								});
							}
						});
					}
				});

			} else {
				self.error("aws-thing shadow is not configured");
			}
		});
	}

	RED.nodes.registerType("aws-thing", awsThingShadowNodeFunc);
};
<|endoftext|>


<commit_before>(function ($) {
  $.extend($.summernote.lang, {
    'pt-BR': {
      font: {
        bold: 'Negrito',
        italic: 'Itálico',
        underline: 'Sublinhado',
        clear: 'Remover estilo da fonte',
        height: 'Altura da linha',
        name: 'Fonte',
        strikethrough: 'Riscado',
        size: 'Tamanho da fonte'
      },
      image: {
        image: 'Imagem',
        insert: 'Inserir imagem',
        resizeFull: 'Resize Full',
        resizeHalf: 'Resize Half',
        resizeQuarter: 'Resize Quarter',
        floatLeft: 'Float Left',
        floatRight: 'Float Right',
        floatNone: 'Float None',
        dragImageHere: 'Arraste uma imagem para cá',
        selectFromFiles: 'Selecione a partir dos arquivos',
        url: 'URL da image'
      },
      video: {
        video: 'Vídeo',
        videoLink: 'Link para vídeo',
        insert: 'Inserir vídeo',
        url: 'URL do vídeo?',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, ou Youku)'
      },
      link: {
        link: 'Link',
        insert: 'Inserir link',
        unlink: 'Remover link',
        edit: 'Editar',
        textToDisplay: 'Texto para exibir',
        url: 'Para qual URL esse link leva?',
        openInNewWindow: 'Abrir em uma nova janela'
      },
      table: {
        table: 'Tabela'
      },
      hr: {
        insert: 'Inserir linha horizontal'
      },
      style: {
        style: 'Estilo',
        normal: 'Normal',
        blockquote: 'Citação',
        pre: 'Código',
        h1: 'Título 1',
        h2: 'Título 2',
        h3: 'Título 3',
        h4: 'Título 4',
        h5: 'Título 5',
        h6: 'Título 6'
      },
      lists: {
        unordered: 'Lista com marcadores',
        ordered: 'Lista numerada'
      },
      options: {
        help: 'Ajuda',
        fullscreen: 'Tela cheia',
        codeview: 'Ver código-fonte'
      },
      paragraph: {
        paragraph: 'Parágrafo',
        outdent: 'Menor tabulação',
        indent: 'Maior tabulação',
        left: 'Alinhar à esquerda',
        center: 'Alinhar ao centro',
        right: 'Alinha à direita',
        justify: 'Justificado'
      },
      color: {
        recent: 'Cor recente',
        more: 'Mais cores',
        background: 'Fundo',
        foreground: 'Fonte',
        transparent: 'Transparente',
        setTransparent: 'Fundo transparente',
        reset: 'Restaurar',
        resetToDefault: 'Restaurar padrão'
      },
      shortcut: {
        shortcuts: 'Atalhos do teclado',
        close: 'Fechar',
        textFormatting: 'Formatação de texto',
        action: 'Ação',
        paragraphFormatting: 'Formatação de parágrafo',
        documentStyle: 'Estilo de documento'
      },
      history: {
        undo: 'Desfazer',
        redo: 'Refazer'
      }
    }
  });
})(jQuery);
<commit_msg>Simple translation summernote-en-BR.js<commit_after>(function ($) {
  $.extend($.summernote.lang, {
    'pt-BR': {
      font: {
        bold: 'Negrito',
        italic: 'Itálico',
        underline: 'Sublinhado',
        clear: 'Remover estilo da fonte',
        height: 'Altura da linha',
        name: 'Fonte',
        strikethrough: 'Riscado',
        size: 'Tamanho da fonte'
      },
      image: {
        image: 'Imagem',
        insert: 'Inserir imagem',
        resizeFull: 'Redimensionar Completamente',
        resizeHalf: 'Redimensionar pela Metade',
        resizeQuarter: 'Redimensionar um Quarto',
        floatLeft: 'Flutuar para Esquerda',
        floatRight: 'Flutuar para Direira',
        floatNone: 'Não Flutuar',
        dragImageHere: 'Arraste uma imagem para cá',
        selectFromFiles: 'Selecione a partir dos arquivos',
        url: 'URL da image'
      },
      video: {
        video: 'Vídeo',
        videoLink: 'Link para vídeo',
        insert: 'Inserir vídeo',
        url: 'URL do vídeo?',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, ou Youku)'
      },
      link: {
        link: 'Link',
        insert: 'Inserir link',
        unlink: 'Remover link',
        edit: 'Editar',
        textToDisplay: 'Texto para exibir',
        url: 'Para qual URL esse link leva?',
        openInNewWindow: 'Abrir em uma nova janela'
      },
      table: {
        table: 'Tabela'
      },
      hr: {
        insert: 'Inserir linha horizontal'
      },
      style: {
        style: 'Estilo',
        normal: 'Normal',
        blockquote: 'Citação',
        pre: 'Código',
        h1: 'Título 1',
        h2: 'Título 2',
        h3: 'Título 3',
        h4: 'Título 4',
        h5: 'Título 5',
        h6: 'Título 6'
      },
      lists: {
        unordered: 'Lista com marcadores',
        ordered: 'Lista numerada'
      },
      options: {
        help: 'Ajuda',
        fullscreen: 'Tela cheia',
        codeview: 'Ver código-fonte'
      },
      paragraph: {
        paragraph: 'Parágrafo',
        outdent: 'Menor tabulação',
        indent: 'Maior tabulação',
        left: 'Alinhar à esquerda',
        center: 'Alinhar ao centro',
        right: 'Alinha à direita',
        justify: 'Justificado'
      },
      color: {
        recent: 'Cor recente',
        more: 'Mais cores',
        background: 'Fundo',
        foreground: 'Fonte',
        transparent: 'Transparente',
        setTransparent: 'Fundo transparente',
        reset: 'Restaurar',
        resetToDefault: 'Restaurar padrão'
      },
      shortcut: {
        shortcuts: 'Atalhos do teclado',
        close: 'Fechar',
        textFormatting: 'Formatação de texto',
        action: 'Ação',
        paragraphFormatting: 'Formatação de parágrafo',
        documentStyle: 'Estilo de documento'
      },
      history: {
        undo: 'Desfazer',
        redo: 'Refazer'
      }
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>/*global require, angular*/

/**
 * [dialog 弹窗服务]
 *
 * @author zhoul
 * @description
 * dialog 弹窗服务
 *
 * 方法：
 *  confirm： 确认框
 *  alert:    确定框
 *  modal:    自定义弹窗
 *
 * 弹框参数：
 *  title：弹出标题模板
 *  template： 显示模板
 *  templateUrl: 模板地址
 *  className： 弹出类名
 *  backdropClass：遮罩层类名
 *  success： 用户自定义模板的时候点击确定 请求某个服务端接口 成功执行的回调
 *  error： 用户自定义模板的时候点击确定 请求某个服务端接口 失败执行的回调
 *  resolves： 弹出之前需要处理的一些依赖
 *  controllerAs：用于支持as语法
 *  controller: 用户自定义模板的时候 可以添加控制器 处理自定义的模板
 *  container：弹窗组append的DOM
 *  locals：一些数据可在自定义模板的控制器中依赖注入
 *
 * @example
 * 确认框
 * dialogs.confirm({
 *    template: '
确认删除？
'
 * })
 * .then(function () {
 *    alert("您点了确认");
 *    dialogs.close();
 * }, function(){
 *    alert("您点了取消");
 *    dialogs.close();
 * });
 *
 * @example
 * 确定框
 * dialogs.alert({
 *    template: '
确认删除？
'
 * })
 * .then(function(){
 *    dialogs.close();
 * })
 *
 * @example
 * 自定义弹窗
 * dialogs.modal({
 *  method: 'login',
 *  className: 'login-from',
 *  backdropClass: 'in',
 *  templateUrl: loginV2Tmp,
 *  success: function (data) {
 *    var result = data.data.data;
 *    alert('tick')
 *  },
 *  controller: 'loginCtrl'
 * })
 */
angular
  .module('jmui.dialog', [])
  .service('dialogs', function ($document, $compile, $q, $http, $rootScope, $controller, $animate, $templateCache) {
    /**
     * 弹出框构造函数
     * @description 一个弹出框服务用于模拟window的alert、confirm 以及自定义模版的弹出框
     * @class Dialogs
     */
    function Dialogs() {
      this.resolveKeys = [];
      this.scope = {};
      this.locals = {};
      this.element = null;
      this.resolves = [];
      this.controllerName = '';
    }

    /**
     * 创建模版
     * @param   {object}  config 初始配置
     * @returns {object} promise对象
     */
    Dialogs.prototype.creatHTML = function (config) {
      var header = '',
        footer = '',
        template = '
' + (config.template) + '
',
        templateUrl = config.templateUrl,
        defer = $q.defer(),
        backdrop = angular.element('

'),
        dialogBox = angular.element('
' + (config.isShowCloseIcon ? '×

' : ''));

      this.backdrop = angular.element('

');

      if (config.dialogHeader) {
        header = '
' + config.dialogHeader + '
';
      }

      if (config.dialogFooter) {
        footer = '
' + config.dialogFooter + '
';
      }
      if (templateUrl) {
        $http.get(templateUrl, {
          cache: $templateCache
        }).then(function (response) {
          defer.resolve(backdrop.append(dialogBox.append(response.data)));
        });
      } else {
        return $q.when(backdrop.append(dialogBox.append((header + template + footer))));
      }
      return defer.promise;
    };

    /**
     * 依赖方法 弹出框依赖的数据在没有得到的时候将不会显示弹出
     * @param   {object} config 配置对象
     * @returns {object} promise 对象
     */
    Dialogs.prototype.resolve = function (config) {
      var resolves = config.resolve,
        attr;

      if (angular.isObject(resolves)) {

        for (attr in resolves) {
          if (resolves.hasOwnProperty(attr)) {
            this.resolveKeys.push(attr);
            this.resolves.push(config.resolve[attr]());
          }
        }
      }
      return $q.all(this.resolves);
    };

    /**
     * 编译模版并添加到指定的Dom中
     * @param   {object} data   传入到弹出框中的数据对象
     * @param   {object} config 配置文件
     * @returns {object} Dom    对象
     */
    Dialogs.prototype.render = function (data, config) {
      var scope = this.scope,
        ctrl,
        prop;

      this.element = angular.element(data);

      if (this.controllerName) {
        this.locals.$scope = scope;
        ctrl = $controller(this.controllerName, this.locals);
        if (this.controllerAs) {
          scope[this.controllerAs] = ctrl;
        } else if (this.locals) {
          for (prop in this.locals) {
            if (this.locals.hasOwnProperty(prop)) {
              scope[prop] = this.locals[prop];
            }
          }
        }
      }
      $compile(this.element)(scope);
      $animate.enter(this.element, this.container);
      $animate.addClass(this.backdrop, config.backdropClass || '');
    };

    /**
     * 弹出框方法
     * @param   {object} conf 配置对象
     * @returns {object} promise
     */
    Dialogs.prototype.modal = function (conf) {
      var config = conf || {};
      var scope = this.scope = $rootScope.$new(true);

      console.log(scope);

      var defer = $q.defer();
      var self = this;
      var method = config.method;
      var dataElement = null;

      this.config = config;
      this.container = angular.element(config.container || document.body);
      this.controllerAs = config.controllerAs;
      this.controllerName = config.controller || null;
      this.locals = config.locals || {};
      this.success = config.success || angular.noop;
      this.error = config.error || angular.noop;

      this.resolve(config).then(function (data) {
        angular.forEach(data, function (item, index) {
          scope[self.resolveKeys[index]] = item;
        });
        return self.creatHTML(config);
      }).then(function (data) {
        dataElement = data;
        self.container.append(self.backdrop);
        self.render(data, config);
      });

      scope.ok = function ($event) {
        // 判断controller中点击ok后是否需要进一步处理异步操作(如: 登录)
        // 如果是将会处理这个请求服务之后返回promise对象
        // 以便dialogs.model() 能正常使用then 方法处理请求后的操作
        // 执行操作处理函数是通过config.method 传入处理函数的名称字符串
        // 然后找到controller中对应的处理函数执行
        if (angular.isFunction(scope[method])) {
          scope[method]($event).then(function (data) {
            self.success({
              scope: scope,
              data: data
            });
            defer.resolve({
              scope: scope,
              data: data
            });
          }, function (err) {
            self.error({
              scope: scope,
              err: err
            });
            defer.reject({
              scope: scope,
              err: err
            });
          });
        } else {
          defer.resolve(scope);
        }
      };

      scope.DropCloseDialogs = function () {
        if (angular.isUndefined(config.isBackdropClickClose) || config.isBackdropClickClose) {
          scope.close();
        }
      };

      scope.close = function () {
        self.close();
      };

      scope.cancel = function () {
        scope.close();
        defer.reject();
      };
      return defer.promise;
    };

    /**
     * 基础弹出框
     * @param   {object} confg 弹出框配置
     * @returns {object} promise
     */
    Dialogs.prototype.alert = function (confg) {
      var config = confg || {};
      var cof = angular.extend(config, {
        dialogHeader: '
' + (config.title || '温馨提示') + '
',
        dialogFooter: '<button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="ok($event)">确定</button>'
      });
      return this.modal(cof);
    };

    /**
     * 确认弹出框
     * @param   {object} confg 配置对象
     * @returns {object} promise
     */
    Dialogs.prototype.confirm = function (confg) {
      var config = confg || {};
      var cof = angular.extend(config, {
        dialogHeader: '
' + (config.title || '温馨提示') + '
',
        dialogFooter: '<button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="ok($event)">确定</button><button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="cancel($event)">取消</button>'
      });
      return this.modal(cof);
    };

    /**
     * 关闭弹框方法
     * @returns {Dialogs}
     */
    Dialogs.prototype.close = function () {
      if (this.backdrop && angular.isFunction(this.backdrop.remove)) {
        $animate.removeClass(this.backdrop, this.config.backdropClass, function () {
          this.backdrop.remove();
          this.backdrop = null;
        }.bind(this));
      }

      if (this.element && angular.isFunction(this.element.remove)) {
        $animate.leave(this.element, function () {
          this.element = null;
          this.scope.$destroy();
        }.bind(this));
      }
      return this;
    };

    return new Dialogs();
  });
<commit_msg>fix: 修复dialog不支持遮罩触发回调<commit_after>/*global require, angular*/

/**
 * [dialog 弹窗服务]
 *
 * @author zhoul
 * @description
 * dialog 弹窗服务
 *
 * 方法：
 *  confirm： 确认框
 *  alert:    确定框
 *  modal:    自定义弹窗
 *
 * 弹框参数：
 *  title：弹出标题模板
 *  template： 显示模板
 *  templateUrl: 模板地址
 *  className： 弹出类名
 *  backdropClass：遮罩层类名
 *  success： 用户自定义模板的时候点击确定 请求某个服务端接口 成功执行的回调
 *  error： 用户自定义模板的时候点击确定 请求某个服务端接口 失败执行的回调
 *  resolves： 弹出之前需要处理的一些依赖
 *  controllerAs：用于支持as语法
 *  controller: 用户自定义模板的时候 可以添加控制器 处理自定义的模板
 *  container：弹窗组append的DOM
 *  locals：一些数据可在自定义模板的控制器中依赖注入
 *
 * @example
 * 确认框
 * dialogs.confirm({
 *    template: '
确认删除？
'
 * })
 * .then(function () {
 *    alert("您点了确认");
 *    dialogs.close();
 * }, function(){
 *    alert("您点了取消");
 *    dialogs.close();
 * });
 *
 * @example
 * 确定框
 * dialogs.alert({
 *    template: '
确认删除？
'
 * })
 * .then(function(){
 *    dialogs.close();
 * })
 *
 * @example
 * 自定义弹窗
 * dialogs.modal({
 *  method: 'login',
 *  className: 'login-from',
 *  backdropClass: 'in',
 *  templateUrl: loginV2Tmp,
 *  success: function (data) {
 *    var result = data.data.data;
 *    alert('tick')
 *  },
 *  controller: 'loginCtrl'
 * })
 */
angular
  .module('jmui.dialog', [])
  .service('dialogs', function ($document, $compile, $q, $http, $rootScope, $controller, $animate, $templateCache) {
    /**
     * 弹出框构造函数
     * @description 一个弹出框服务用于模拟window的alert、confirm 以及自定义模版的弹出框
     * @class Dialogs
     */
    function Dialogs() {
      this.resolveKeys = [];
      this.scope = {};
      this.locals = {};
      this.element = null;
      this.resolves = [];
      this.controllerName = '';
    }

    /**
     * 创建模版
     * @param   {object}  config 初始配置
     * @returns {object} promise对象
     */
    Dialogs.prototype.creatHTML = function (config) {
      var header = '',
        footer = '',
        template = '
' + (config.template) + '
',
        templateUrl = config.templateUrl,
        defer = $q.defer(),
        backdrop = angular.element('

'),
        dialogBox = angular.element('
' + (config.isShowCloseIcon ? '×

' : ''));

      this.backdrop = angular.element('

');

      if (config.dialogHeader) {
        header = '
' + config.dialogHeader + '
';
      }

      if (config.dialogFooter) {
        footer = '
' + config.dialogFooter + '
';
      }
      if (templateUrl) {
        $http.get(templateUrl, {
          cache: $templateCache
        }).then(function (response) {
          defer.resolve(backdrop.append(dialogBox.append(response.data)));
        });
      } else {
        return $q.when(backdrop.append(dialogBox.append((header + template + footer))));
      }
      return defer.promise;
    };

    /**
     * 依赖方法 弹出框依赖的数据在没有得到的时候将不会显示弹出
     * @param   {object} config 配置对象
     * @returns {object} promise 对象
     */
    Dialogs.prototype.resolve = function (config) {
      var resolves = config.resolve,
        attr;

      if (angular.isObject(resolves)) {

        for (attr in resolves) {
          if (resolves.hasOwnProperty(attr)) {
            this.resolveKeys.push(attr);
            this.resolves.push(config.resolve[attr]());
          }
        }
      }
      return $q.all(this.resolves);
    };

    /**
     * 编译模版并添加到指定的Dom中
     * @param   {object} data   传入到弹出框中的数据对象
     * @param   {object} config 配置文件
     * @returns {object} Dom    对象
     */
    Dialogs.prototype.render = function (data, config) {
      var scope = this.scope,
        ctrl,
        prop;

      this.element = angular.element(data);

      if (this.controllerName) {
        this.locals.$scope = scope;
        ctrl = $controller(this.controllerName, this.locals);
        if (this.controllerAs) {
          scope[this.controllerAs] = ctrl;
        } else if (this.locals) {
          for (prop in this.locals) {
            if (this.locals.hasOwnProperty(prop)) {
              scope[prop] = this.locals[prop];
            }
          }
        }
      }
      $compile(this.element)(scope);
      $animate.enter(this.element, this.container);
      $animate.addClass(this.backdrop, config.backdropClass || '');
    };

    /**
     * 弹出框方法
     * @param   {object} conf 配置对象
     * @returns {object} promise
     */
    Dialogs.prototype.modal = function (conf) {
      var config = conf || {};
      var scope = this.scope = $rootScope.$new(true);

      console.log(scope);

      var defer = $q.defer();
      var self = this;
      var method = config.method;
      var dataElement = null;

      this.config = config;
      this.container = angular.element(config.container || document.body);
      this.controllerAs = config.controllerAs;
      this.controllerName = config.controller || null;
      this.locals = config.locals || {};
      this.success = config.success || angular.noop;
      this.error = config.error || angular.noop;

      this.resolve(config).then(function (data) {
        angular.forEach(data, function (item, index) {
          scope[self.resolveKeys[index]] = item;
        });
        return self.creatHTML(config);
      }).then(function (data) {
        dataElement = data;
        self.container.append(self.backdrop);
        self.render(data, config);
      });

      scope.ok = function ($event) {
        // 判断controller中点击ok后是否需要进一步处理异步操作(如: 登录)
        // 如果是将会处理这个请求服务之后返回promise对象
        // 以便dialogs.model() 能正常使用then 方法处理请求后的操作
        // 执行操作处理函数是通过config.method 传入处理函数的名称字符串
        // 然后找到controller中对应的处理函数执行
        if (angular.isFunction(scope[method])) {
          scope[method]($event).then(function (data) {
            self.success({
              scope: scope,
              data: data
            });
            defer.resolve({
              scope: scope,
              data: data
            });
          }, function (err) {
            self.error({
              scope: scope,
              err: err
            });
            defer.reject({
              scope: scope,
              err: err
            });
          });
        } else {
          defer.resolve(scope);
        }
      };

      scope.DropCloseDialogs = function () {
        if (angular.isUndefined(config.isBackdropClickClose) || config.isBackdropClickClose) {
          scope.close();
        }
      };

      scope.close = function () {
        scope.cancel();
      };

      scope.cancel = function () {
        self.close();
        defer.reject();
      };
      return defer.promise;
    };

    /**
     * 基础弹出框
     * @param   {object} confg 弹出框配置
     * @returns {object} promise
     */
    Dialogs.prototype.alert = function (confg) {
      var config = confg || {};
      var cof = angular.extend(config, {
        dialogHeader: '
' + (config.title || '温馨提示') + '
',
        dialogFooter: '<button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="ok($event)">确定</button>'
      });
      return this.modal(cof);
    };

    /**
     * 确认弹出框
     * @param   {object} confg 配置对象
     * @returns {object} promise
     */
    Dialogs.prototype.confirm = function (confg) {
      var config = confg || {};
      var cof = angular.extend(config, {
        dialogHeader: '
' + (config.title || '温馨提示') + '
',
        dialogFooter: '<button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="ok($event)">确定</button><button class="jm-btn jm-btn-sm jm-btn-primary " ng-click="cancel($event)">取消</button>'
      });
      return this.modal(cof);
    };

    /**
     * 关闭弹框方法
     * @returns {Dialogs}
     */
    Dialogs.prototype.close = function () {
      if (this.backdrop && angular.isFunction(this.backdrop.remove)) {
        $animate.removeClass(this.backdrop, this.config.backdropClass, function () {
          this.backdrop.remove();
          this.backdrop = null;
        }.bind(this));
      }

      if (this.element && angular.isFunction(this.element.remove)) {
        $animate.leave(this.element, function () {
          this.element = null;
          this.scope.$destroy();
        }.bind(this));
      }
      return this;
    };

    return new Dialogs();
  });
<|endoftext|>


<commit_before>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var mergeTrees = require('broccoli-merge-trees');
var concatFiles = require('broccoli-concat');
var path = require('path');
var jsStringEscape = require('js-string-escape');
var eslint = require('broccoli-lint-eslint');
var stew = require('broccoli-stew');
var writeFile = require('broccoli-file-creator');
var replace = require('broccoli-string-replace');
var esTranspiler = require('broccoli-babel-transpiler');
var moduleResolver = require('amd-name-resolver').resolveModules({ throwOnRootAccess: false });
var Funnel = require('broccoli-funnel');
var packageJson = require('./package.json');

var mv = stew.mv;
var map = stew.map;

/*global process */

var options = {
  fingerprint: {
    enabled: false
  },
  babel: {
    // async/await
    optional: ['es7.asyncFunctions']
  }
};

function renderErrors(errors) {
  if (!errors) { return ''; }
  return errors.map(function(error) {
    return error.line + ':' + error.column + ' ' +
      ' - ' + error.message + ' (' + error.ruleId +')';
  }).join('\n');
}

function eslintTestGenerator(relativePath, errors) {
  var pass = !errors || errors.length === 0;
  return "import { module, test } from 'qunit';\n" +
    "module('ESLINT - " + path.dirname(relativePath) + "');\n" +
    "test('" + relativePath + " should pass eslint', function(assert) {\n" +
    "  assert.ok(" + pass + ", '" + relativePath + " should pass eslint." +
    jsStringEscape("\n" + renderErrors(errors)) + "');\n" +
   "});\n";
}

// Firefox requires non-minified assets for review :(
options.minifyJS = { enabled: false };
options.minifyCSS = { enabled: false };

module.exports = function(defaults) {
  var app = new EmberApp(defaults, options);

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.
  //
  var env = process.env.EMBER_ENV;

  if (env !== 'production') {
    // To be able to compile htmlbars templates in tests
    app.import('bower_components/ember/ember-template-compiler.js');
  }

  app.import('vendor/babel-polyfill.js', { prepend: true });
  app.import('bower_components/contextMenu/contextMenu.js');
  app.import('bower_components/contextMenu/contextMenu.css');

  // Ember Debug

  var emberDebug = 'ember_debug';

  emberDebug = new Funnel(emberDebug, {
    destDir: 'ember-debug',
    include: ['**/*.js'],
    exclude: [
      'vendor/loader.js',
      'vendor/source-map.js',
      'vendor/startup-wrapper.js',
    ]
  });

  if (env === 'test') {
    var linted = eslint(emberDebug, {
      testGenerator: eslintTestGenerator,
      options: {
        configFile: './ember_debug/.eslintrc.js',
        rulePaths: ['./']
      }
    });
    emberDebug = mergeTrees([emberDebug, linted]);
  }

  emberDebug = esTranspiler(emberDebug, {
    moduleIds: true,
    modules: 'amdStrict',
    resolveModuleSource: moduleResolver,
  });

  var previousEmberVersionsSupportedString = '[' + packageJson.previousEmberVersionsSupported.map(function(item) {
    return "'" + item + "'";
  }).join(',') + ']';
  var emberVersionsSupportedString = '[' + packageJson.emberVersionsSupported.map(function(item) {
    return "'" + item + "'";
  }).join(',') + ']';

  var startupWrapper = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['startup-wrapper.js'],
  });

  startupWrapper = replace(startupWrapper, {
    files: ['startup-wrapper.js'],
    patterns: [{
      match: /{{EMBER_VERSIONS_SUPPORTED}}/,
      replacement: emberVersionsSupportedString
    }]
  });

  var sourceMap = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['source-map.js'],
  });

  var loader = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['loader.js'],
  });

  sourceMap = map(sourceMap, '**/*.js', function(content) {
    return "(function() {\n" + content + "\n}());";
  });

  emberDebug = mergeTrees([loader, startupWrapper, sourceMap, emberDebug]);

  emberDebug = concatFiles(emberDebug, {
    headerFiles: ['loader.js'],
    inputFiles: ['**/*.js'],
    outputFile: '/ember_debug.js'
  });

  var emberDebugs = [];
  ['basic', 'chrome', 'firefox', 'bookmarklet', 'websocket'].forEach(function(dist) {
    emberDebugs[dist] = map(emberDebug, '**/*.js', function(content) {
      return "(function(adapter, env) {\n" + content + "\n}('" + dist + "', '" + env + "'));";
    });
  });

  var tree = app.toTree();

  var emberInspectorVersionPattern = [{
    match: /{{EMBER_INSPECTOR_VERSION}}/g,
    replacement: packageJson.version
  }];

  tree = replace(tree, {
    files: ['**/*.js'],
    patterns: emberInspectorVersionPattern
  });

  var minimumVersion = packageJson.emberVersionsSupported[0].replace(/\./g, '-');
  var chromeRoot = 'panes-' + minimumVersion;
  var firefoxRoot = 'data/' + chromeRoot;

  var firefoxAndChromeExtra = new Funnel('shared', {
    files: ['in-page-script.js'],
  });

  var replacementPattern = [{
    match: /{{env}}/,
    replacement: env === 'development' ? ' [DEV]' : ''
  }, {
    match: /{{PANE_ROOT}}/g,
    replacement: 'panes-' + minimumVersion
  }, {
    match: /{{PREVIOUS_EMBER_VERSIONS_SUPPORTED}}/g,
    replacement: previousEmberVersionsSupportedString
  }, {
    match: /{{EMBER_VERSIONS_SUPPORTED}}/g,
    replacement: emberVersionsSupportedString
  }];

  replacementPattern = replacementPattern.concat(emberInspectorVersionPattern);

  var skeletonChrome = replace('skeletons/chrome', {
    files: ['*'],
    patterns: replacementPattern
  });

  var skeletonFirefox = replace('skeletons/firefox', {
    files: ['*', '*/**'],
    patterns: replacementPattern
  });

  var skeletonBookmarklet = replace('skeletons/bookmarklet', {
    files: ['*'],
    patterns: replacementPattern
  });

  var firefox = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.firefox]), firefoxRoot),
    skeletonFirefox
  ]);

  var chrome = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.chrome]), chromeRoot),
    skeletonChrome
  ]);

  var bookmarklet = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.bookmarklet]), chromeRoot),
    skeletonBookmarklet
  ]);

  packageJson.previousEmberVersionsSupported.forEach(function(version) {
    version = version.replace(/\./g, '-');
    if (env === 'production') {
      var prevDist = 'dist_prev/' + env;

      bookmarklet = mergeTrees([
        mv(prevDist + '/bookmarklet/panes-' + version, 'panes-' + version),
        bookmarklet
      ]);
      firefox = mergeTrees([
        mv(prevDist + '/firefox/panes-' + version, 'data/panes-' + version),
        firefox
      ]);
      chrome = mergeTrees([
        mv(prevDist + '/chrome/panes-' + version, 'panes-' + version),
        chrome
      ]);
    } else {
      var file = writeFile('index.html', "This Ember version is not supported in development environment.");
      var emberDebugFile = writeFile('ember_debug.js', 'void(0);');
      chrome = mergeTrees([mv(file, 'panes-' + version), chrome]);
      firefox = mergeTrees([mv(file, 'data/panes-' + version), mv(emberDebugFile, 'data/panes-' + version), firefox]);
      bookmarklet = mergeTrees([mv(file, 'panes-' + version), mv(emberDebugFile, 'panes-' + version), bookmarklet]);
    }
  });

  firefox = mergeTrees([
    mv(firefoxAndChromeExtra, 'data/scripts'),
    firefox
  ]);

  chrome = mergeTrees([
    mv(firefoxAndChromeExtra, 'scripts'),
    chrome
  ]);

  // Pass the current dist to the Ember Inspector app.
  // EMBER DIST
  var dists = {
    chrome: chrome,
    firefox: firefox,
    bookmarklet: bookmarklet,
    websocket: mergeTrees([tree, emberDebugs.websocket]),
    basic: mergeTrees([tree, emberDebugs.basic])
  };
  Object.keys(dists).forEach(function(key) {
    dists[key] = replace(dists[key], {
      files: ['**/*.js'],
      patterns: [{
        match: /{{EMBER_DIST}}/g,
        replacement: key
      }]
    });
  });

  // Add {{ remote-port }} to the head
  // so that the websocket addon can replace it.
  dists.websocket = replace(dists.websocket, {
    files: ['index.html'],
    patterns: [{
      match: /<head>/,
      replacement: '<head>\n{{ remote-port }}\n'
    }]
  });

  var output;

  if (env === 'test') {
    // `ember test` expects the index.html file to be in the
    // output directory.
    output = dists.basic;
  } else {

    // Change base tag for running tests in development env.
    dists.basic = replace(dists.basic, {
      files: ['tests/index.html'],
      patterns: [{
        match: /<base.*\/>/,
        replacement: '<base href="../" />'
      }]
    });

    output = mergeTrees([
      mv(dists.bookmarklet, 'bookmarklet'),
      mv(dists.firefox, 'firefox'),
      mv(dists.chrome, 'chrome'),
      mv(dists.websocket, 'websocket'),
      mv(dists.basic, 'testing')
    ]);
  }

  return output;
};
<commit_msg>Disable source map for ember_debug.js<commit_after>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var mergeTrees = require('broccoli-merge-trees');
var concatFiles = require('broccoli-concat');
var path = require('path');
var jsStringEscape = require('js-string-escape');
var eslint = require('broccoli-lint-eslint');
var stew = require('broccoli-stew');
var writeFile = require('broccoli-file-creator');
var replace = require('broccoli-string-replace');
var esTranspiler = require('broccoli-babel-transpiler');
var moduleResolver = require('amd-name-resolver').resolveModules({ throwOnRootAccess: false });
var Funnel = require('broccoli-funnel');
var packageJson = require('./package.json');

var mv = stew.mv;
var map = stew.map;

/*global process */

var options = {
  fingerprint: {
    enabled: false
  },
  babel: {
    // async/await
    optional: ['es7.asyncFunctions']
  }
};

function renderErrors(errors) {
  if (!errors) { return ''; }
  return errors.map(function(error) {
    return error.line + ':' + error.column + ' ' +
      ' - ' + error.message + ' (' + error.ruleId +')';
  }).join('\n');
}

function eslintTestGenerator(relativePath, errors) {
  var pass = !errors || errors.length === 0;
  return "import { module, test } from 'qunit';\n" +
    "module('ESLINT - " + path.dirname(relativePath) + "');\n" +
    "test('" + relativePath + " should pass eslint', function(assert) {\n" +
    "  assert.ok(" + pass + ", '" + relativePath + " should pass eslint." +
    jsStringEscape("\n" + renderErrors(errors)) + "');\n" +
   "});\n";
}

// Firefox requires non-minified assets for review :(
options.minifyJS = { enabled: false };
options.minifyCSS = { enabled: false };

module.exports = function(defaults) {
  var app = new EmberApp(defaults, options);

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.
  //
  var env = process.env.EMBER_ENV;

  if (env !== 'production') {
    // To be able to compile htmlbars templates in tests
    app.import('bower_components/ember/ember-template-compiler.js');
  }

  app.import('vendor/babel-polyfill.js', { prepend: true });
  app.import('bower_components/contextMenu/contextMenu.js');
  app.import('bower_components/contextMenu/contextMenu.css');

  // Ember Debug

  var emberDebug = 'ember_debug';

  emberDebug = new Funnel(emberDebug, {
    destDir: 'ember-debug',
    include: ['**/*.js'],
    exclude: [
      'vendor/loader.js',
      'vendor/source-map.js',
      'vendor/startup-wrapper.js',
    ]
  });

  if (env === 'test') {
    var linted = eslint(emberDebug, {
      testGenerator: eslintTestGenerator,
      options: {
        configFile: './ember_debug/.eslintrc.js',
        rulePaths: ['./']
      }
    });
    emberDebug = mergeTrees([emberDebug, linted]);
  }

  emberDebug = esTranspiler(emberDebug, {
    moduleIds: true,
    modules: 'amdStrict',
    resolveModuleSource: moduleResolver
  });

  var previousEmberVersionsSupportedString = '[' + packageJson.previousEmberVersionsSupported.map(function(item) {
    return "'" + item + "'";
  }).join(',') + ']';
  var emberVersionsSupportedString = '[' + packageJson.emberVersionsSupported.map(function(item) {
    return "'" + item + "'";
  }).join(',') + ']';

  var startupWrapper = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['startup-wrapper.js'],
  });

  startupWrapper = replace(startupWrapper, {
    files: ['startup-wrapper.js'],
    patterns: [{
      match: /{{EMBER_VERSIONS_SUPPORTED}}/,
      replacement: emberVersionsSupportedString
    }]
  });

  var sourceMap = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['source-map.js'],
  });

  var loader = new Funnel('ember_debug', {
    srcDir: 'vendor',
    files: ['loader.js'],
  });

  sourceMap = map(sourceMap, '**/*.js', function(content) {
    return "(function() {\n" + content + "\n}());";
  });

  emberDebug = mergeTrees([loader, startupWrapper, sourceMap, emberDebug]);

  emberDebug = concatFiles(emberDebug, {
    headerFiles: ['loader.js'],
    inputFiles: ['**/*.js'],
    outputFile: '/ember_debug.js',
    sourceMapConfig: { enabled: false }
  });

  var emberDebugs = [];
  ['basic', 'chrome', 'firefox', 'bookmarklet', 'websocket'].forEach(function(dist) {
    emberDebugs[dist] = map(emberDebug, '**/*.js', function(content) {
      return "(function(adapter, env) {\n" + content + "\n}('" + dist + "', '" + env + "'));";
    });
  });

  var tree = app.toTree();

  var emberInspectorVersionPattern = [{
    match: /{{EMBER_INSPECTOR_VERSION}}/g,
    replacement: packageJson.version
  }];

  tree = replace(tree, {
    files: ['**/*.js'],
    patterns: emberInspectorVersionPattern
  });

  var minimumVersion = packageJson.emberVersionsSupported[0].replace(/\./g, '-');
  var chromeRoot = 'panes-' + minimumVersion;
  var firefoxRoot = 'data/' + chromeRoot;

  var firefoxAndChromeExtra = new Funnel('shared', {
    files: ['in-page-script.js'],
  });

  var replacementPattern = [{
    match: /{{env}}/,
    replacement: env === 'development' ? ' [DEV]' : ''
  }, {
    match: /{{PANE_ROOT}}/g,
    replacement: 'panes-' + minimumVersion
  }, {
    match: /{{PREVIOUS_EMBER_VERSIONS_SUPPORTED}}/g,
    replacement: previousEmberVersionsSupportedString
  }, {
    match: /{{EMBER_VERSIONS_SUPPORTED}}/g,
    replacement: emberVersionsSupportedString
  }];

  replacementPattern = replacementPattern.concat(emberInspectorVersionPattern);

  var skeletonChrome = replace('skeletons/chrome', {
    files: ['*'],
    patterns: replacementPattern
  });

  var skeletonFirefox = replace('skeletons/firefox', {
    files: ['*', '*/**'],
    patterns: replacementPattern
  });

  var skeletonBookmarklet = replace('skeletons/bookmarklet', {
    files: ['*'],
    patterns: replacementPattern
  });

  var firefox = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.firefox]), firefoxRoot),
    skeletonFirefox
  ]);

  var chrome = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.chrome]), chromeRoot),
    skeletonChrome
  ]);

  var bookmarklet = mergeTrees([
    mv(mergeTrees([tree, emberDebugs.bookmarklet]), chromeRoot),
    skeletonBookmarklet
  ]);

  packageJson.previousEmberVersionsSupported.forEach(function(version) {
    version = version.replace(/\./g, '-');
    if (env === 'production') {
      var prevDist = 'dist_prev/' + env;

      bookmarklet = mergeTrees([
        mv(prevDist + '/bookmarklet/panes-' + version, 'panes-' + version),
        bookmarklet
      ]);
      firefox = mergeTrees([
        mv(prevDist + '/firefox/panes-' + version, 'data/panes-' + version),
        firefox
      ]);
      chrome = mergeTrees([
        mv(prevDist + '/chrome/panes-' + version, 'panes-' + version),
        chrome
      ]);
    } else {
      var file = writeFile('index.html', "This Ember version is not supported in development environment.");
      var emberDebugFile = writeFile('ember_debug.js', 'void(0);');
      chrome = mergeTrees([mv(file, 'panes-' + version), chrome]);
      firefox = mergeTrees([mv(file, 'data/panes-' + version), mv(emberDebugFile, 'data/panes-' + version), firefox]);
      bookmarklet = mergeTrees([mv(file, 'panes-' + version), mv(emberDebugFile, 'panes-' + version), bookmarklet]);
    }
  });

  firefox = mergeTrees([
    mv(firefoxAndChromeExtra, 'data/scripts'),
    firefox
  ]);

  chrome = mergeTrees([
    mv(firefoxAndChromeExtra, 'scripts'),
    chrome
  ]);

  // Pass the current dist to the Ember Inspector app.
  // EMBER DIST
  var dists = {
    chrome: chrome,
    firefox: firefox,
    bookmarklet: bookmarklet,
    websocket: mergeTrees([tree, emberDebugs.websocket]),
    basic: mergeTrees([tree, emberDebugs.basic])
  };
  Object.keys(dists).forEach(function(key) {
    dists[key] = replace(dists[key], {
      files: ['**/*.js'],
      patterns: [{
        match: /{{EMBER_DIST}}/g,
        replacement: key
      }]
    });
  });

  // Add {{ remote-port }} to the head
  // so that the websocket addon can replace it.
  dists.websocket = replace(dists.websocket, {
    files: ['index.html'],
    patterns: [{
      match: /<head>/,
      replacement: '<head>\n{{ remote-port }}\n'
    }]
  });

  var output;

  if (env === 'test') {
    // `ember test` expects the index.html file to be in the
    // output directory.
    output = dists.basic;
  } else {

    // Change base tag for running tests in development env.
    dists.basic = replace(dists.basic, {
      files: ['tests/index.html'],
      patterns: [{
        match: /<base.*\/>/,
        replacement: '<base href="../" />'
      }]
    });

    output = mergeTrees([
      mv(dists.bookmarklet, 'bookmarklet'),
      mv(dists.firefox, 'firefox'),
      mv(dists.chrome, 'chrome'),
      mv(dists.websocket, 'websocket'),
      mv(dists.basic, 'testing')
    ]);
  }

  return output;
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Loader from '../Loader/Loader'
import Paper from 'material-ui/Paper'
import { Link } from 'react-router'
import CatalogPreview from './CatalogPreview/CatalogPreview'
import LastHarvesting from '../LastHarvesting/LastHarvesting'
import { fetchMetrics } from '../fetch/fetch';
import { waitForDataAndSetState, cancelAllPromises } from '../helpers/components';

class Catalog extends Component {
  constructor(props) {
    super(props)
    this.state = {errors: []}
  }

  componentWillMount() {
    return waitForDataAndSetState(fetchMetrics(this.props.catalog.id), this, 'metrics');
  }

  componentWillUnmount() {
    return cancelAllPromises(this)
  }

  render() {
      const catalogPreview = <CatalogPreview metrics={this.state.metrics} />
      const styles = {
        link: {
          cursor: 'pointer',
          margin: '1em 3em 1em 3em',
        },
      }
      return (
          <Link to={`/catalogs/${this.props.catalog.id}`} style={styles.link}>
            <Paper rounded={true} zDepth={2}>
              <LastHarvesting style={styles.ribbon} harvest={this.props.catalog.lastHarvesting}/>

                {this.props.catalog.name}
                <Loader value={this.state.metrics} component={catalogPreview}/>

            </Paper>
          </Link>
      )
  }
}

export default Catalog
<commit_msg>Flex Catalog Component<commit_after>import React, { Component } from 'react'
import Loader from '../Loader/Loader'
import Paper from 'material-ui/Paper'
import { Link } from 'react-router'
import CatalogPreview from './CatalogPreview/CatalogPreview'
import LastHarvesting from '../LastHarvesting/LastHarvesting'
import { fetchMetrics } from '../fetch/fetch';
import { waitForDataAndSetState, cancelAllPromises } from '../helpers/components';

class Catalog extends Component {
  constructor(props) {
    super(props)
    this.state = {errors: []}
  }

  componentWillMount() {
    return waitForDataAndSetState(fetchMetrics(this.props.catalog.id), this, 'metrics');
  }

  componentWillUnmount() {
    return cancelAllPromises(this)
  }

  render() {
      const catalogPreview = <CatalogPreview metrics={this.state.metrics} />
      const styles = {
        link: {
          cursor: 'pointer',
          margin: '1em 3em 1em 3em',
          position: 'relative',
        },
        ribbon: {
          position: 'absolute',
          top: '1em',
          left: '-14px',
        },
        stats: {
          display: 'flex',
          felxWrap: 'wrap',
          justifyContent: 'space-around',
          alignItems: 'center',
        },
        title: {
          position: 'relative',
          justifyContent: 'center',
          width: '30%',
          top: '20px',
        },
      }
      return (
          <Link to={`/catalogs/${this.props.catalog.id}`} style={styles.link}>
            <Paper rounded={true} zDepth={2}>
              <LastHarvesting style={styles.ribbon} harvest={this.props.catalog.lastHarvesting}/>

                {this.props.catalog.name}
                <Loader value={this.state.metrics} component={catalogPreview}/>

            </Paper>
          </Link>
      )
  }
}

export default Catalog
<|endoftext|>


<commit_before>(function (global) {
	var segments
		,i;

	function getStyle(el, style) {
		return window.getComputedStyle(el).getPropertyCSSValue(style).cssText;
	}

	function cycle (el, callback) {
		var tweenable
			,originalLeft

		function toTheLeftToTheLeft (callback) {
			tweenable.to({
				'to': {
					'left': '300px'
				}

				,'duration': 1000

				,'easing': 'easeInOutSine'

				,'step': function step () {
					el.style.left = this['left'];
				}

				,'callback': callback
			});
		}

		function toTheRightToTheRight (callback) {
			tweenable.to({
				'to': {
					'left': originalLeft
				}

				,'duration': 1000

				,'easing': 'easeInOutSine'

				,'step': function step () {
					el.style.left = this['left'];
				}

				,'callback': callback
			});
		}

		function loop () {
			toTheLeftToTheLeft(function () {
				toTheRightToTheRight(loop);
			});
		}

		originalLeft = getStyle(el, 'left');

		tweenable = new Tweenable({
			'initialState': {
				'left': originalLeft
			}
			,'fps': 30
		});

		loop();
	}

	segments = document.getElementsByClassName('segment');

	for (i = 0; i < segments.length; i++) {
		(function (i) {
			setTimeout(function () {
				cycle(segments[i]);
			}, 30 * i);
		} (i));
	}

} (this));<commit_msg>Made the helix demo stop looping.<commit_after>(function (global) {
	var segments
		,i;

	function getStyle(el, style) {
		return window.getComputedStyle(el).getPropertyCSSValue(style).cssText;
	}

	function cycle (el, callback) {
		var tweenable
			,originalLeft

		function toTheLeftToTheLeft (callback) {
			tweenable.queue({
				'to': {
					'left': '300px'
				}

				,'duration': 1500

				,'easing': 'easeInOutSine'

				,'step': function step () {
					el.style.left = this['left'];
				}

				,'callback': callback
			}).queue({
				'to': {
					'left': originalLeft
				}

				,'duration': 1500

				,'easing': 'easeInOutSine'

				,'step': function step () {
					el.style.left = this['left'];
				}

				,'callback': callback
			})
		}

		originalLeft = getStyle(el, 'left');

		tweenable = new Tweenable({
			'initialState': {
				'left': originalLeft
			}
			,'fps': 30
		});

		toTheLeftToTheLeft();
	}

	segments = document.getElementsByClassName('segment');

	for (i = 0; i < segments.length; i++) {
		(function (i) {
			setTimeout(function () {
				cycle(segments[i]);
			}, (30 * i));
		} (i));
	}

} (this));<|endoftext|>


<commit_before>openerp_mail_followers = function(session, mail) {
    var _t = session.web._t,
       _lt = session.web._lt;

    var mail_followers = session.mail_followers = {};

    /**
     * ------------------------------------------------------------
     * mail_followers Widget
     * ------------------------------------------------------------
     *
     * This widget handles the display of a list of records as a vertical
     * list, with an image on the left. The widget itself is a floatting
     * right-sided box.
     * This widget is mainly used to display the followers of records
     * in OpenChatter.
     */

    /* Add the widget to registry */
    session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers');

    mail_followers.Followers = session.web.form.AbstractField.extend({
        template: 'mail.followers',

        init: function() {
            this._super.apply(this, arguments);
            this.image = this.node.attrs.image || 'image_small';
            this.comment = this.node.attrs.help || false;
            this.displayed_nb = this.node.attrs.displayed_nb || 10;
            this.ds_model = new session.web.DataSetSearch(this, this.view.model);
            this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
            this.ds_users = new session.web.DataSetSearch(this, 'res.users');

            this.value = [];
        },

        start: function() {
            // use actual_mode property on view to know if the view is in create mode anymore
            this.view.on("change:actual_mode", this, this.on_check_visibility_mode);
            this.on_check_visibility_mode();
            this.reinit();
            this.bind_events();
            this._super();
        },

        on_check_visibility_mode: function () {
            this.set({"force_invisible": this.view.get("actual_mode") == "create"});
        },

        set_value: function(_value) {
            this.value = _value;
            this._super(_value);
        },

        reinit: function() {
            this.message_is_follower == undefined;
            this.display_buttons();
        },

        bind_events: function() {
            var self = this;
            // event: click on '(Un)Follow' button, that toggles the follow for uid
            this.$('.oe_follower').on('click', function (event) {
                if($(this).hasClass('oe_notfollow'))
                    self.do_follow();
                else
                    self.do_unfollow();
            });
            // event: click on a subtype, that (un)subscribe for this subtype
            this.$el.on('click', '.oe_subtype_list input', self.do_update_subscription);
            // event: click on 'invite' button, that opens the invite wizard
            this.$('.oe_invite').on('click', function (event) {
                action = {
                    type: 'ir.actions.act_window',
                    res_model: 'mail.wizard.invite',
                    view_mode: 'form',
                    view_type: 'form',
                    views: [[false, 'form']],
                    target: 'new',
                    context: {
                        'default_res_model': self.view.dataset.model,
                        'default_res_id': self.view.datarecord.id,
                    },
                }
                self.do_action(action, {
                    on_close: function() {
                        self.read_value();
                    },
                });
            });
        },

        read_value: function () {
            var self = this;
            return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
                self.value = results[0].message_follower_ids;
                self.render_value();
            });
        },

        render_value: function () {
            this.reinit();
            return this.fetch_followers(this.value);
        },

        fetch_followers: function (value_) {
            this.value = value_ || {};
            return this.ds_follow.call('read', [this.value, ['name', 'user_ids']])
                .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
                .then(this.proxy('display_buttons'))
                .then(this.proxy('fetch_subtypes'));
        },

        /** Read on res.partner failed: fall back on a generic case
            - fetch current user partner_id (call because no other smart solution currently) FIXME
            - then display a generic message about followers */
        fetch_generic: function (error, event) {
            var self = this;
            event.preventDefault();
            return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
                var pid = results['partner_id'][0];
                self.message_is_follower = (_.indexOf(self.value, pid) != -1);
            }).then(self.proxy('display_generic'));
        },
        _format_followers: function(count){
            // TDE note: why redefining _t ?
            function _t(str) { return str; }
            var str = '';
            if(count <= 0){
                str = _t('No followers');
            }else if(count === 1){
                str = _t('One follower');
            }else{
                str = ''+count+' '+_t('followers');
            }
            return str;
        },
        /* Display generic info about follower, for people not having access to res_partner */
        display_generic: function () {
            var self = this;
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.value.length));
        },

        /** Display the followers */
        display_followers: function (records) {
            var self = this;
            records = records || [];
            this.message_is_follower = this.set_is_follower(records);
            // clean and display title
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(records.length));
            // truncate number of displayed followers
            truncated = records.splice(0, this.displayed_nb);
            _(truncated).each(function (record) {
                record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
                $(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
            });
            // FVA note: be sure it is correctly translated
            if (truncated.length < records.length) {
                $('
And ' + (records.length - truncated.length) + ' more.
').appendTo(node_user_list);
            }
        },

        /** Computes whether the current user is in the followers */
        set_is_follower: function (records) {
            var user_ids = _.pluck(_.pluck(records, 'user_ids'), 0);
            return _.indexOf(user_ids, this.session.uid) != -1;
        },

        display_buttons: function () {
            if (this.message_is_follower) {
                this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
            }
            else {
                this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
            }

            if (this.view.is_action_enabled('edit'))
                this.$('span.oe_mail_invite_wrapper').hide();
            else
                this.$('span.oe_mail_invite_wrapper').show();
        },

        /** Fetch subtypes, only if current user is follower */
        fetch_subtypes: function () {
            var subtype_list_ul = this.$('.oe_subtype_list').empty();
            if (! this.message_is_follower) return;
            var context = new session.web.CompoundContext(this.build_context(), {});
            this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).then(this.proxy('display_subtypes'));
        },

        /** Display subtypes: {'name': default, followed} */
        display_subtypes:function (data) {
            var self = this;
            var subtype_list_ul = this.$('.oe_subtype_list');
            subtype_list_ul.empty();
            var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
            _(records).each(function (record, record_name) {
                record.name = record_name;
                record.followed = record.followed || undefined;
                $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
            });
        },

        do_follow: function () {
            _(this.$('.oe_msg_subtype_check')).each(function (record) {
                $(record).attr('checked', 'checked');
            });
            this.do_update_subscription();
        },

        do_unfollow: function () {
            _(this.$('.oe_msg_subtype_check')).each(function (record) {
                $(record).attr('checked',false);
            });
            var context = new session.web.CompoundContext(this.build_context(), {});
            return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
                .then(this.proxy('read_value'));
        },

        do_update_subscription: function (event) {
            var self = this;

            var checklist = new Array();
            _(this.$('.oe_actions input[type="checkbox"]')).each(function (record) {
                if ($(record).is(':checked')) {
                    checklist.push(parseInt($(record).data('id')));
                }
            });

            var context = new session.web.CompoundContext(this.build_context(), {});
            return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist : undefined, context])
                .then(this.proxy('read_value'));
        },
    });
};
<commit_msg>[IMP] mail follower: hide follower subtype if <= 1. unfollow if the user uncheck all subtype<commit_after>openerp_mail_followers = function(session, mail) {
    var _t = session.web._t,
       _lt = session.web._lt;

    var mail_followers = session.mail_followers = {};

    /**
     * ------------------------------------------------------------
     * mail_followers Widget
     * ------------------------------------------------------------
     *
     * This widget handles the display of a list of records as a vertical
     * list, with an image on the left. The widget itself is a floatting
     * right-sided box.
     * This widget is mainly used to display the followers of records
     * in OpenChatter.
     */

    /* Add the widget to registry */
    session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers');

    mail_followers.Followers = session.web.form.AbstractField.extend({
        template: 'mail.followers',

        init: function() {
            this._super.apply(this, arguments);
            this.image = this.node.attrs.image || 'image_small';
            this.comment = this.node.attrs.help || false;
            this.displayed_nb = this.node.attrs.displayed_nb || 10;
            this.ds_model = new session.web.DataSetSearch(this, this.view.model);
            this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
            this.ds_users = new session.web.DataSetSearch(this, 'res.users');

            this.value = [];
        },

        start: function() {
            // use actual_mode property on view to know if the view is in create mode anymore
            this.view.on("change:actual_mode", this, this.on_check_visibility_mode);
            this.on_check_visibility_mode();
            this.reinit();
            this.bind_events();
            this._super();
        },

        on_check_visibility_mode: function () {
            this.set({"force_invisible": this.view.get("actual_mode") == "create"});
        },

        set_value: function(_value) {
            this.value = _value;
            this._super(_value);
        },

        reinit: function() {
            this.message_is_follower == undefined;
            this.display_buttons();
        },

        bind_events: function() {
            var self = this;
            // event: click on '(Un)Follow' button, that toggles the follow for uid
            this.$('.oe_follower').on('click', function (event) {
                if($(this).hasClass('oe_notfollow'))
                    self.do_follow();
                else
                    self.do_unfollow();
            });
            // event: click on a subtype, that (un)subscribe for this subtype
            this.$el.on('click', '.oe_subtype_list input', self.do_update_subscription);
            // event: click on 'invite' button, that opens the invite wizard
            this.$('.oe_invite').on('click', function (event) {
                action = {
                    type: 'ir.actions.act_window',
                    res_model: 'mail.wizard.invite',
                    view_mode: 'form',
                    view_type: 'form',
                    views: [[false, 'form']],
                    target: 'new',
                    context: {
                        'default_res_model': self.view.dataset.model,
                        'default_res_id': self.view.datarecord.id,
                    },
                }
                self.do_action(action, {
                    on_close: function() {
                        self.read_value();
                    },
                });
            });
        },

        read_value: function () {
            var self = this;
            return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
                self.value = results[0].message_follower_ids;
                self.render_value();
            });
        },

        render_value: function () {
            this.reinit();
            return this.fetch_followers(this.value);
        },

        fetch_followers: function (value_) {
            this.value = value_ || {};
            return this.ds_follow.call('read', [this.value, ['name', 'user_ids']])
                .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
                .then(this.proxy('display_buttons'))
                .then(this.proxy('fetch_subtypes'));
        },

        /** Read on res.partner failed: fall back on a generic case
            - fetch current user partner_id (call because no other smart solution currently) FIXME
            - then display a generic message about followers */
        fetch_generic: function (error, event) {
            var self = this;
            event.preventDefault();
            return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
                var pid = results['partner_id'][0];
                self.message_is_follower = (_.indexOf(self.value, pid) != -1);
            }).then(self.proxy('display_generic'));
        },
        _format_followers: function(count){
            // TDE note: why redefining _t ?
            function _t(str) { return str; }
            var str = '';
            if(count <= 0){
                str = _t('No followers');
            }else if(count === 1){
                str = _t('One follower');
            }else{
                str = ''+count+' '+_t('followers');
            }
            return str;
        },
        /* Display generic info about follower, for people not having access to res_partner */
        display_generic: function () {
            var self = this;
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.value.length));
        },

        /** Display the followers */
        display_followers: function (records) {
            var self = this;
            records = records || [];
            this.message_is_follower = this.set_is_follower(records);
            // clean and display title
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(records.length));
            // truncate number of displayed followers
            truncated = records.splice(0, this.displayed_nb);
            _(truncated).each(function (record) {
                record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
                $(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
            });
            // FVA note: be sure it is correctly translated
            if (truncated.length < records.length) {
                $('
And ' + (records.length - truncated.length) + ' more.
').appendTo(node_user_list);
            }
        },

        /** Computes whether the current user is in the followers */
        set_is_follower: function (records) {
            var user_ids = _.pluck(_.pluck(records, 'user_ids'), 0);
            return _.indexOf(user_ids, this.session.uid) != -1;
        },

        display_buttons: function () {
            if (this.message_is_follower) {
                this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
            }
            else {
                this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
            }

            if (this.view.is_action_enabled('edit'))
                this.$('span.oe_mail_invite_wrapper').hide();
            else
                this.$('span.oe_mail_invite_wrapper').show();
        },

        /** Fetch subtypes, only if current user is follower */
        fetch_subtypes: function () {
            var subtype_list_ul = this.$('.oe_subtype_list').empty();
            if (! this.message_is_follower) return;
            var context = new session.web.CompoundContext(this.build_context(), {});
            this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).then(this.proxy('display_subtypes'));
        },

        /** Display subtypes: {'name': default, followed} */
        display_subtypes:function (data) {
            var self = this;
            var subtype_list_ul = this.$('.oe_subtype_list');
            subtype_list_ul.empty();
            var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
            if (records.length > 1) {
                _(records).each(function (record, record_name) {
                    record.name = record_name;
                    record.followed = record.followed || undefined;
                    $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
                });
            }
        },

        do_follow: function () {
            var context = new session.web.CompoundContext(this.build_context(), {});
            this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context])
                .then(this.proxy('read_value'));

            _.each(this.$('.oe_subtype_list input'), function (record) {
                console.log(record);
                $(record).attr('checked', 'checked');
            });
        },

        do_unfollow: function () {
            _(this.$('.oe_msg_subtype_check')).each(function (record) {
                $(record).attr('checked',false);
            });
            var context = new session.web.CompoundContext(this.build_context(), {});
            return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
                .then(this.proxy('read_value'));
        },

        do_update_subscription: function (event) {
            var self = this;

            var checklist = new Array();
            _(this.$('.oe_actions input[type="checkbox"]')).each(function (record) {
                if ($(record).is(':checked')) {
                    checklist.push(parseInt($(record).data('id')));
                }
            });

            if (!checklist.length) {
                this.do_unfollow();
            } else {
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], checklist, context])
                    .then(this.proxy('read_value'));
            }
        },
    });
};
<|endoftext|>


<commit_before>function (key, values)
{
    v = values.reduce(function (v1, v2)
                      {
                          return {schema: key,
                                  count: v1.count + v2.count};
                      },
                      {schema: key, count: 0});
    return v;
}
<commit_msg>Strictness in JS.<commit_after>function (key, values)
{
    var v = values.reduce(function (v1, v2)
                          {
                              return {schema: key,
                                      count: v1.count + v2.count};
                          },
                          {schema: key, count: 0});
    return v;
}
<|endoftext|>