<commit_before>/*** MQTT Z-Way odule *******************************************
 Version: 1.0.0
 -----------------------------------------------------------------------------
 Author: David Uebelacker <david@uebelacker.ch>
 ******************************************************************************/

function ZWayMqttBridge(id, controller) {
    ZWayMqttBridge.super_.call(this, id, controller);
}

inherits(ZWayMqttBridge, AutomationModule);

_module = ZWayMqttBridge;

ZWayMqttBridge.prototype.init = function (config) {
    ZWayMqttBridge.super_.prototype.init.call(this, config);

    var self = this;

    this.log = function(message) {
        console.log('ZWayMqttBridge: ' + message);
    };

    if (!self.config.host || !self.config.port) {
        this.log('Host or port not configured! will not start!')
    };

    this.reconnect = function () {
        self.connected = false;
        self.mqttBridge = null;
        self.log('Will try to reconnect to Mqtt Bridge in 10 seconds ...');
        setTimeout(function () {
            self.connect();
        }, 10000);
    };

    this.connect = function () {
        self.log('Connecting to Mqtt Bridge ....');

        this.mqttBridge = new sockets.tcp();
        this.mqttBridge.onrecv = function (data) {
            self.log('Connecting to Mqtt Bridge established!');
            self.connected = true;
        };

        this.mqttBridge.onclose = function () {
            self.log('Mqtt Bridge connection was closed!');
            self.reconnect();
        };

        if (this.mqttBridge.connect(self.config.host, parseInt(self.config.port))) {
            setTimeout(function () {
                if (self.mqttBridge && !self.connected) {
                    self.log('Mqtt Bridge connection timeout!');
                    self.reconnect();
                }
            }, 5000);
        } else {
            self.log('Could not connect to Mqtt Bridge!');
            self.reconnect();
        }
    };

    this.findRoom = function(id) {
        var locations = self.controller.locations;
        if (locations) {
            for (var i = 0; i < locations.length; i++) {
                if (locations[i].id == id) {
                    return locations[i];
                }
            }
        }
        return null;
    };

    this.createTopic = function(device) {
        var room = self.findRoom(device.get('location'));
        var topic = '/';
        topic += self.config.topic_prefix;
        topic += '/';
        topic += self.normalizeTopicToken(room.title);
        topic += '/';
        topic += self.normalizeTopicToken(device.get('metrics:title'));
        return topic;
    };

    this.normalizeTopicToken = function(token) {
        token = token.toLowerCase();
        token = token.replace(/[^0-9a-z_]/g, '_');
        return token;
    };

    this.deviceUpdate = function (device) {
        if (self.mqttBridge) {
            var message = {
                'topic': self.createTopic(device),
                'payload': device.get('metric:level')
            };

            var str = JSON.stringify(message);
            self.log('Sending update to bridge:' + str);
            var buf = new ArrayBuffer(str.length); // 2 bytes for each char
            var bufView = new Uint8Array(buf);

            for (var i=0; i < str.length; i++) {
                bufView[i] = str.charCodeAt(i);
            }

            self.mqttBridge.send(buf);
        }
    };

    this.connect();
    this.controller.devices.on('change:metrics:level', self.deviceUpdate);
};

<commit_msg>devel<commit_after>/*** MQTT Z-Way odule *******************************************
 Version: 1.0.0
 -----------------------------------------------------------------------------
 Author: David Uebelacker <david@uebelacker.ch>
 ******************************************************************************/

function ZWayMqttBridge(id, controller) {
    ZWayMqttBridge.super_.call(this, id, controller);
}

inherits(ZWayMqttBridge, AutomationModule);

_module = ZWayMqttBridge;

ZWayMqttBridge.prototype.init = function (config) {
    ZWayMqttBridge.super_.prototype.init.call(this, config);

    var self = this;

    this.log = function(message) {
        console.log('ZWayMqttBridge: ' + message);
    };

    if (!self.config.host || !self.config.port) {
        this.log('Host or port not configured! will not start!')
    };

    this.reconnect = function () {
        self.connected = false;
        self.mqttBridge = null;
        self.log('Will try to reconnect to Mqtt Bridge in 10 seconds ...');
        setTimeout(function () {
            self.connect();
        }, 10000);
    };

    this.connect = function () {
        self.log('Connecting to Mqtt Bridge ....');

        this.mqttBridge = new sockets.tcp();
        this.mqttBridge.onrecv = function (data) {
            self.log('Connecting to Mqtt Bridge established!');
            self.connected = true;
        };

        this.mqttBridge.onclose = function () {
            self.log('Mqtt Bridge connection was closed!');
            self.reconnect();
        };

        if (this.mqttBridge.connect(self.config.host, parseInt(self.config.port))) {
            setTimeout(function () {
                if (self.mqttBridge && !self.connected) {
                    self.log('Mqtt Bridge connection timeout!');
                    self.reconnect();
                }
            }, 5000);
        } else {
            self.log('Could not connect to Mqtt Bridge!');
            self.reconnect();
        }
    };

    this.findRoom = function(id) {
        var locations = self.controller.locations;
        if (locations) {
            for (var i = 0; i < locations.length; i++) {
                if (locations[i].id == id) {
                    return locations[i];
                }
            }
        }
        return null;
    };

    this.createTopic = function(device) {
        var room = self.findRoom(device.get('location'));
        topic += self.config.topic_prefix;
        topic += '/';
        topic += self.normalizeTopicToken(room.title);
        topic += '/';
        topic += self.normalizeTopicToken(device.get('metrics:title'));
        return topic;
    };

    this.normalizeTopicToken = function(token) {
        token = token.toLowerCase();
        token = token.replace(/[^0-9a-z_]/g, '_');
        return token;
    };

    this.deviceUpdate = function (device) {
        if (self.mqttBridge) {
            var message = {
                'topic': self.createTopic(device),
                'payload': device.get('metric:level')
            };

            var str = JSON.stringify(message);
            self.log('Sending update to bridge:' + str);
            var buf = new ArrayBuffer(str.length); // 2 bytes for each char
            var bufView = new Uint8Array(buf);

            for (var i=0; i < str.length; i++) {
                bufView[i] = str.charCodeAt(i);
            }

            self.mqttBridge.send(buf);
        }
    };

    this.connect();
    this.controller.devices.on('change:metrics:level', self.deviceUpdate);
};

<|endoftext|>


<commit_before>// The dock
jQuery(function(){
	jQuery('#dock').jqDock();
});

// The toolbar, a jQuery plugin
jQuery(function() {

	jQuery('#floatingbar').css({
		height : "38px"
	});
});

jQuery(function() {
	jQuery(".gallery a[rel^='prettyPhoto']").prettyPhoto({});
});

// The drop-down menu for mobile
jQuery(function() {
	// Landscape mode menubar by default
	jQuery("#jMenu").show();
	jQuery('.dropdownmenu').hide();
	jQuery('.categories').hide();

	jQuery('.dropdownmenu').click(function(){
		jQuery('.categories').toggle();
	});
});

jQuery(function() {
	// @see: initTooltip.js
	// TODO: re-activate Dnd + tap handle for baldu
	jQuery("#card249c4f0b_cad0_4606_b5ea_eaee8866a347").click(
	function(e) {
		jQuery("#cardTooltip249c4f0b_cad0_4606_b5ea_eaee8866a347").attr('style', 'display: block');
	});
});

//The website tour, a jQuery plugin
jQuery(function() {
	tl.pg.init({ 'pg_caption' : 'Site tour', 'auto_show_first': true});
});

// Display the name of the currently displayed card in the hand
function updateHandLabel(){
	var handCardName = jQuery('#handGallery .active-thumbGraveyard .nav-thumb').attr('name');
	if (handCardName == undefined) {
		handCardName = jQuery('#handGallery .active-thumb .nav-thumb').attr('name');
	}
	jQuery('#cardLabel').text(handCardName);
};

jQuery(function() {
	setTimeout(function() {
        // Freebox
        var userAgent = jQuery("#qunit-userAgent").html();
        if (userAgent.indexOf("FbxQmlTV") != -1) {
            jQuery("#floatingbar").css("top", "-10px");
            jQuery("#cssmenu").css("top", "28px");
            jQuery(".dropdownmenu").css("top", "28px");
        }

		updateHandLabel();
		jQuery('#handGallery .cross-link .nav-thumb').click(updateHandLabel);

		// We switch the menu to full bar or small drop-down depending upon the size of the screen
		jQuery(window).resize(function() {
		    var width = viewportSize.getWidth();
			var height = viewportSize.getHeight();

			if ((typeof(width) != "undefined") && (typeof(height) != "undefined") && (null != width) && (null != height) && (width<height)) {
				// Portrait
				jQuery("#cssmenu").hide();
				jQuery('.dropdownmenu').show();
			} else {
				// Landscape
				jQuery("#cssmenu").show();
				jQuery('.dropdownmenu').hide();
				jQuery('.categories').hide();
			}
		});
	}, 4000);
});

// The tooltips
jQuery(function() {
	jQuery('[title]').tipsy({gravity: 's'});
});

// For cards drag + hand, graveyard & exile drop
var shouldMove = true;

// Hand, Graveyard & Exile
jQuery(function() {
	var theInt = null; var $crosslink, $navthumb; var curclicked = 0; theInterval = function(cur) { if (typeof cur != 'undefined') curclicked = cur; $crosslink.removeClass('active-thumb-Hand'); $navthumb.eq(curclicked).parent().addClass('active-thumb-Hand'); jQuery('.stripNav ul li a').eq(curclicked).trigger('click'); $crosslink.removeClass('active-thumb-Hand'); $navthumb.eq(curclicked).parent().addClass('active-thumb-Hand'); jQuery('.stripNav ul li a').eq(curclicked).trigger('click'); curclicked++; if (6 == curclicked) curclicked = 0; }; jQuery('#main-photo-slider').codaSlider(); $navthumb = jQuery('.nav-thumb'); $crosslink = jQuery('.cross-link'); $navthumb.click(function() { var $this = jQuery(this); theInterval($this.parent().attr('href').slice(1) - 1); return false; }); theInterval(); function updateHandLabel(){ var handCardName = jQuery('#handGallery .active-thumb-Hand .nav-thumb').attr('name'); if (handCardName == undefined) { handCardName = jQuery('#handGallery .active-thumb-Hand .nav-thumb').attr('name'); } jQuery('#cardLabel').text(handCardName); }; jQuery(function() { setTimeout(function() { updateHandLabel(); jQuery('#handGallery .cross-link .nav-thumb').click(updateHandLabel); }, 175); });
	var theIntGraveyard = null; var $crosslinkGraveyard, $navthumbGraveyard; var curclickedGraveyard = 0; theIntervalGraveyard = function(cur) { if (typeof cur != 'undefined') curclickedGraveyard = cur; $crosslinkGraveyard.removeClass('active-thumb-Graveyard'); $navthumbGraveyard.eq(curclickedGraveyard).parent().addClass('active-thumb-Graveyard'); jQuery('.stripNavGraveyard ul li a').eq(curclickedGraveyard).trigger('click'); $crosslinkGraveyard.removeClass('active-thumb-Graveyard'); $navthumbGraveyard.eq(curclickedGraveyard).parent().addClass('active-thumb-Graveyard'); jQuery('.stripNavGraveyard ul li a').eq(curclickedGraveyard).trigger('click'); curclickedGraveyard++; if (6 == curclickedGraveyard) curclickedGraveyard = 0; }; jQuery('#graveyard-main-photo-slider').codaSliderGraveyard(); $navthumbGraveyard = jQuery('.graveyard-nav-thumb'); $crosslinkGraveyard = jQuery('.graveyard-cross-link'); $navthumbGraveyard.click(function() { var $this = jQuery(this); theIntervalGraveyard($this.parent().attr('href').slice(1) - 1); return false; }); theIntervalGraveyard(); function updateGraveyardLabel(){ var graveyardCardName = jQuery('#graveyardGallery .active-thumb-Graveyard .nav-thumb').attr('name'); if (graveyardCardName == undefined) { graveyardCardName = jQuery('#graveyardGallery .active-thumb-Graveyard .nav-thumb').attr('name'); } jQuery('#graveyardCardLabel').text(graveyardCardName); }; jQuery(function() { setTimeout(function() { updateGraveyardLabel(); jQuery('#graveyardGallery .cross-link .nav-thumb').click(updateGraveyardLabel); }, 175); });
	var theIntExile = null; var $crosslinkExile, $navthumbExile; var curclickedExile = 0; theIntervalExile = function(cur) { if (typeof cur != 'undefined') curclickedExile = cur; $crosslinkExile.removeClass('active-thumb-Exile'); $navthumbExile.eq(curclickedExile).parent().addClass('active-thumb-Exile'); jQuery('.stripNavExile ul li a').eq(curclickedExile).trigger('click'); $crosslinkExile.removeClass('active-thumb-Exile'); $navthumbExile.eq(curclickedExile).parent().addClass('active-thumb-Exile'); jQuery('.stripNavExile ul li a').eq(curclickedExile).trigger('click'); curclickedExile++; if (6 == curclickedExile) curclickedExile = 0; }; jQuery('#exile-main-photo-slider').codaSliderExile(); $navthumbExile = jQuery('.exile-nav-thumb'); $crosslinkExile = jQuery('.exile-cross-link'); $navthumbExile.click(function() { var $this = jQuery(this); theIntervalExile($this.parent().attr('href').slice(1) - 1); return false; }); theIntervalExile(); function updateExileLabel(){ var exileCardName = jQuery('#exileGallery .active-thumb-Exile .nav-thumb').attr('name'); if (exileCardName == undefined) { exileCardName = jQuery('#exileGallery .active-thumb-Exile .nav-thumb').attr('name'); } jQuery('#exileCardLabel').text(exileCardName); }; jQuery(function() { setTimeout(function() { updateExileLabel(); jQuery('#exileGallery .cross-link .nav-thumb').click(updateExileLabel); }, 175); });
});

jQuery(function() {
	window.setTimeout(function() {
		function getViewPortSize() {
		    if (typeof window.innerWidth != 'undefined')
		    {
		    	window.viewportwidth = window.innerWidth,
		    	window.viewportheight = window.innerHeight;
		    }
		}

		getViewPortSize();
		if (viewportwidth <= 1024) {
			jQuery('#putToHand').attr('src', 'image/hand_small.jpg');
			jQuery('#putToGraveyard').attr('src', 'image/graveyard_small.jpg');
			jQuery('#putToExile').attr('src', 'image/exile_small.jpg');
		}

		jQuery(window).resize(function () {
			getViewPortSize();
			var allCards = jQuery('.magicCard.ui-draggable');

			var allImages = allCards.find('.clickableCard');
			var firstCard = jQuery(allImages[0]);

			if (viewportwidth > 1024) {
				if ((typeof firstCard != 'undefined') && (typeof firstCard.attr('src') != 'undefined') && (firstCard.attr('src').indexOf('_small') != -1)) {
					for (var i = 0; i < allImages.length; i++) {
						var card = jQuery(allImages[i]);
						if ((typeof card != 'undefined') && (typeof card.attr('src') != 'undefined')) {
						card.attr('src', card.attr('src').replace('_small', '_medium'));
						}
					}
				}
			} else {
				if  ((typeof firstCard != 'undefined') && (typeof firstCard.attr('src') != 'undefined') && (firstCard.attr('src').indexOf('_medium') != -1)) {
					for (var i = 0; i < allImages.length; i++) {
						var card = jQuery(allImages[i]);
						card.attr('src', card.attr('src').replace('_medium', '_small'));
					}
				}
			}
		});
	}, 500);
});

//Visio-conference
jQuery(function() {
	window.setTimeout(function() {
		jQuery('#conference').dialog({ autoOpen: false, position: { my: 'center', at: 'center', of: window } });
	}, 250);
});

// Remove the ugly blue arrow due to the conference
jQuery(function() {
	jQuery('#fvd-single-fennec-popup').hide();
});<commit_msg>FIXED JS<commit_after>// The dock
jQuery(function(){
	jQuery('#dock').jqDock();
});

// The toolbar, a jQuery plugin
jQuery(function() {

	jQuery('#floatingbar').css({
		height : "38px"
	});
});

jQuery(function() {
	jQuery(".gallery a[rel^='prettyPhoto']").prettyPhoto({});
});

// The drop-down menu for mobile
jQuery(function() {
	// Landscape mode menubar by default
	jQuery("#jMenu").show();
	jQuery('.dropdownmenu').hide();
	jQuery('.categories').hide();

	jQuery('.dropdownmenu').click(function(){
		jQuery('.categories').toggle();
	});
});

jQuery(function() {
	// @see: initTooltip.js
	// TODO: re-activate Dnd + tap handle for baldu
	jQuery("#card249c4f0b_cad0_4606_b5ea_eaee8866a347").click(
	function(e) {
		jQuery("#cardTooltip249c4f0b_cad0_4606_b5ea_eaee8866a347").attr('style', 'display: block');
	});
});

//The website tour, a jQuery plugin
jQuery(function() {
	tl.pg.init({ 'pg_caption' : 'Site tour', 'auto_show_first': true});
});

// Display the name of the currently displayed card in the hand
function updateHandLabel(){
	var handCardName = jQuery('#handGallery .active-thumbGraveyard .nav-thumb').attr('name');
	if (handCardName == undefined) {
		handCardName = jQuery('#handGallery .active-thumb .nav-thumb').attr('name');
	}
	jQuery('#cardLabel').text(handCardName);
};

jQuery(function() {
	setTimeout(function() {
        // Freebox
        var userAgent = jQuery("#qunit-userAgent").html();
        if (userAgent.indexOf("FbxQmlTV") != -1) {
            jQuery("#floatingbar").css("top", "-10px");
            jQuery("#cssmenu").css("top", "28px");
            jQuery(".dropdownmenu").css("top", "28px");
        }

		updateHandLabel();
		jQuery('#handGallery .cross-link .nav-thumb').click(updateHandLabel);

		// We switch the menu to full bar or small drop-down depending upon the size of the screen
		jQuery(window).resize(function() {
		    var width = viewportSize.getWidth();
			var height = viewportSize.getHeight();

			if ((typeof(width) != "undefined") && (typeof(height) != "undefined") && (null != width) && (null != height) && (width<height)) {
				// Portrait
				jQuery("#cssmenu").hide();
				jQuery('.dropdownmenu').show();
			} else {
				// Landscape
				jQuery("#cssmenu").show();
				jQuery('.dropdownmenu').hide();
				jQuery('.categories').hide();
			}
		});
	}, 4000);
});

// The tooltips
jQuery(function() {
	jQuery('[title]').tipsy({gravity: 's'});
});

// For cards drag + hand, graveyard & exile drop
var shouldMove = true;

// Hand, Graveyard & Exile
jQuery(function() {
	var theInt = null; var $crosslink, $navthumb; var curclicked = 0; theInterval = function(cur) { if (typeof cur != 'undefined') curclicked = cur; $crosslink.removeClass('active-thumb-Hand'); $navthumb.eq(curclicked).parent().addClass('active-thumb-Hand'); jQuery('.stripNav ul li a').eq(curclicked).trigger('click'); $crosslink.removeClass('active-thumb-Hand'); $navthumb.eq(curclicked).parent().addClass('active-thumb-Hand'); jQuery('.stripNav ul li a').eq(curclicked).trigger('click'); curclicked++; if (6 == curclicked) curclicked = 0; }; jQuery('#main-photo-slider').codaSlider(); $navthumb = jQuery('.nav-thumb'); $crosslink = jQuery('.cross-link'); $navthumb.click(function() { var $this = jQuery(this); theInterval($this.parent().attr('href').slice(1) - 1); return false; }); theInterval(); function updateHandLabel(){ var handCardName = jQuery('#handGallery .active-thumb-Hand .nav-thumb').attr('name'); if (handCardName == undefined) { handCardName = jQuery('#handGallery .active-thumb-Hand .nav-thumb').attr('name'); } jQuery('#cardLabel').text(handCardName); }; jQuery(function() { setTimeout(function() { updateHandLabel(); jQuery('#handGallery .cross-link .nav-thumb').click(updateHandLabel); }, 175); });
	var theIntGraveyard = null; var $crosslinkGraveyard, $navthumbGraveyard; var curclickedGraveyard = 0; theIntervalGraveyard = function(cur) { if (typeof cur != 'undefined') curclickedGraveyard = cur; $crosslinkGraveyard.removeClass('active-thumb-Graveyard'); $navthumbGraveyard.eq(curclickedGraveyard).parent().addClass('active-thumb-Graveyard'); jQuery('.stripNavGraveyard ul li a').eq(curclickedGraveyard).trigger('click'); $crosslinkGraveyard.removeClass('active-thumb-Graveyard'); $navthumbGraveyard.eq(curclickedGraveyard).parent().addClass('active-thumb-Graveyard'); jQuery('.stripNavGraveyard ul li a').eq(curclickedGraveyard).trigger('click'); curclickedGraveyard++; if (6 == curclickedGraveyard) curclickedGraveyard = 0; }; jQuery('#graveyard-main-photo-slider').codaSliderGraveyard(); $navthumbGraveyard = jQuery('.graveyard-nav-thumb'); $crosslinkGraveyard = jQuery('.graveyard-cross-link'); $navthumbGraveyard.click(function() { var $this = jQuery(this); theIntervalGraveyard($this.parent().attr('href').slice(1) - 1); return false; }); theIntervalGraveyard(); function updateGraveyardLabel(){ var graveyardCardName = jQuery('#graveyardGallery .active-thumb-Graveyard .nav-thumb').attr('name'); if (graveyardCardName == undefined) { graveyardCardName = jQuery('#graveyardGallery .active-thumb-Graveyard .nav-thumb').attr('name'); } jQuery('#graveyardCardLabel').text(graveyardCardName); }; jQuery(function() { setTimeout(function() { updateGraveyardLabel(); jQuery('#graveyardGallery .cross-link .nav-thumb').click(updateGraveyardLabel); }, 175); });
	var theIntExile = null; var $crosslinkExile, $navthumbExile; var curclickedExile = 0; theIntervalExile = function(cur) { if (typeof cur != 'undefined') curclickedExile = cur; $crosslinkExile.removeClass('active-thumb-Exile'); $navthumbExile.eq(curclickedExile).parent().addClass('active-thumb-Exile'); jQuery('.stripNavExile ul li a').eq(curclickedExile).trigger('click'); $crosslinkExile.removeClass('active-thumb-Exile'); $navthumbExile.eq(curclickedExile).parent().addClass('active-thumb-Exile'); jQuery('.stripNavExile ul li a').eq(curclickedExile).trigger('click'); curclickedExile++; if (6 == curclickedExile) curclickedExile = 0; }; jQuery('#exile-main-photo-slider').codaSliderExile(); $navthumbExile = jQuery('.exile-nav-thumb'); $crosslinkExile = jQuery('.exile-cross-link'); $navthumbExile.click(function() { var $this = jQuery(this); theIntervalExile($this.parent().attr('href').slice(1) - 1); return false; }); theIntervalExile(); function updateExileLabel(){ var exileCardName = jQuery('#exileGallery .active-thumb-Exile .nav-thumb').attr('name'); if (exileCardName == undefined) { exileCardName = jQuery('#exileGallery .active-thumb-Exile .nav-thumb').attr('name'); } jQuery('#exileCardLabel').text(exileCardName); }; jQuery(function() { setTimeout(function() { updateExileLabel(); jQuery('#exileGallery .cross-link .nav-thumb').click(updateExileLabel); }, 175); });
});

jQuery(function() {
	window.setTimeout(function() {
		function getViewPortSize() {
		    if (typeof window.innerWidth != 'undefined')
		    {
		    	window.viewportwidth = window.innerWidth,
		    	window.viewportheight = window.innerHeight;
		    }
		}

		getViewPortSize();
		if (viewportwidth <= 1024) {
			jQuery('#putToHand').attr('src', 'image/hand_small.jpg');
			jQuery('#putToGraveyard').attr('src', 'image/graveyard_small.jpg');
			jQuery('#putToExile').attr('src', 'image/exile_small.jpg');
		}

		jQuery(window).resize(function () {
			getViewPortSize();
			var allCards = jQuery('.magicCard.ui-draggable');

			var allImages = allCards.find('.clickableCard');
			var firstCard = jQuery(allImages[0]);

			if (viewportwidth > 1024) {
				if ((typeof firstCard != 'undefined') && (typeof firstCard.attr('src') != 'undefined') && (firstCard.attr('src').indexOf('_small') != -1)) {
					for (var i = 0; i < allImages.length; i++) {
						var card = jQuery(allImages[i]);
						if ((typeof card != 'undefined') && (typeof card.attr('src') != 'undefined')) {
							card.attr('src', card.attr('src').replace('_small', '_medium'));
						}
					}
				}
			} else {
				if  ((typeof firstCard != 'undefined') && (typeof firstCard.attr('src') != 'undefined') && (firstCard.attr('src').indexOf('_medium') != -1)) {
					for (var i = 0; i < allImages.length; i++) {
						var card = jQuery(allImages[i]);
						if ((typeof card != 'undefined') && (typeof card.attr('src') != 'undefined')) {
							card.attr('src', card.attr('src').replace('_medium', '_small'));
						}
					}
				}
			}
		});
	}, 500);
});

//Visio-conference
jQuery(function() {
	window.setTimeout(function() {
		jQuery('#conference').dialog({ autoOpen: false, position: { my: 'center', at: 'center', of: window } });
	}, 250);
});

// Remove the ugly blue arrow due to the conference
jQuery(function() {
	window.setTimeout(function() {
		jQuery('#fvd-single-fennec-popup').hide();
	}, 500);
});
});<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var angular = require('angular');
var createSearchQueryForDecisionInstance = require('./create-search-query-for-decision-instance');

var template = fs.readFileSync(__dirname + '/decision-instance-table.html', 'utf8');
var decisionSearchConfig = JSON.parse(fs.readFileSync(__dirname + '/decision-instance-search-config.json', 'utf8'));

module.exports = [ 'ViewsProvider', function(ViewsProvider) {

  ViewsProvider.registerDefaultView('cockpit.decisionDefinition.tab', {
    id: 'decision-instances-table',
    label: 'Decision Instances',
    template: template,
    controller: [
      '$scope', '$location', 'search', 'routeUtil', 'camAPI', 'Views', '$rootScope',
      function($scope,   $location,   search,   routeUtil,   camAPI,   Views,   $rootScope) {

        var processInstancePlugins = Views.getProviders({ component: 'cockpit.processInstance.view' });

        var hasHistoryPlugin = processInstancePlugins.filter(function(plugin) {
          return plugin.id === 'history';
        }).length > 0;

        $scope.getProcessDefinitionLink = function(decisionInstance) {
          if(hasHistoryPlugin) {
            return '#/process-definition/' + decisionInstance.processDefinitionId + '/history';
          } else {
            return '#/process-definition/' + decisionInstance.processDefinitionId;
          }
        };

        $scope.getProcessInstanceLink = function(decisionInstance) {
          if(hasHistoryPlugin) {
            return '#/process-instance/' + decisionInstance.processInstanceId + '/history' +
            '?activityInstanceIds=' + decisionInstance.activityInstanceId +
            '&activityIds=' + decisionInstance.activityId;
          } else {
            return '#/process-instance/' + decisionInstance.processInstanceId;
          }
        };

        $scope.decisionSearchConfig = angular.copy(decisionSearchConfig);

        $scope.$on('$routeChanged', function() {
          pages.current = search().page || 1;
        });

        $scope.$watch('decisionSearchConfig.searches', function (newValue, oldValue) {
          if (newValue !== oldValue) {
            updateView();
          }
        }, true);

        var historyService = camAPI.resource('history');

        var DEFAULT_PAGES = { size: 50, total: 0, current: search().page || 1 };

        var pages = $scope.pages = angular.copy(DEFAULT_PAGES);

        $scope.$watch('pages.current', function(newValue, oldValue) {
          if (newValue == oldValue) {
            return;
          }

          search('page', !newValue || newValue == 1 ? null : newValue);
          updateView();
        });

        function updateView() {
          var page = pages.current,
              count = pages.size,
              firstResult = (page - 1) * count,
              searchQuery = createSearchQueryForDecisionInstance($scope.decisionSearchConfig.searches);

          $scope.decisionInstances = null;
          $scope.loadingState = 'LOADING';

          var decisionInstanceQuery = angular.extend(
            {
              decisionDefinitionId: $scope.decisionDefinition.id,
              firstResult: firstResult,
              maxResults: count,
              sortBy: 'evaluationTime',
              sortOrder: 'desc'
            },
            searchQuery
          );

          historyService.decisionInstance(decisionInstanceQuery, function(err, data) {
            $scope.decisionInstances = data;
            $scope.loadingState = data.length ? 'LOADED' : 'EMPTY';

            var phase = $rootScope.$$phase;
            if(phase !== '$apply' && phase !== '$digest') {
              $scope.$apply();
            }
          });

          var countQuery = angular.extend(
            {
              decisionDefinitionId: $scope.decisionDefinition.id
            },
            searchQuery
          );

          historyService.decisionInstanceCount(countQuery, function(err, data) {
            pages.total = data.count;

            var phase = $rootScope.$$phase;
            if(phase !== '$apply' && phase !== '$digest') {
              $scope.$apply();
            }

          });
        }
      }],
    priority: 10
  });
}];
<commit_msg><chore>(decistion instance): remove space after function<commit_after>'use strict';

var fs = require('fs');
var angular = require('angular');
var createSearchQueryForDecisionInstance = require('./create-search-query-for-decision-instance');

var template = fs.readFileSync(__dirname + '/decision-instance-table.html', 'utf8');
var decisionSearchConfig = JSON.parse(fs.readFileSync(__dirname + '/decision-instance-search-config.json', 'utf8'));

module.exports = [ 'ViewsProvider', function(ViewsProvider) {

  ViewsProvider.registerDefaultView('cockpit.decisionDefinition.tab', {
    id: 'decision-instances-table',
    label: 'Decision Instances',
    template: template,
    controller: [
      '$scope', '$location', 'search', 'routeUtil', 'camAPI', 'Views', '$rootScope',
      function($scope,   $location,   search,   routeUtil,   camAPI,   Views,   $rootScope) {

        var processInstancePlugins = Views.getProviders({ component: 'cockpit.processInstance.view' });

        var hasHistoryPlugin = processInstancePlugins.filter(function(plugin) {
          return plugin.id === 'history';
        }).length > 0;

        $scope.getProcessDefinitionLink = function(decisionInstance) {
          if(hasHistoryPlugin) {
            return '#/process-definition/' + decisionInstance.processDefinitionId + '/history';
          } else {
            return '#/process-definition/' + decisionInstance.processDefinitionId;
          }
        };

        $scope.getProcessInstanceLink = function(decisionInstance) {
          if(hasHistoryPlugin) {
            return '#/process-instance/' + decisionInstance.processInstanceId + '/history' +
            '?activityInstanceIds=' + decisionInstance.activityInstanceId +
            '&activityIds=' + decisionInstance.activityId;
          } else {
            return '#/process-instance/' + decisionInstance.processInstanceId;
          }
        };

        $scope.decisionSearchConfig = angular.copy(decisionSearchConfig);

        $scope.$on('$routeChanged', function() {
          pages.current = search().page || 1;
        });

        $scope.$watch('decisionSearchConfig.searches', function(newValue, oldValue) {
          if (newValue !== oldValue) {
            updateView();
          }
        }, true);

        var historyService = camAPI.resource('history');

        var DEFAULT_PAGES = { size: 50, total: 0, current: search().page || 1 };

        var pages = $scope.pages = angular.copy(DEFAULT_PAGES);

        $scope.$watch('pages.current', function(newValue, oldValue) {
          if (newValue == oldValue) {
            return;
          }

          search('page', !newValue || newValue == 1 ? null : newValue);
          updateView();
        });

        function updateView() {
          var page = pages.current,
              count = pages.size,
              firstResult = (page - 1) * count,
              searchQuery = createSearchQueryForDecisionInstance($scope.decisionSearchConfig.searches);

          $scope.decisionInstances = null;
          $scope.loadingState = 'LOADING';

          var decisionInstanceQuery = angular.extend(
            {
              decisionDefinitionId: $scope.decisionDefinition.id,
              firstResult: firstResult,
              maxResults: count,
              sortBy: 'evaluationTime',
              sortOrder: 'desc'
            },
            searchQuery
          );

          historyService.decisionInstance(decisionInstanceQuery, function(err, data) {
            $scope.decisionInstances = data;
            $scope.loadingState = data.length ? 'LOADED' : 'EMPTY';

            var phase = $rootScope.$$phase;
            if(phase !== '$apply' && phase !== '$digest') {
              $scope.$apply();
            }
          });

          var countQuery = angular.extend(
            {
              decisionDefinitionId: $scope.decisionDefinition.id
            },
            searchQuery
          );

          historyService.decisionInstanceCount(countQuery, function(err, data) {
            pages.total = data.count;

            var phase = $rootScope.$$phase;
            if(phase !== '$apply' && phase !== '$digest') {
              $scope.$apply();
            }

          });
        }
      }],
    priority: 10
  });
}];
<|endoftext|>


<commit_before>;(function() {

    var isInited = false;
    var marker = null;
    var container = null;
    SVG.extend(SVG.Element, {
        connectable: function(options, elmTarget) {

            if (elmTarget === undefined) {
                elmTarget = options;
                options = {};
            }

            container = container || options.container;
            var elmSource = this;
            var line = container.line().attr("marker-end", "url(#triangle)");
            var markers = options.markers;

            // Source and target positions
            var sPos = {};
            var tPos = {};

            function updateLine() {

                sPos = elmSource.transform();
                tPos = elmTarget.transform();

                var x1 = sPos.x;
                var y1 = sPos.y;
                var x2 = tPos.x;
                var y2 = tPos.y;

                var dx = x2 - x1;
                var dy = y2 - y1;

                if (Math.abs(dy) < 200) {
                    if (dx < 0) {
                        x1 -= 25;
                        x2 += 30;
                    } else {
                        x2 -= 30;
                        x1 += 25;
                    }
                } else {
                    if (dy < 0) {
                        y1 -= 25;
                        y2 += 30;
                    } else {
                        y2 -= 30;
                        y1 += 25;
                    }
                }

                line.attr({
                    x1: x1,
                    y1: y1,
                    x2: x2,
                    y2: y2
                });
            }

            if (isInited === false) {
                marker = markers.marker(10, 10);
                marker.attr({
                    id: "triangle",
                    viewBox: "0 0 10 10",
                    refX: "0",
                    refY: "5",
                    markerUnits: "strokeWidth",
                    markerWidth: "4",
                    markerHeight: "5"
                });

                marker.path().attr({
                    d: "M 0 0 L 10 5 L 0 10 z"
                });

                isInited = true;
            }

            updateLine();

            elmSource.dragmove = updateLine;
            elmTarget.dragmove = updateLine;

            return {
                source: elmSource,
                target: elmTarget,
                line: line
            };
        }
    });
}).call(this);
<commit_msg>Create new markers for each line<commit_after>;(function() {

    var container = null;
    var markers = null;

    SVG.extend(SVG.Element, {
        connectable: function(options, elmTarget) {

            if (elmTarget === undefined) {
                elmTarget = options;
                options = {};
            }

            container = container || options.container;
            var elmSource = this;
            markers = markers || options.markers;

            var marker = markers.marker(10, 10);
            var markerId = "triangle-" + Math.random().toString(16);
            var line = container.line().attr("marker-end", "url(#" + markerId + ")");

            marker.attr({
                id: markerId,
                viewBox: "0 0 10 10",
                refX: "0",
                refY: "5",
                markerUnits: "strokeWidth",
                markerWidth: "4",
                markerHeight: "5"
            });

            marker.path().attr({
                d: "M 0 0 L 10 5 L 0 10 z"
            });

            // Source and target positions
            var sPos = {};
            var tPos = {};

            function updateLine() {

                sPos = elmSource.transform();
                tPos = elmTarget.transform();

                var x1 = sPos.x;
                var y1 = sPos.y;
                var x2 = tPos.x;
                var y2 = tPos.y;

                var dx = x2 - x1;
                var dy = y2 - y1;

                if (Math.abs(dy) < 200) {
                    if (dx < 0) {
                        x1 -= 25;
                        x2 += 30;
                    } else {
                        x2 -= 30;
                        x1 += 25;
                    }
                } else {
                    if (dy < 0) {
                        y1 -= 25;
                        y2 += 30;
                    } else {
                        y2 -= 30;
                        y1 += 25;
                    }
                }

                line.attr({
                    x1: x1,
                    y1: y1,
                    x2: x2,
                    y2: y2
                });
            }

            updateLine();

            elmSource.dragmove = updateLine;
            elmTarget.dragmove = updateLine;

            return {
                source: elmSource,
                target: elmTarget,
                line: line,
                marker: marker
            };
        }
    });
}).call(this);
<|endoftext|>


<commit_before>import Ember from 'ember';

const get = Ember.get;

/*
  Check if the passed model has a `type` attribute or a relationship named `type`.

  @method modelHasAttributeOrRelationshipNamedType
  @param modelClass
 */
function modelHasAttributeOrRelationshipNamedType(modelClass) {
  return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type');
}

/*
  ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public
  API for looking items up.  This function serves as a super simple polyfill to avoid
  triggering deprecations.
 */
function getOwner(context) {
  let owner;

  if (Ember.getOwner) {
    owner = Ember.getOwner(context);
  }

  if (!owner && context.container) {
    owner = context.container;
  }

  if (owner && owner.lookupFactory && !owner._lookupFactory) {
    // `owner` is a container, we are just making this work
    owner._lookupFactory = owner.lookupFactory;
    owner.register = function() {
      let registry = owner.registry || owner._registry || owner;

      return registry.register(...arguments);
    };
  }

  return owner;
}

export {
  modelHasAttributeOrRelationshipNamedType,
  getOwner
};
<commit_msg>Do not access container if Ember.getOwner exists.<commit_after>import Ember from 'ember';

const get = Ember.get;

/*
  Check if the passed model has a `type` attribute or a relationship named `type`.

  @method modelHasAttributeOrRelationshipNamedType
  @param modelClass
 */
function modelHasAttributeOrRelationshipNamedType(modelClass) {
  return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type');
}

/*
  ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public
  API for looking items up.  This function serves as a super simple polyfill to avoid
  triggering deprecations.
 */
function getOwner(context) {
  let owner;

  if (Ember.getOwner) {
    owner = Ember.getOwner(context);
  } else if (context.container) {
    owner = context.container;
  }

  if (owner && owner.lookupFactory && !owner._lookupFactory) {
    // `owner` is a container, we are just making this work
    owner._lookupFactory = owner.lookupFactory;
    owner.register = function() {
      let registry = owner.registry || owner._registry || owner;

      return registry.register(...arguments);
    };
  }

  return owner;
}

export {
  modelHasAttributeOrRelationshipNamedType,
  getOwner
};
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';
//import BelongsToRelationship from 'ember-data/-private/system/relationships/state/belongs-to';

import {
  extractDeleteRecord
} from '../utils';

const {
  getOwner,
  run: {
    bind
  },
  on,
  String: {
    pluralize,
    camelize,
    classify
  }
} = Ember;

//BelongsToRelationship.reopen({
//  findRecord() {
//    return this._super().catch(() => {
//      //not found: deleted
//      this.clear();
//    });
//  }
//});

export default DS.RESTAdapter.extend({
  coalesceFindRequests: false,

  // The change listener ensures that individual records are kept up to date
  // when the data in the database changes. This makes ember-data 2.0's record
  // reloading redundant.
  shouldReloadRecord: function () { return false; },
  shouldBackgroundReloadRecord: function () { return false; },
  _onInit : on('init', function()  {
    this._startChangesToStoreListener();
  }),
  _startChangesToStoreListener: function () {
    var db = this.get('db');
    if (db) {
      this.changes = db.changes({
        since: 'now',
        live: true,
        returnDocs: false
      }).on('change', bind(this, 'onChange'));
    }
  },
  changeDb: function(db) {
    if (this.changes) {
      this.changes.cancel();
    }

    var store = this.store;
    var schema = this._schema || [];

    for (var i = 0, len = schema.length; i < len; i++) {
      store.unloadAll(schema[i].singular);
    }

    this._schema = null;
    this.set('db', db);
    this._startChangesToStoreListener();
  },
  onChange: function (change) {
    // If relational_pouch isn't initialized yet, there can't be any records
    // in the store to update.
    if (!this.get('db').rel) { return; }

    var obj = this.get('db').rel.parseDocID(change.id);
    // skip changes for non-relational_pouch docs. E.g., design docs.
    if (!obj.type || !obj.id || obj.type === '') { return; }

    var store = this.store;

    if (this.waitingForConsistency[change.id]) {
      let promise = this.waitingForConsistency[change.id];
      delete this.waitingForConsistency[change.id];
      if (change.deleted) {
        promise.reject("deleted");
      } else {
        promise.resolve(this._findRecord(obj.type, obj.id));
      }
      return;
    }

    try {
      store.modelFor(obj.type);
    } catch (e) {
      // The record refers to a model which this version of the application
      // does not have.
      return;
    }

    var recordInStore = store.peekRecord(obj.type, obj.id);
    if (!recordInStore) {
      // The record hasn't been loaded into the store; no need to reload its data.
      this.unloadedDocumentChanged(obj);
      return;
    }
    if (!recordInStore.get('isLoaded') || recordInStore.get('hasDirtyAttributes')) {
      // The record either hasn't loaded yet or has unpersisted local changes.
      // In either case, we don't want to refresh it in the store
      // (and for some substates, attempting to do so will result in an error).
      return;
    }

    if (change.deleted) {
      store.unloadRecord(recordInStore);
    } else {
      recordInStore.reload();
    }
  },

  unloadedDocumentChanged: function(/* obj */) {
    /*
     * For performance purposes, we don't load records into the store that haven't previously been loaded.
     * If you want to change this, subclass this method, and push the data into the store. e.g.
     *
     *  let store = this.get('store');
     *  let recordTypeName = this.getRecordTypeName(store.modelFor(obj.type));
     *  this.get('db').rel.find(recordTypeName, obj.id).then(function(doc){
     *    store.pushPayload(recordTypeName, doc);
     *  });
     */
  },

  willDestroy: function() {
    if (this.changes) {
      this.changes.cancel();
    }
  },

  _init: function (store, type) {
    var self = this,
        recordTypeName = this.getRecordTypeName(type);
    if (!this.get('db') || typeof this.get('db') !== 'object') {
      throw new Error('Please set the `db` property on the adapter.');
    }

    if (!Ember.get(type, 'attributes').has('rev')) {
      var modelName = classify(recordTypeName);
      throw new Error('Please add a `rev` attribute of type `string`' +
        ' on the ' + modelName + ' model.');
    }

    this._schema = this._schema || [];

    var singular = recordTypeName;
    var plural = pluralize(recordTypeName);

    // check that we haven't already registered this model
    for (var i = 0, len = this._schema.length; i < len; i++) {
      var currentSchemaDef = this._schema[i];
      if (currentSchemaDef.singular === singular) {
        return;
      }
    }

    var schemaDef = {
      singular: singular,
      plural: plural
    };

    if (type.documentType) {
      schemaDef['documentType'] = type.documentType;
    }

    let config = getOwner(this).resolveRegistration('config:environment');
    let dontsavedefault = config['emberpouch'] && config['emberpouch']['dontsavehasmany'];
    // else it's new, so update
    this._schema.push(schemaDef);
    // check all the subtypes
    // We check the type of `rel.type`because with ember-data beta 19
    // `rel.type` switched from DS.Model to string
    type.eachRelationship(function (_, rel) {
      if (rel.kind !== 'belongsTo' && rel.kind !== 'hasMany') {
        // TODO: support inverse as well
        return; // skip
      }
      var relDef = {},
          relModel = (typeof rel.type === 'string' ? store.modelFor(rel.type) : rel.type);
      if (relModel) {
        let includeRel = true;
        rel.options = rel.options || {};
        if (typeof(rel.options.async) === "undefined") {
          rel.options.async = config.emberpouch && !Ember.isEmpty(config.emberpouch.async) ? config.emberpouch.async : true;//default true from https://github.com/emberjs/data/pull/3366
        }
        let options = Object.create(rel.options);
        if (rel.kind === 'hasMany' && (options.dontsave || typeof(options.dontsave) === 'undefined' && dontsavedefault)) {
          let inverse = type.inverseFor(rel.key, store);
          if (inverse) {
            if (inverse.kind === 'belongsTo') {
              self.get('db').createIndex({index: { fields: ['data.' + inverse.name, '_id'] }});
              if (options.async) {
                includeRel = false;
              } else {
                options.queryInverse = inverse.name;
              }
            }
          }
        }

        if (includeRel) {
          relDef[rel.kind] = {
            type: self.getRecordTypeName(relModel),
            options: options
          };
          if (!schemaDef.relations) {
            schemaDef.relations = {};
          }
          schemaDef.relations[rel.key] = relDef;
        }
        self._init(store, relModel);
      }
    });

    this.get('db').setSchema(this._schema);
  },

  _recordToData: function (store, type, record) {
    var data = {};
    // Though it would work to use the default recordTypeName for modelName &
    // serializerKey here, these uses are conceptually distinct and may vary
    // independently.
    var modelName = type.modelName || type.typeKey;
    var serializerKey = camelize(modelName);
    var serializer = store.serializerFor(modelName);

    serializer.serializeIntoHash(
      data,
      type,
      record,
      {includeId: true}
    );

    data = data[serializerKey];

    // ember sets it to null automatically. don't need it.
    if (data.rev === null) {
      delete data.rev;
    }

    return data;
  },

  /**
   * Return key that conform to data adapter
   * ex: 'name' become 'data.name'
   */
  _dataKey: function(key) {
    var dataKey ='data.' + key;
    return ""+ dataKey + "";
  },

  /**
   * Returns the modified selector key to comform data key
   * Ex: selector: {name: 'Mario'} wil become selector: {'data.name': 'Mario'}
   */
  _buildSelector: function(selector) {
    var dataSelector = {};
    var selectorKeys = [];

    for (var key in selector) {
      if(selector.hasOwnProperty(key)){
        selectorKeys.push(key);
      }
    }

    selectorKeys.forEach(function(key) {
      var dataKey = this._dataKey(key);
      dataSelector[dataKey] = selector[key];
    }.bind(this));

    return dataSelector;
  },

  /**
   * Returns the modified sort key
   * Ex: sort: ['series'] will become ['data.series']
   * Ex: sort: [{series: 'desc'}] will became [{'data.series': 'desc'}]
   */
  _buildSort: function(sort) {
    return sort.map(function (value) {
      var sortKey = {};
      if (typeof value === 'object' && value !== null) {
        for (var key in value) {
          if(value.hasOwnProperty(key)){
            sortKey[this._dataKey(key)] = value[key];
          }
        }
      } else {
        return this._dataKey(value);
      }
      return sortKey;
    }.bind(this));
  },

  /**
   * Returns the string to use for the model name part of the PouchDB document
   * ID for records of the given ember-data type.
   *
   * This method uses the camelized version of the model name in order to
   * preserve data compatibility with older versions of ember-pouch. See
   * pouchdb-community/ember-pouch#63 for a discussion.
   *
   * You can override this to change the behavior. If you do, be aware that you
   * need to execute a data migration to ensure that any existing records are
   * moved to the new IDs.
   */
  getRecordTypeName(type) {
    return camelize(type.modelName);
  },

  findAll: function(store, type /*, sinceToken */) {
    // TODO: use sinceToken
    this._init(store, type);
    return this.get('db').rel.find(this.getRecordTypeName(type));
  },

  findMany: function(store, type, ids) {
    this._init(store, type);
    return this.get('db').rel.find(this.getRecordTypeName(type), ids);
  },

  findHasMany: function(store, record, link, rel) {
    let inverse = record.type.inverseFor(rel.key, store);
    if (inverse && inverse.kind === 'belongsTo') {
      return this.get('db').rel.findHasMany(camelize(rel.type), inverse.name, record.id);
    } else {
      let result = {};
      result[pluralize(rel.type)] = [];
      return result; //data;
    }
  },

  query: function(store, type, query) {
    this._init(store, type);

    var recordTypeName = this.getRecordTypeName(type);
    var db = this.get('db');

    var queryParams = {
      selector: this._buildSelector(query.filter)
    };

    if (!Ember.isEmpty(query.sort)) {
      queryParams.sort = this._buildSort(query.sort);
    }

    return db.find(queryParams).then(pouchRes => db.rel.parseRelDocs(recordTypeName, pouchRes.docs));
  },

  queryRecord: function(store, type, query) {
    return this.query(store, type, query).then(results => {
      let recordType = this.getRecordTypeName(type);
      let recordTypePlural = pluralize(recordType);
      if(results[recordTypePlural].length > 0){
        results[recordType] = results[recordTypePlural][0];
      } else {
        results[recordType] = null;
      }
      delete results[recordTypePlural];
      return results;
    });
  },

  /**
   * `find` has been deprecated in ED 1.13 and is replaced by 'new store
   * methods', see: https://github.com/emberjs/data/pull/3306
   * We keep the method for backward compatibility and forward calls to
   * `findRecord`. This can be removed when the library drops support
   * for deprecated methods.
  */
  find: function (store, type, id) {
    return this.findRecord(store, type, id);
  },

  findRecord: function (store, type, id) {
    this._init(store, type);
    var recordTypeName = this.getRecordTypeName(type);
    return this._findRecord(recordTypeName, id);
  },

  _findRecord(recordTypeName, id) {
    return this.get('db').rel.find(recordTypeName, id).then(payload => {
      // Ember Data chokes on empty payload, this function throws
      // an error when the requested data is not found
      if (typeof payload === 'object' && payload !== null) {
        var singular = recordTypeName;
        var plural = pluralize(recordTypeName);

        var results = payload[singular] || payload[plural];
        if (results && results.length > 0) {
          return payload;
        }
      }

      return this._eventuallyConsistent(recordTypeName, id);
    });
  },

  //TODO: cleanup promises on destroy or db change?
  waitingForConsistency: {},
  _eventuallyConsistent: function(type, id) {
    let pouchID = this.get('db').rel.makeDocID({type, id});
    let defer = Ember.RSVP.defer();
    this.waitingForConsistency[pouchID] = defer;

    return this.get('db').rel.isDeleted(type, id).then(deleted => {
      //TODO: should we test the status of the promise here? Could it be handled in onChange already?
      if (deleted) {
        delete this.waitingForConsistency[pouchID];
        throw "Document of type '" + type + "' with id '" + id + "' is deleted.";
      } else if (deleted === null) {
        return defer.promise;
      } else {
        Ember.assert('Status should be existing', deleted === false);
        //TODO: should we reject or resolve the promise? or does JS GC still clean it?
        if (this.waitingForConsistency[pouchID]) {
          delete this.waitingForConsistency[pouchID];
          return this._findRecord(type, id);
        } else {
          //findRecord is already handled by onChange
          return defer.promise;
        }
      }
    });
  },

  createRecord: function(store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.save(this.getRecordTypeName(type), data);
  },

  updateRecord: function (store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.save(this.getRecordTypeName(type), data);
  },

  deleteRecord: function (store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.del(this.getRecordTypeName(type), data)
      .then(extractDeleteRecord);
  }
});
<commit_msg>make sure only one changes listener ever exists on a database<commit_after>import Ember from 'ember';
import DS from 'ember-data';
//import BelongsToRelationship from 'ember-data/-private/system/relationships/state/belongs-to';

import {
  extractDeleteRecord
} from '../utils';

const {
  getOwner,
  run: {
    bind
  },
  on,
  String: {
    pluralize,
    camelize,
    classify
  }
} = Ember;

//BelongsToRelationship.reopen({
//  findRecord() {
//    return this._super().catch(() => {
//      //not found: deleted
//      this.clear();
//    });
//  }
//});

export default DS.RESTAdapter.extend({
  coalesceFindRequests: false,

  // The change listener ensures that individual records are kept up to date
  // when the data in the database changes. This makes ember-data 2.0's record
  // reloading redundant.
  shouldReloadRecord: function () { return false; },
  shouldBackgroundReloadRecord: function () { return false; },
  _onInit : on('init', function()  {
    this._startChangesToStoreListener();
  }),
  _startChangesToStoreListener: function() {
    var db = this.get('db');
    if (db && !this.changes) { // only run this once
      var onChangeListener = bind(this, 'onChange');
      this.set('onChangeListener', onChangeListener);
      this.changes = db.changes({
        since: 'now',
        live: true,
        returnDocs: false
      });
      this.changes.on('change', onChangeListener);
    }
  },

  _stopChangesListener: function() {
    if (this.changes) {
      var onChangeListener = this.get('onChangeListener');
      this.changes.removeListener('change', onChangeListener);
      this.changes.cancel();
      this.changes = undefined;
    }
  },
  changeDb: function(db) {
    this._stopChangesListener();

    var store = this.store;
    var schema = this._schema || [];

    for (var i = 0, len = schema.length; i < len; i++) {
      store.unloadAll(schema[i].singular);
    }

    this._schema = null;
    this.set('db', db);
    this._startChangesToStoreListener();
  },
  onChange: function (change) {
    // If relational_pouch isn't initialized yet, there can't be any records
    // in the store to update.
    if (!this.get('db').rel) { return; }

    var obj = this.get('db').rel.parseDocID(change.id);
    // skip changes for non-relational_pouch docs. E.g., design docs.
    if (!obj.type || !obj.id || obj.type === '') { return; }

    var store = this.store;

    if (this.waitingForConsistency[change.id]) {
      let promise = this.waitingForConsistency[change.id];
      delete this.waitingForConsistency[change.id];
      if (change.deleted) {
        promise.reject("deleted");
      } else {
        promise.resolve(this._findRecord(obj.type, obj.id));
      }
      return;
    }

    try {
      store.modelFor(obj.type);
    } catch (e) {
      // The record refers to a model which this version of the application
      // does not have.
      return;
    }

    var recordInStore = store.peekRecord(obj.type, obj.id);
    if (!recordInStore) {
      // The record hasn't been loaded into the store; no need to reload its data.
      this.unloadedDocumentChanged(obj);
      return;
    }
    if (!recordInStore.get('isLoaded') || recordInStore.get('hasDirtyAttributes')) {
      // The record either hasn't loaded yet or has unpersisted local changes.
      // In either case, we don't want to refresh it in the store
      // (and for some substates, attempting to do so will result in an error).
      return;
    }

    if (change.deleted) {
      store.unloadRecord(recordInStore);
    } else {
      recordInStore.reload();
    }
  },

  unloadedDocumentChanged: function(/* obj */) {
    /*
     * For performance purposes, we don't load records into the store that haven't previously been loaded.
     * If you want to change this, subclass this method, and push the data into the store. e.g.
     *
     *  let store = this.get('store');
     *  let recordTypeName = this.getRecordTypeName(store.modelFor(obj.type));
     *  this.get('db').rel.find(recordTypeName, obj.id).then(function(doc){
     *    store.pushPayload(recordTypeName, doc);
     *  });
     */
  },

  willDestroy: function() {
    this._stopChangesListener();
  },

  _init: function (store, type) {
    var self = this,
        recordTypeName = this.getRecordTypeName(type);
    if (!this.get('db') || typeof this.get('db') !== 'object') {
      throw new Error('Please set the `db` property on the adapter.');
    }

    if (!Ember.get(type, 'attributes').has('rev')) {
      var modelName = classify(recordTypeName);
      throw new Error('Please add a `rev` attribute of type `string`' +
        ' on the ' + modelName + ' model.');
    }

    this._schema = this._schema || [];

    var singular = recordTypeName;
    var plural = pluralize(recordTypeName);

    // check that we haven't already registered this model
    for (var i = 0, len = this._schema.length; i < len; i++) {
      var currentSchemaDef = this._schema[i];
      if (currentSchemaDef.singular === singular) {
        return;
      }
    }

    var schemaDef = {
      singular: singular,
      plural: plural
    };

    if (type.documentType) {
      schemaDef['documentType'] = type.documentType;
    }

    let config = getOwner(this).resolveRegistration('config:environment');
    let dontsavedefault = config['emberpouch'] && config['emberpouch']['dontsavehasmany'];
    // else it's new, so update
    this._schema.push(schemaDef);
    // check all the subtypes
    // We check the type of `rel.type`because with ember-data beta 19
    // `rel.type` switched from DS.Model to string
    type.eachRelationship(function (_, rel) {
      if (rel.kind !== 'belongsTo' && rel.kind !== 'hasMany') {
        // TODO: support inverse as well
        return; // skip
      }
      var relDef = {},
          relModel = (typeof rel.type === 'string' ? store.modelFor(rel.type) : rel.type);
      if (relModel) {
        let includeRel = true;
        rel.options = rel.options || {};
        if (typeof(rel.options.async) === "undefined") {
          rel.options.async = config.emberpouch && !Ember.isEmpty(config.emberpouch.async) ? config.emberpouch.async : true;//default true from https://github.com/emberjs/data/pull/3366
        }
        let options = Object.create(rel.options);
        if (rel.kind === 'hasMany' && (options.dontsave || typeof(options.dontsave) === 'undefined' && dontsavedefault)) {
          let inverse = type.inverseFor(rel.key, store);
          if (inverse) {
            if (inverse.kind === 'belongsTo') {
              self.get('db').createIndex({index: { fields: ['data.' + inverse.name, '_id'] }});
              if (options.async) {
                includeRel = false;
              } else {
                options.queryInverse = inverse.name;
              }
            }
          }
        }

        if (includeRel) {
          relDef[rel.kind] = {
            type: self.getRecordTypeName(relModel),
            options: options
          };
          if (!schemaDef.relations) {
            schemaDef.relations = {};
          }
          schemaDef.relations[rel.key] = relDef;
        }
        self._init(store, relModel);
      }
    });

    this.get('db').setSchema(this._schema);
  },

  _recordToData: function (store, type, record) {
    var data = {};
    // Though it would work to use the default recordTypeName for modelName &
    // serializerKey here, these uses are conceptually distinct and may vary
    // independently.
    var modelName = type.modelName || type.typeKey;
    var serializerKey = camelize(modelName);
    var serializer = store.serializerFor(modelName);

    serializer.serializeIntoHash(
      data,
      type,
      record,
      {includeId: true}
    );

    data = data[serializerKey];

    // ember sets it to null automatically. don't need it.
    if (data.rev === null) {
      delete data.rev;
    }

    return data;
  },

  /**
   * Return key that conform to data adapter
   * ex: 'name' become 'data.name'
   */
  _dataKey: function(key) {
    var dataKey ='data.' + key;
    return ""+ dataKey + "";
  },

  /**
   * Returns the modified selector key to comform data key
   * Ex: selector: {name: 'Mario'} wil become selector: {'data.name': 'Mario'}
   */
  _buildSelector: function(selector) {
    var dataSelector = {};
    var selectorKeys = [];

    for (var key in selector) {
      if(selector.hasOwnProperty(key)){
        selectorKeys.push(key);
      }
    }

    selectorKeys.forEach(function(key) {
      var dataKey = this._dataKey(key);
      dataSelector[dataKey] = selector[key];
    }.bind(this));

    return dataSelector;
  },

  /**
   * Returns the modified sort key
   * Ex: sort: ['series'] will become ['data.series']
   * Ex: sort: [{series: 'desc'}] will became [{'data.series': 'desc'}]
   */
  _buildSort: function(sort) {
    return sort.map(function (value) {
      var sortKey = {};
      if (typeof value === 'object' && value !== null) {
        for (var key in value) {
          if(value.hasOwnProperty(key)){
            sortKey[this._dataKey(key)] = value[key];
          }
        }
      } else {
        return this._dataKey(value);
      }
      return sortKey;
    }.bind(this));
  },

  /**
   * Returns the string to use for the model name part of the PouchDB document
   * ID for records of the given ember-data type.
   *
   * This method uses the camelized version of the model name in order to
   * preserve data compatibility with older versions of ember-pouch. See
   * pouchdb-community/ember-pouch#63 for a discussion.
   *
   * You can override this to change the behavior. If you do, be aware that you
   * need to execute a data migration to ensure that any existing records are
   * moved to the new IDs.
   */
  getRecordTypeName(type) {
    return camelize(type.modelName);
  },

  findAll: function(store, type /*, sinceToken */) {
    // TODO: use sinceToken
    this._init(store, type);
    return this.get('db').rel.find(this.getRecordTypeName(type));
  },

  findMany: function(store, type, ids) {
    this._init(store, type);
    return this.get('db').rel.find(this.getRecordTypeName(type), ids);
  },

  findHasMany: function(store, record, link, rel) {
    let inverse = record.type.inverseFor(rel.key, store);
    if (inverse && inverse.kind === 'belongsTo') {
      return this.get('db').rel.findHasMany(camelize(rel.type), inverse.name, record.id);
    } else {
      let result = {};
      result[pluralize(rel.type)] = [];
      return result; //data;
    }
  },

  query: function(store, type, query) {
    this._init(store, type);

    var recordTypeName = this.getRecordTypeName(type);
    var db = this.get('db');

    var queryParams = {
      selector: this._buildSelector(query.filter)
    };

    if (!Ember.isEmpty(query.sort)) {
      queryParams.sort = this._buildSort(query.sort);
    }

    return db.find(queryParams).then(pouchRes => db.rel.parseRelDocs(recordTypeName, pouchRes.docs));
  },

  queryRecord: function(store, type, query) {
    return this.query(store, type, query).then(results => {
      let recordType = this.getRecordTypeName(type);
      let recordTypePlural = pluralize(recordType);
      if(results[recordTypePlural].length > 0){
        results[recordType] = results[recordTypePlural][0];
      } else {
        results[recordType] = null;
      }
      delete results[recordTypePlural];
      return results;
    });
  },

  /**
   * `find` has been deprecated in ED 1.13 and is replaced by 'new store
   * methods', see: https://github.com/emberjs/data/pull/3306
   * We keep the method for backward compatibility and forward calls to
   * `findRecord`. This can be removed when the library drops support
   * for deprecated methods.
  */
  find: function (store, type, id) {
    return this.findRecord(store, type, id);
  },

  findRecord: function (store, type, id) {
    this._init(store, type);
    var recordTypeName = this.getRecordTypeName(type);
    return this._findRecord(recordTypeName, id);
  },

  _findRecord(recordTypeName, id) {
    return this.get('db').rel.find(recordTypeName, id).then(payload => {
      // Ember Data chokes on empty payload, this function throws
      // an error when the requested data is not found
      if (typeof payload === 'object' && payload !== null) {
        var singular = recordTypeName;
        var plural = pluralize(recordTypeName);

        var results = payload[singular] || payload[plural];
        if (results && results.length > 0) {
          return payload;
        }
      }

      return this._eventuallyConsistent(recordTypeName, id);
    });
  },

  //TODO: cleanup promises on destroy or db change?
  waitingForConsistency: {},
  _eventuallyConsistent: function(type, id) {
    let pouchID = this.get('db').rel.makeDocID({type, id});
    let defer = Ember.RSVP.defer();
    this.waitingForConsistency[pouchID] = defer;

    return this.get('db').rel.isDeleted(type, id).then(deleted => {
      //TODO: should we test the status of the promise here? Could it be handled in onChange already?
      if (deleted) {
        delete this.waitingForConsistency[pouchID];
        throw "Document of type '" + type + "' with id '" + id + "' is deleted.";
      } else if (deleted === null) {
        return defer.promise;
      } else {
        Ember.assert('Status should be existing', deleted === false);
        //TODO: should we reject or resolve the promise? or does JS GC still clean it?
        if (this.waitingForConsistency[pouchID]) {
          delete this.waitingForConsistency[pouchID];
          return this._findRecord(type, id);
        } else {
          //findRecord is already handled by onChange
          return defer.promise;
        }
      }
    });
  },

  createRecord: function(store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.save(this.getRecordTypeName(type), data);
  },

  updateRecord: function (store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.save(this.getRecordTypeName(type), data);
  },

  deleteRecord: function (store, type, record) {
    this._init(store, type);
    var data = this._recordToData(store, type, record);
    return this.get('db').rel.del(this.getRecordTypeName(type), data)
      .then(extractDeleteRecord);
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';

const {
  isEmpty,
  computed,
  A: emberArray
} = Ember;

 /**
  * @module Classes
  * @class Column
  */
export default class Column extends Ember.Object.extend({
  /**
   * @property hidden
   * @type {Boolean}
   * @default false
   */
  hidden: false,

  /**
   * @property ascending
   * @type {Boolean}
   * @default true
   */
  ascending: true,

  /**
   * @property sortable
   * @type {Boolean}
   * @default true
   */
  sortable: true,

  /**
   * @property sorted
   * @type {Boolean}
   * @default false
   */
  sorted: false,

  /**
   * Column header label
   * @property label
   * @type {String}
   * @default ''
   */
  label: '',

  /**
   * Text alignment. Possible values are ['left', 'right', 'center']
   * @property align
   * @type {String}
   * @default 'left'
   */
  align: 'left',

  /**
   * An array of sub columns to be grouped together
   * @property subColumns
   * @type {Array}
   * @optional
   */
  subColumns: null,

  /**
   * Component name for the column header
   * @property headerComponent
   * @type {String}
   * @optional
   */
  headerComponent: null,

  /**
   * Component name for the column cells
   * @property cellComponent
   * @type {String}
   * @optional
   */
  cellComponent: null,

  /**
   * @property valuePath
   * @type {String}
   */
  valuePath: null,

  /**
   * @property width
   * @type {String}
   */
  width: null,

  /**
   * Class names to be applied to header and footer cells of this column
   *
   * @property classNames
   * @type {String | Array}
   */
  classNames: null,

  /**
   * Class names to be applied to all cells of this column
   *
   * @property cellClassNames
   * @type {String | Array}
   */
  cellClassNames: null,

  /**
   * A format function used to calculate a cell's value
   * @property format
   * @type {Function}
   */
  format: null,

  /**
   * @property isGroupColumn
   * @type {Boolean}
   * @private
   */
  isGroupColumn: computed.notEmpty('subColumns').readOnly(),

  /**
   * @property isVisibleGroupColumn
   * @type {Boolean}
   * @private
   */
  isVisibleGroupColumn: computed('visibleSubColumns.[]', 'hidden', function() {
    return !isEmpty(this.get('visibleSubColumns')) && !this.get('hidden');
  }).readOnly(),

  /**
   * @property visibleSubColumns
   * @type {Array}
   * @private
   */
  visibleSubColumns: computed('subColumns.@each.hidden', 'hidden', function() {
    let subColumns = this.get('subColumns');
    return isEmpty(subColumns) || this.get('hidden') ? [] : subColumns.filterBy('hidden', false);
  }).readOnly()
}) {
  /**
   * @class Column
   * @constructor
   * @param {Object} options
   */
  constructor(options = {}) {
    if(options instanceof Column) {
      return options;
    }

    super();
    this.setProperties(options);

    if(!isEmpty(options.subColumns)) {
      this.set('subColumns', emberArray(options.subColumns.map(sc => new Column(sc))));
    }
  }
}
<commit_msg>Add some clarification to docs (#31)<commit_after>import Ember from 'ember';

const {
  isEmpty,
  computed,
  A: emberArray
} = Ember;

 /**
  * @module Classes
  * @class Column
  */
export default class Column extends Ember.Object.extend({
  /**
   * @property hidden
   * @type {Boolean}
   * @default false
   */
  hidden: false,

  /**
   * @property ascending
   * @type {Boolean}
   * @default true
   */
  ascending: true,

  /**
   * @property sortable
   * @type {Boolean}
   * @default true
   */
  sortable: true,

  /**
   * @property sorted
   * @type {Boolean}
   * @default false
   */
  sorted: false,

  /**
   * Column header label
   * @property label
   * @type {String}
   * @default ''
   */
  label: '',

  /**
   * Text alignment. Possible values are ['left', 'right', 'center']
   * @property align
   * @type {String}
   * @default 'left'
   */
  align: 'left',

  /**
   * An array of sub columns to be grouped together
   * @property subColumns
   * @type {Array}
   * @optional
   */
  subColumns: null,

  /**
   * Component name for the column header
   * @property headerComponent
   * @type {String}
   * @optional
   */
  headerComponent: null,

  /**
   * Component name for the column cells. This component is automatically passed row,
   * column, and value variables, and you can specify a valuePath to set what property
   * the value is set to.
   * @property cellComponent
   * @type {String}
   * @optional
   */
  cellComponent: null,

  /**
   * @property valuePath
   * @type {String}
   */
  valuePath: null,

  /**
   * @property width
   * @type {String}
   */
  width: null,

  /**
   * Class names to be applied to header and footer cells of this column
   *
   * @property classNames
   * @type {String | Array}
   */
  classNames: null,

  /**
   * Class names to be applied to all cells of this column
   *
   * @property cellClassNames
   * @type {String | Array}
   */
  cellClassNames: null,

  /**
   * A format function used to calculate a cell's value
   * @property format
   * @type {Function}
   */
  format: null,

  /**
   * @property isGroupColumn
   * @type {Boolean}
   * @private
   */
  isGroupColumn: computed.notEmpty('subColumns').readOnly(),

  /**
   * @property isVisibleGroupColumn
   * @type {Boolean}
   * @private
   */
  isVisibleGroupColumn: computed('visibleSubColumns.[]', 'hidden', function() {
    return !isEmpty(this.get('visibleSubColumns')) && !this.get('hidden');
  }).readOnly(),

  /**
   * @property visibleSubColumns
   * @type {Array}
   * @private
   */
  visibleSubColumns: computed('subColumns.@each.hidden', 'hidden', function() {
    let subColumns = this.get('subColumns');
    return isEmpty(subColumns) || this.get('hidden') ? [] : subColumns.filterBy('hidden', false);
  }).readOnly()
}) {
  /**
   * @class Column
   * @constructor
   * @param {Object} options
   */
  constructor(options = {}) {
    if(options instanceof Column) {
      return options;
    }

    super();
    this.setProperties(options);

    if(!isEmpty(options.subColumns)) {
      this.set('subColumns', emberArray(options.subColumns.map(sc => new Column(sc))));
    }
  }
}
<|endoftext|>


<commit_before>const self = require("sdk/self");
const system = require("sdk/system");

exports.deviceInfo = function () {
  return {
    addonVersion: self.version,
    platform: system.platform,
    architecture: system.architecture,
    version: system.version,
    build: system.build,
    appName: system.name,
    platformVersion: system.platformVersion,
    appVendor: system.vendor
  };
};
<commit_msg>trailing whitespace<commit_after>const self = require("sdk/self");
const system = require("sdk/system");

exports.deviceInfo = function () {
  return {
    addonVersion: self.version,
    platform: system.platform,
    architecture: system.architecture,
    version: system.version,
    build: system.build,
    appName: system.name,
    platformVersion: system.platformVersion,
    appVendor: system.vendor
  };
};
<|endoftext|>


<commit_before>function __developerMode() {

    var defaultSettings= {
        title: 'Режим разработчика',
        description: 'Вы можете сами создавать новые аддоны. Если Вы хотите отредактировать аддон, который входит в состав основной сборки, то нужно при создании нового аддона выбрать аддон на основе которого хотите создать. После этого отключите встроенный аддон, а новый будет загружаться автоматически.
В настоящий момент нельзя смотреть страницу настроек таких скриптов- они всегда используют настройки по-умолчанию.
Все созданные таким образом скрипты загружаются всегда. После того, как закончите творить новый аддон, сохраните его в отдельный файл в utf-8+BOM и сделайте pull request в репозиторий.
Если произошла ошибка, то объект ошибки можно найти в консоли.',
        exports: {
            scripts:{type:"text", value:"[]", title:"нет в ордер, не показываются"},
            lastOpened:{type:"text", value:0, title:"hidden"},
            maxHighlightLength:{type:"text", value:Infinity, title:"Максимальная подсвечиваемая длина
(в символах или Infinity)"},
            settings:{type:"text", value:"{}", title:""}
        },
        order: ["maxHighlightLength"]
    };
    var addonName= arguments.callee.name;
    var settings= __addonsSettings.getUpdatedSettings( addonName, defaultSettings );
    var scripts= JSON.parse(settings.exports.scripts.value);
    var lastOpened= settings.exports.lastOpened.value;
    var css= "div.addons-DM {left: 5px; width: 98%; max-width:100%; max-height:100%;} img.addons-DM-icon {width:16px; height:16px; margin-right:10px} div.addons-DM-new {position:relative; top:30px; left:10px;}";
    __addonsAddCSS(css);

    var escapeHtml= function(text) {
      return text
          .replace(/&/g, "&")
          .replace(/</g, "<")
          .replace(/>/g, ">")
          .replace(/"/g, """)
          .replace(/'/g, "'");
    };

    var saveSettings= function(scripts, lastOpened, reloadPage){
        if (scripts!=null) settings.exports.scripts.value= JSON.stringify(scripts);
        if (lastOpened!=null) settings.exports.lastOpened.value= lastOpened;
        __addonsSettings.set(addonName, settings);
        if (reloadPage) location.reload();
    };

    var img= document.createElement("img");
    img.src="[DEPLOY:image64]images/iconDM.png[/DEPLOY]";
    img.className='cursor-pointer addons-DM-icon'; // из лоадера
    img.onclick= function(e) {
        div1.style.display= div1.style.display=="block" ? "none":"block";
    };
    $(img).insertBefore($("#__imageIcon")[0]);
    var imgRect= img.getBoundingClientRect();

    var div1= document.createElement('div');
    div1.className="addons-settings addons-DM"; // из лоадера
    div1.style.top=(imgRect.top+imgRect.height+5)+"px";
    div1.style.height= "90%";

    var html= "

<BUTTON onclick='$(\".addons-DM .addons-DM-new\").css(\"display\", \"block\");'>Новый...</BUTTON> <SELECT id='__addons_DM_selectScript' style='min-width:70px'>";
    for (var i in scripts) {
        html+="<OPTION value='"+i+"' "+(i==parseInt(lastOpened) ? "selected='selected' >":">")+scripts[i].replace(/^[\s\S]*?function\s+([^\(]+)\([\s\S]*$/, "$1")+"</OPTION>";
    };
    html+="</SELECT> <BUTTON id='__addons_DM_saveScript'>Сохранить</BUTTON> <BUTTON id='__addons_DM_saveAndUpdateScript'>Сохранить и обновить</BUTTON>	<BUTTON id='__addons_DM_deleteScript'>Удалить</BUTTON>

";
    // блок с новым скриптом
    html+="

<INPUT type=radio name=addons_DM_new_blank value=blank checked >Чистый	<INPUT type=text value='Имя функции' >

<INPUT type=radio name=addons_DM_new_blank value=clone >На основе	<SELECT>";
    for (var i in __addons) {
        var addon= __addonsSettings.settings[__addons[i]];
        var title= addon == undefined ? __addons[i] : addon.title;
        html+="<OPTION value='"+__addons[i]+"'>"+title+"</OPTION>";
    };
    html+="</SELECT>

<BUTTON id='__addons_DM_createNew' >Создать</BUTTON><BUTTON onclick='$(\".addons-DM .addons-DM-new\").css(\"display\", \"none\");' >Закрыть</BUTTON>
";
    // блок с CodeMirror
    html+="

";

    div1.innerHTML= html;
    document.body.appendChild(div1);

    var linkSS= document.createElement('link');
    linkSS.rel= "stylesheet";
    linkSS.type= "text/css";
    linkSS.href="http://localhost/temp/codemirror319/lib/codemirror.css";
    document.getElementsByTagName('head')[0].appendChild(linkSS);
    var script1= document.createElement("script");
    script1.src='http://localhost/temp/codemirror319/lib/codemirror.js';
    document.getElementsByTagName('head')[0].appendChild(script1);

    var editor; // глобалим
    var initCodeMirror= function(){
        img.onclick(); // наглый хак, но почему-то не происходит отрисовка CodeMirror в скрытый блок
        editor = CodeMirror(document.getElementById("__CodeMirrorArea"), {
            value: scripts[lastOpened]==undefined? 'Чтобы создать новый скрипт нажмите New':scripts[lastOpened],
            lineNumbers: true,
            maxHighlightLength: settings.exports.maxHighlightLength.value=="Infinity"?Infinity:parseInt(settings.exports.maxHighlightLength.value)
        });
        editor.display.scroller.parentNode.style.height="100%";
        img.onclick();
    };
    var fixSlowLoading= function() {
        if (typeof(CodeMirror)=="undefined") return;
        var script2= document.createElement("script");
        script2.src='http://localhost/temp/codemirror319/mode/javascript/javascript.js';
        document.getElementsByTagName('head')[0].appendChild(script2);
        window.setTimeout(initCodeMirror, 50);
        clearInterval(interval);
    };
    var interval= window.setInterval(fixSlowLoading, 50);

    $("#__addons_DM_createNew").bind('click', function(){
        var name=$(".addons-DM-new input[type='text']")[0].value.replace(/^\s+|\s+$/, '');
        var blankInputs= $(".addons-DM-new input[type='radio']");
        for (var i =0; i<blankInputs.length; i++) if (blankInputs[i].checked) var blank=blankInputs[i].value;
        if (blank=="clone") {
            var text= window[$(".addons-DM-new select")[0].value].toString();
        } else {
            if (name=="") {
                alert("Имя не задано");
                return
            };
            var text="function "+name+"() {\n    var defaultSettings= {\n        title: '',\n        description: '',\n        exports: {\n        },\n        order: []\n    };\n    var settings= __addonsSettings.getUpdatedSettings( arguments.callee.name, defaultSettings );\n};\n";
        };
        scripts.push(text);
        saveSettings(scripts, lastOpened, true);
    });
    $('#__addons_DM_selectScript').bind("change", function(){
        scripts[lastOpened]= editor.doc.getValue();
        lastOpened= parseInt(this.value);
        saveSettings(null, lastOpened, false);
        if (typeof(editor)!= "undefined") editor.doc.setValue( scripts[lastOpened] );
    });
    $('#__addons_DM_deleteScript').bind("click", function() {
        var item= parseInt($('#__addons_DM_selectScript')[0].value);
        lastOpened= 0;
        scripts= scripts.slice(0, item).concat(scripts.slice(item+1));
        saveSettings(scripts, lastOpened, true);
    });
    $("#__addons_DM_saveScript").bind("click", function() {
        scripts[lastOpened]= editor.doc.getValue();
        saveSettings(scripts, lastOpened, false);
    });
    $("#__addons_DM_saveAndUpdateScript").bind("click", function() {
        scripts[lastOpened]= editor.doc.getValue();
        saveSettings(scripts, lastOpened, true);
    });

    var glush= "var __addonsSettings=new (function () {this.settings={}; this.get=function(addonName) {return this.settings[addonName];}; this.set= function(){}; this.getUpdatedSettings= function(addonName, defaultSettings) {this.settings[addonName]= defaultSettings;return defaultSettings;};})();"
    for (var i in scripts) {
        console.log('Запуск функции '+ $("#__addons_DM_selectScript option")[i].innerHTML);
        var scr= document.createElement('script');
        scr.innerHTML=glush+"\n("+scripts[i].replace(/\}[^\}]*?$/, "})();");
        document.getElementsByTagName('head')[0].appendChild(scr);
    };
};
<commit_msg>готово<commit_after>function __developerMode() {

    var defaultSettings= {
        title: 'Режим разработчика',
        description: 'Вы можете сами создавать новые аддоны. Если Вы хотите отредактировать аддон, который входит в состав основной сборки, то нужно при создании нового аддона выбрать аддон на основе которого хотите создать. После этого отключите встроенный аддон, а новый будет загружаться автоматически.
В настоящий момент нельзя смотреть страницу настроек таких скриптов- они всегда используют настройки по-умолчанию.
Все созданные таким образом скрипты загружаются всегда. После того, как закончите творить новый аддон, сохраните его в отдельный файл в utf-8+BOM и сделайте pull request в репозиторий.
Если произошла ошибка, то объект ошибки можно найти в консоли.',
        exports: {
            scripts:{type:"text", value:"[]", title:"нет в ордер, не показываются"},
            lastOpened:{type:"text", value:0, title:"hidden"},
            maxHighlightLength:{type:"text", value:"Infinity", title:"Максимальная подсвечиваемая длина
(в символах или Infinity)"},
            fontSize: {type:"text", value:'14px', title:'Размер шрифта в редакторе'},
            settings:{type:"text", value:"{}", title:""}
        },
        order: ["maxHighlightLength", "fontSize"]
    };
    var addonName= arguments.callee.name;
    var settings= __addonsSettings.getUpdatedSettings( addonName, defaultSettings );
    var scripts= JSON.parse(settings.exports.scripts.value);
    var lastOpened= settings.exports.lastOpened.value;
    var css= "div.addons-DM {left: 5px; width: 98%; max-width:100%; max-height:100%;} img.addons-DM-icon {width:16px; height:16px; margin-right:10px} div.addons-DM-new {position:relative; top:30px; left:10px;}";
    __addonsAddCSS(css);

    var escapeHtml= function(text) {
      return text
          .replace(/&/g, "&")
          .replace(/</g, "<")
          .replace(/>/g, ">")
          .replace(/"/g, """)
          .replace(/'/g, "'");
    };

    var saveSettings= function(scripts, lastOpened, reloadPage){
        if (scripts!=null) settings.exports.scripts.value= JSON.stringify(scripts);
        if (lastOpened!=null) settings.exports.lastOpened.value= lastOpened;
        __addonsSettings.set(addonName, settings);
        if (reloadPage) location.reload();
    };

    var img= document.createElement("img");
    img.src="[DEPLOY:image64]images/iconDM.png[/DEPLOY]";
    img.className='cursor-pointer addons-DM-icon'; // из лоадера
    img.onclick= function(e) {
        div1.style.display= div1.style.display=="block" ? "none":"block";
    };
    $(img).insertBefore($("#__imageIcon")[0]);
    var imgRect= img.getBoundingClientRect();

    var div1= document.createElement('div');
    div1.className="addons-settings addons-DM"; // из лоадера
    div1.style.top=(imgRect.top+imgRect.height+5)+"px";
    div1.style.height= "90%";

    var html= "

<BUTTON onclick='$(\".addons-DM .addons-DM-new\").css(\"display\", \"block\");'>Новый...</BUTTON> <SELECT id='__addons_DM_selectScript' style='min-width:70px'>";
    for (var i in scripts) {
        html+="<OPTION value='"+i+"' "+(i==parseInt(lastOpened) ? "selected='selected' >":">")+scripts[i].replace(/^[\s\S]*?function\s+([^\(]+)\([\s\S]*$/, "$1")+"</OPTION>";
    };
    html+="</SELECT> <BUTTON id='__addons_DM_saveScript'>Сохранить</BUTTON> <BUTTON id='__addons_DM_saveAndUpdateScript'>Сохранить и обновить</BUTTON>	<BUTTON id='__addons_DM_deleteScript'>Удалить</BUTTON>

";
    // блок с новым скриптом
    html+="

<INPUT type=radio name=addons_DM_new_blank value=blank checked >Чистый	<INPUT type=text value='Имя функции' >

<INPUT type=radio name=addons_DM_new_blank value=clone >На основе	<SELECT>";
    for (var i in __addons) {
        var addon= __addonsSettings.settings[__addons[i]];
        var title= addon == undefined ? __addons[i] : addon.title;
        html+="<OPTION value='"+__addons[i]+"'>"+title+"</OPTION>";
    };
    html+="</SELECT>

<BUTTON id='__addons_DM_createNew' >Создать</BUTTON><BUTTON onclick='$(\".addons-DM .addons-DM-new\").css(\"display\", \"none\");' >Закрыть</BUTTON>
";
    // блок с CodeMirror
    html+="

";

    div1.innerHTML= html;
    document.body.appendChild(div1);

    var linkSS= document.createElement('link');
    linkSS.rel= "stylesheet";
    linkSS.type= "text/css";
    linkSS.href="http://localhost/temp/codemirror319/lib/codemirror.css";
    document.getElementsByTagName('head')[0].appendChild(linkSS);
    var script1= document.createElement("script");
    script1.src='http://localhost/temp/codemirror319/lib/codemirror.js';
    document.getElementsByTagName('head')[0].appendChild(script1);

    var editor; // глобалим
    var initCodeMirror= function(){
        img.onclick(); // наглый хак, но почему-то не происходит отрисовка CodeMirror в скрытый блок
        editor = CodeMirror(document.getElementById("__CodeMirrorArea"), {
            value: scripts[lastOpened]==undefined? 'Чтобы создать новый скрипт нажмите New':scripts[lastOpened],
            lineNumbers: true,
            maxHighlightLength: settings.exports.maxHighlightLength.value=="Infinity"?Infinity:parseInt(settings.exports.maxHighlightLength.value)
        });
        editor.display.scroller.parentNode.style.height="100%";
        editor.display.scroller.style.fontSize= settings.fontSize;
        img.onclick();
    };
    var fixSlowLoading= function() {
        if (typeof(CodeMirror)=="undefined") return;
        var script2= document.createElement("script");
        script2.src='http://localhost/temp/codemirror319/mode/javascript/javascript.js';
        document.getElementsByTagName('head')[0].appendChild(script2);
        window.setTimeout(initCodeMirror, 50);
        clearInterval(interval);
    };
    var interval= window.setInterval(fixSlowLoading, 50);

    $("#__addons_DM_createNew").bind('click', function(){
        var name=$(".addons-DM-new input[type='text']")[0].value.replace(/^\s+|\s+$/, '');
        var blankInputs= $(".addons-DM-new input[type='radio']");
        for (var i =0; i<blankInputs.length; i++) if (blankInputs[i].checked) var blank=blankInputs[i].value;
        if (blank=="clone") {
            var text= window[$(".addons-DM-new select")[0].value].toString();
        } else {
            if (name=="") {
                alert("Имя не задано");
                return
            };
            var text="function "+name+"() {\n    var defaultSettings= {\n        title: '',\n        description: '',\n        exports: {\n        },\n        order: []\n    };\n    var settings= __addonsSettings.getUpdatedSettings( arguments.callee.name, defaultSettings );\n};\n";
        };
        scripts.push(text);
        saveSettings(scripts, lastOpened, true);
    });
    $('#__addons_DM_selectScript').bind("change", function(){
        scripts[lastOpened]= editor.doc.getValue();
        lastOpened= parseInt(this.value);
        saveSettings(null, lastOpened, false);
        if (typeof(editor)!= "undefined") editor.doc.setValue( scripts[lastOpened] );
    });
    $('#__addons_DM_deleteScript').bind("click", function() {
        var item= parseInt($('#__addons_DM_selectScript')[0].value);
        lastOpened= 0;
        scripts= scripts.slice(0, item).concat(scripts.slice(item+1));
        saveSettings(scripts, lastOpened, true);
    });
    $("#__addons_DM_saveScript").bind("click", function() {
        scripts[lastOpened]= editor.doc.getValue();
        saveSettings(scripts, lastOpened, false);
    });
    $("#__addons_DM_saveAndUpdateScript").bind("click", function() {
        scripts[lastOpened]= editor.doc.getValue();
        saveSettings(scripts, lastOpened, true);
    });

    var glush= "var __addonsSettings=new (function () {this.settings={}; this.get=function(addonName) {return this.settings[addonName];}; this.set= function(){}; this.getUpdatedSettings= function(addonName, defaultSettings) {this.settings[addonName]= defaultSettings;return defaultSettings;};})();"
    for (var i in scripts) {
        console.log('Запуск функции '+ $("#__addons_DM_selectScript option")[i].innerHTML);
        var scr= document.createElement('script');
        scr.innerHTML= "("+scripts[i].replace(/\}[^\}]*?$/, "})();").replace(/^([^\{]*\{)/, "$1"+glush);
        document.getElementsByTagName('head')[0].appendChild(scr);
    };
};
<|endoftext|>


<commit_before>var React = require('react');
var utils = require('keystone-utils');
var CreateForm = require('../components/CreateForm');
var Toolbar = require('../components/Toolbar');

var Button = require('elemental').Button;
var Dropdown = require('elemental').Dropdown;

var View = React.createClass({

	displayName: 'ListView',

	getInitialState: function() {
		return {
			createIsVisible: Keystone.showCreateForm,
			animateCreateForm: false
		};
	},

	toggleCreate: function(visible) {
		this.setState({
			createIsVisible: visible,
			animateCreateForm: true
		});
	},

	renderCreateButton: function() {
		var props = { type: 'success' };
		if (Keystone.list.autocreate) {
			props.href = '?new' + Keystone.csrf.query;
		} else {
			props.onClick = this.toggleCreate.bind(this, true);
		}
		return (
			<Button {...props}>

				Create {Keystone.list.singular}
			</Button>
		);
	},

	renderCreateForm: function() {
		if (!this.state.createIsVisible) return null;
		return <CreateForm list={Keystone.list} animate={this.state.animateCreateForm} onCancel={this.toggleCreate.bind(this, false)} values={Keystone.createFormData} err={Keystone.createFormErrors} />;
	},

	render: function() {
		if (Keystone.list.nocreate) return null;
		return (
			<Toolbar>
				<Toolbar.Section left>
					{this.renderCreateButton()}
					{this.renderCreateForm()}
				</Toolbar.Section>
				<Toolbar.Section right>
					<Button type="link">

						Recent Filters
					</Button>
					<Button type="link">

						Download
					</Button>
				</Toolbar.Section>
			</Toolbar>
		);
	}

});

/*
	==============================
	SORT DROPDOWN
	==============================
*/

var ListSortDropdown = React.createClass({

	displayName: 'ListSortDropdown',

	getInitialState: function() {
		return {};
	},

	menuItems: function() {
		return Keystone.list.uiElements.map(function(item, i) {
			if (item.type === 'heading') {
				return { type: 'header', label: item.content };
			} else {
				return { type: 'item', label: utils.titlecase(item.field) };
			}
		});
	},

	renderDropdown: function() {
		var sort = Keystone.sort;
		var buttonLabel = 'sort by';

		if (sort.label) {
			buttonLabel = sort.label.toLowerCase();

			if (sort.inv) {
				buttonLabel += ' (descending)';
			}
		}

		return (
			<Dropdown items={this.menuItems()} component='span'>
				{buttonLabel}
			</Dropdown>
		);
	},

	render: function() {
		return this.renderDropdown();
	}

});

React.render(<View />, document.getElementById('list-view'));
React.render(<ListSortDropdown />, document.getElementById('list-sort-dropdown'));<commit_msg>list: sorting in react<commit_after>var React = require('react');
var utils = require('keystone-utils');
var CreateForm = require('../components/CreateForm');
var Toolbar = require('../components/Toolbar');

var Button = require('elemental').Button;
var Dropdown = require('elemental').Dropdown;

var View = React.createClass({

	displayName: 'ListView',

	getInitialState: function() {
		return {
			createIsVisible: Keystone.showCreateForm,
			animateCreateForm: false
		};
	},

	toggleCreate: function(visible) {
		this.setState({
			createIsVisible: visible,
			animateCreateForm: true
		});
	},

	renderCreateButton: function() {
		var props = { type: 'success' };
		if (Keystone.list.autocreate) {
			props.href = '?new' + Keystone.csrf.query;
		} else {
			props.onClick = this.toggleCreate.bind(this, true);
		}
		return (
			<Button {...props}>

				Create {Keystone.list.singular}
			</Button>
		);
	},

	renderCreateForm: function() {
		if (!this.state.createIsVisible) return null;
		return <CreateForm list={Keystone.list} animate={this.state.animateCreateForm} onCancel={this.toggleCreate.bind(this, false)} values={Keystone.createFormData} err={Keystone.createFormErrors} />;
	},

	render: function() {
		if (Keystone.list.nocreate) return null;
		return (
			<Toolbar>
				<Toolbar.Section left>
					{this.renderCreateButton()}
					{this.renderCreateForm()}
				</Toolbar.Section>
				<Toolbar.Section right>
					<Dropdown alignRight items={[{ label: 'Listing state matches "published"' },{ label: 'Email matches "gmail"' }]}>
						<Button type="link">

							Recent Filters
						</Button>
					</Dropdown>
					<Button type="link">

						Download
					</Button>
				</Toolbar.Section>
			</Toolbar>
		);
	}

});

/*
	==============================
	SORT DROPDOWN
	==============================
*/

var ListSortDropdown = React.createClass({

	displayName: 'ListSortDropdown',

	getInitialState: function() {
		return {
			sortOrder: Keystone.sort
		};
	},

	handleSortChange: function(newSortOrder) {
		// handle state later, for now just use old querystring method
		console.log('/keystone/' + Keystone.list.plural.toLowerCase() + '?sort=' + utils.camelcase(newSortOrder, true));
		var listParam = '/keystone/' + Keystone.list.plural.toLowerCase();
		var sortParam = '?sort=' + utils.camelcase(newSortOrder, true).replace(/\s+/g, '');

		window.location = listParam.concat(sortParam);
	},

	menuItems: function() {
		return Keystone.list.uiElements.map(function(item, i) {
			if (item.type === 'heading') {
				return { type: 'header', label: item.content };
			} else {
				return { type: 'item', label: utils.titlecase(item.field) };
			}
		});
	},

	renderDropdown: function() {
		var sort = this.state.sortOrder;
		var buttonLabel = 'sort by';

		if (sort) {
			buttonLabel = utils.titlecase(sort).toLowerCase();

			if (sort.inv) {
				buttonLabel += ' (descending)';
			}
		}

		return (
			<Dropdown items={this.menuItems()} onSelect={this.handleSortChange} component='span'>

					{buttonLabel}

			</Dropdown>
		);
	},

	render: function() {
		return this.renderDropdown();
	}

});

React.render(<View />, document.getElementById('list-view'));
React.render(<ListSortDropdown />, document.getElementById('list-sort-dropdown'));<|endoftext|>