<commit_before>const DEFAULT_DOWNLOAD_LINK = 'http://miuiandroid.com/community/link-forums/roms.73/';
var devices = {};
// save this in db
var version = '2.4.13';
function sortObject(o) {
	var sorted = {},
	key, a = [];

	for (key in o) {
		if (o.hasOwnProperty(key)) {
			a.push(key);
		}
	}

	a.sort();
	for (key = 0; key < a.length; key++) {
		sorted[a[key]] = o[a[key]];
	}
	return sorted;
}
var addDevice = function(manufacturer, name, model, download_link){
	if(!download_link){
		download_link = DEFAULT_DOWNLOAD_LINK;
	}
	if(!devices[manufacturer]){
		devices[manufacturer] = {};
	}
	devices[manufacturer][name] = {};
	devices[manufacturer][name]['name'] = name;
	devices[manufacturer][name]['model'] = model;
	devices[manufacturer][name]['download_link'] = download_link;
	devices = sortObject(devices);
}
var removeDevice = function(manufacturer, name){
	if(devices[manufacturer] && devices[manufacturer][name]){
		delete devices[manufacturer][name];
	}
	devices = sortObject(devices);
}
var getDevice = function(name){
	for(manufacturer in devices){
		if(devices[manufacturer] && devices[manufacturer][name] && devices[manufacturer][name]['name'] == name){
			return devices[manufacturer][name];
		}
	};
}
var getDevices = function(manufacturer){
	var result = {}, device;
	if(manufacturer){
		return devices[manufacturer];
	}else{
		for(manufacturer in devices){
			for(device in devices[manufacturer]){
				device = devices[manufacturer][device];
				result[device.name] = device;
			}
		}
	}
	return result;
}
exports.init = function(plugins, bot){
	bot.addCommand('supported', 'Shows supported devices', '[<manufacturer>]', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('downloads', 'Shows download link(s)', '[<device_name>]', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('stats', 'Link to stats', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('forums', 'Link to forums', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('logcat', 'Link to logcat', '', USER_LEVEL_GLOBAL, undefined, true);
        bot.addCommand('bugs', 'Link to bugs', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('addDevice', '[<device>]', 'Adds device', USER_LEVEL_ADMIN, undefined);
	//bot.addCommand('changeDevice', '[<device>]', 'Changes device', USER_LEVEL_ADMIN);
	bot.addCommand('removeDevice', '[<device>]', 'Removes device', USER_LEVEL_ADMIN);
	bot.addCommand('updateVersion', '[<version>]', 'Updates version', USER_LEVEL_ADMIN);
	// Devices
		addDevice('google', 'Galaxy Nexus', 'GT-I9250', 'http://files.miuiandroid.com/VERSION/miuiandroid_GNEX-VERSION.zip');
		addDevice('google', 'NexusS', 'GT-I9020', 'http://files.miuiandroid.com/VERSION/miuiandroid_NS-VERSION.zip');
		addDevice('google', 'NexusOne', 'PB99100', 'http://files.miuiandroid.com/VERSION/miuiandroid_N1-VERSION.zip');
		addDevice('samsung', 'GalaxyS2', 'GT-I9100', 'http://files.miuiandroid.com/VERSION/miuiandroid_SGS2-VERSION.zip');
		addDevice('samsung', 'Captivate', 'SGH-I897', 'http://files.miuiandroid.com/VERSION/miuiandroid_Captivate-VERSION.zip');
		addDevice('samsung', 'GalaxyS', 'I9000', 'http://files.miuiandroid.com/VERSION/miuiandroid_i9100-VERSION.zip');
		addDevice('motorola', 'Defy', '?', 'http://files.miuiandroid.com/VERSION/miuiandroid_Defy-VERSION.zip');
		addDevice('motorola', 'Milestone', 'A853', 'http://files.miuiandroid.com/VERSION/miuiandroid_Milestone-VERSION.zip');
		addDevice('htc', 'Sensation', 'Z710e', 'http://files.miuiandroid.com/VERSION/miuiandroid_Sensation-VERSION.zip');
		addDevice('htc', 'Desire', 'A8181', 'http://files.miuiandroid.com/VERSION/miuiandroid_Desire-VERSION.zip');
		addDevice('htc', 'DesireZ', 'Saga', 'http://files.miuiandroid.com/VERSION/miuiandroid_DesireZ-VERSION.zip');
		addDevice('htc', 'DesireS', 'A7272', 'http://files.miuiandroid.com/VERSION/miuiandroid_DesireS-VERSION.zip');
		addDevice('htc', 'DesireHD', 'A9191', 'http://files.miuiandroid.com/VERSION/miuiandroid_DHD-VERSION.zip');
		addDevice('htc', 'HD2', 'T8585', 'http://files.miuiandroid.com/VERSION/miuiandroid_HD2-VERSION.zip');
		addDevice('htc', 'IncredibleS', 'S710e', 'http://files.miuiandroid.com/VERSION/miuiandroid_IncredibleS-VERSION.zip');
		addDevice('huawei', 'Honor', 'U8860', 'http://files.miuiandroid.com/VERSION/miuiandroid_Honor-VERSION.zip');
		addDevice('xiaomi', 'MI-ONE', 'MI-ONE+', 'http://files.miuiandroid.com/VERSION/update.zip');
		addDevice('lg', 'Optimus2x', 'P990', 'http://files.miuiandroid.com/VERSION/miuiandroid_Optimus2x-VERSION.zip');
	plugins.listen(this, 'command', function(args){
		var level = bot.getUserLevel(args.user, args.host);
		if(!bot.isCommand(args.command, level)){
			return;
		}
		switch(args.command){
			case 'downloads':
				if(args.arguments && args.arguments[0]){
					device = getDevice(args.arguments[0]);
					if(typeof device == 'object'){
						IRC.message(args.channel, 'Download at: ' + device['download_link'].replace(/VERSION/ig, version));
					}else{
						IRC.message(args.channel, 'Device is not supported!');
					}
				}else{
					IRC.message(args.channel, 'Downloads: ' + DEFAULT_DOWNLOAD_LINK);
				}
			break;
			case 'supported':
				var supported, msg = '';
				if(args.arguments && args.arguments[0]){
					supported = getDevices(args.arguments[0]);
				}else{
					supported = getDevices();
				}
				for(device in supported){
					msg += supported[device]['name'] + ' ';
				};
				if(msg){
					IRC.message(args.channel, 'Supported devices: ' + msg);
				}else{
					IRC.message(args.channel, 'That manufacturer is not supported!');
				}
			break;
			case 'addDevice':
				if(args.arguments && args.arguments[0] && args.arguments[1] && args.arguments[2]){
					var manufacturer = args.arguments[0];
					var name = args.arguments[1];
					var model = args.arguments[2];
					var download_link = args.arguments[3] ? args.arguments[3] : DEFAULT_DOWNLOAD_LINK;
					addDevice(manufacturer, name, model, download_link);
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'removeDevice':
				if(args.arguments && args.arguments[0] && args.arguments[1]){
					var manufacturer = args.arguments[0];
					var name = args.arguments[1];
					if(removeDevice(manufacturer, device)){
						IRC.message(args.channel, 'Device removed!');
					}else{
						IRC.message(args.channel, 'Not a valid device or manufacturer!');
					}
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'updateVersion':
				if(args.arguments && args.arguments[0]) {
					var new_version = args.arguments[0];
					if(version = new_version){
						IRC.message(args.channel, 'Version changed!');
					}
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'forums':
				IRC.message(args.channel, 'Forum: http://miuiandroid.com/community/forum/');
			break;
			case 'stats':
				IRC.message(args.channel, 'Stats: http:/stats.miuiandroid.com/');
			break;
			case 'logcat':
				IRC.message(args.channel, 'Logcat: http://logcat.miuiandroid.com/');
			break;
			case 'bugs':
				IRC.message(args.channel, 'Bugs: http://miuiandroid.com/community/forums/bugs.20/');
			break;
		}
	});
}
<commit_msg>more miui fixes<commit_after>const DEFAULT_DOWNLOAD_LINK = 'http://miuiandroid.com/community/link-forums/roms.73/';
var devices = {};
// save this in db
var version = '2.4.13';
function sortObject(o) {
	var sorted = {},
	key, a = [];

	for (key in o) {
		if (o.hasOwnProperty(key)) {
			a.push(key);
		}
	}

	a.sort();
	for (key = 0; key < a.length; key++) {
		sorted[a[key]] = o[a[key]];
	}
	return sorted;
}
var addDevice = function(manufacturer, name, model, download_link){
	if(!download_link){
		download_link = DEFAULT_DOWNLOAD_LINK;
	}
	if(!devices[manufacturer]){
		devices[manufacturer] = {};
	}
	devices[manufacturer][name] = {};
	devices[manufacturer][name]['name'] = name;
	devices[manufacturer][name]['model'] = model;
	devices[manufacturer][name]['download_link'] = download_link;
	devices = sortObject(devices);
}
var removeDevice = function(manufacturer, name){
	if(devices[manufacturer] && devices[manufacturer][name]){
		delete devices[manufacturer][name];
	}
	devices = sortObject(devices);
}
var getDevice = function(name){
	for(manufacturer in devices){
		if(devices[manufacturer] && devices[manufacturer][name] && devices[manufacturer][name]['name'] == name){
			return devices[manufacturer][name];
		}
	};
}
var getDevices = function(manufacturer){
	var result = {}, device;
	if(manufacturer){
		return devices[manufacturer];
	}else{
		for(manufacturer in devices){
			for(device in devices[manufacturer]){
				device = devices[manufacturer][device];
				result[device.name] = device;
			}
		}
	}
	return result;
}
exports.init = function(plugins, bot){
	bot.addCommand('supported', 'Shows supported devices', '[<manufacturer>]', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('downloads', 'Shows download link(s)', '[<device_name>]', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('stats', 'Link to stats', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('forums', 'Link to forums', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('logcat', 'Link to logcat', '', USER_LEVEL_GLOBAL, undefined, true);
        bot.addCommand('bugs', 'Link to bugs', '', USER_LEVEL_GLOBAL, undefined, true);
	bot.addCommand('addDevice', '[<device>]', 'Adds device', USER_LEVEL_ADMIN, undefined);
	//bot.addCommand('changeDevice', '[<device>]', 'Changes device', USER_LEVEL_ADMIN);
	bot.addCommand('removeDevice', '[<device>]', 'Removes device', USER_LEVEL_ADMIN);
	bot.addCommand('updateVersion', '[<version>]', 'Updates version', USER_LEVEL_ADMIN);
	// Devices
		addDevice('google', 'GalaxyNexus', 'GT-I9250', 'http://files.miuiandroid.com/VERSION/miuiandroid_GNEX-VERSION.zip');
		addDevice('google', 'NexusS', 'GT-I9020', 'http://files.miuiandroid.com/VERSION/miuiandroid_NS-VERSION.zip');
		addDevice('google', 'NexusOne', 'PB99100', 'http://files.miuiandroid.com/VERSION/miuiandroid_N1-VERSION.zip');
		addDevice('samsung', 'GalaxyS2', 'GT-I9100', 'http://files.miuiandroid.com/VERSION/miuiandroid_SGS2-VERSION.zip');
		addDevice('samsung', 'Captivate', 'SGH-I897', 'http://files.miuiandroid.com/VERSION/miuiandroid_Captivate-VERSION.zip');
		addDevice('samsung', 'GalaxyS', 'I9000', 'http://files.miuiandroid.com/VERSION/miuiandroid_i9100-VERSION.zip');
		addDevice('motorola', 'Defy', '?', 'http://files.miuiandroid.com/VERSION/miuiandroid_Defy-VERSION.zip');
		addDevice('motorola', 'Milestone', 'A853', 'http://files.miuiandroid.com/VERSION/miuiandroid_Milestone-VERSION.zip');
		addDevice('htc', 'Sensation', 'Z710e', 'http://files.miuiandroid.com/VERSION/miuiandroid_Sensation-VERSION.zip');
		addDevice('htc', 'Desire', 'A8181', 'http://files.miuiandroid.com/VERSION/miuiandroid_Desire-VERSION.zip');
		addDevice('htc', 'DesireZ', 'Saga', 'http://files.miuiandroid.com/VERSION/miuiandroid_DesireZ-VERSION.zip');
		addDevice('htc', 'DesireS', 'A7272', 'http://files.miuiandroid.com/VERSION/miuiandroid_DesireS-VERSION.zip');
		addDevice('htc', 'DesireHD', 'A9191', 'http://files.miuiandroid.com/VERSION/miuiandroid_DHD-VERSION.zip');
		addDevice('htc', 'HD2', 'T8585', 'http://files.miuiandroid.com/VERSION/miuiandroid_HD2-VERSION.zip');
		addDevice('htc', 'IncredibleS', 'S710e', 'http://files.miuiandroid.com/VERSION/miuiandroid_IncredibleS-VERSION.zip');
		addDevice('huawei', 'Honor', 'U8860', 'http://files.miuiandroid.com/VERSION/miuiandroid_Honor-VERSION.zip');
		addDevice('xiaomi', 'MI-ONE', 'MI-ONE+', 'http://files.miuiandroid.com/VERSION/update.zip');
		addDevice('lg', 'Optimus2x', 'P990', 'http://files.miuiandroid.com/VERSION/miuiandroid_Optimus2x-VERSION.zip');
	plugins.listen(this, 'command', function(args){
		var level = bot.getUserLevel(args.user, args.host);
		if(!bot.isCommand(args.command, level)){
			return;
		}
		switch(args.command){
			case 'downloads':
				if(args.arguments && args.arguments[0]){
					device = getDevice(args.arguments[0]);
					if(typeof device == 'object'){
						IRC.message(args.channel, 'Download at: ' + device['download_link'].replace(/VERSION/ig, version));
					}else{
						IRC.message(args.channel, 'Device is not supported!');
					}
				}else{
					IRC.message(args.channel, 'Downloads: ' + DEFAULT_DOWNLOAD_LINK);
				}
			break;
			case 'supported':
				var supported, msg = '';
				if(args.arguments && args.arguments[0]){
					supported = getDevices(args.arguments[0]);
				}else{
					supported = getDevices();
				}
				for(device in supported){
					msg += supported[device]['name'] + ' ';
				};
				if(msg){
					IRC.message(args.channel, 'Supported devices: ' + msg);
				}else{
					IRC.message(args.channel, 'That manufacturer is not supported!');
				}
			break;
			case 'addDevice':
				if(args.arguments && args.arguments[0] && args.arguments[1] && args.arguments[2]){
					var manufacturer = args.arguments[0];
					var name = args.arguments[1];
					var model = args.arguments[2];
					var download_link = args.arguments[3] ? args.arguments[3] : DEFAULT_DOWNLOAD_LINK;
					addDevice(manufacturer, name, model, download_link);
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'removeDevice':
				if(args.arguments && args.arguments[0] && args.arguments[1]){
					var manufacturer = args.arguments[0];
					var name = args.arguments[1];
					if(removeDevice(manufacturer, device)){
						IRC.message(args.channel, 'Device removed!');
					}else{
						IRC.message(args.channel, 'Not a valid device or manufacturer!');
					}
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'updateVersion':
				if(args.arguments && args.arguments[0]) {
					var new_version = args.arguments[0];
					if(version = new_version){
						IRC.message(args.channel, 'Version changed!');
					}
				}else{
					IRC.message(args.channel, 'Not enough arguments!');
				}
			break;
			case 'forums':
				IRC.message(args.channel, 'Forum: http://miuiandroid.com/community/forum/');
			break;
			case 'stats':
				IRC.message(args.channel, 'Stats: http:/stats.miuiandroid.com/');
			break;
			case 'logcat':
				IRC.message(args.channel, 'Logcat: http://logcat.miuiandroid.com/');
			break;
			case 'bugs':
				IRC.message(args.channel, 'Bugs: http://miuiandroid.com/community/forums/bugs.20/');
			break;
		}
	});
}
<|endoftext|>


<commit_before>var HexConnector = function () {
    var self = this;

    var initializedAdapters = {};
    var adapterConfigs = {};

    this.adapters = {};
    this.container = {};

    this.registerAdapter = function (port, adapter, config, withoutInit) {
        initializedAdapters[port] = false;
        adapterConfigs[port] = config || {};

        if (adapter instanceof Object) {
            self.adapters[port] = adapter;
        } else {
            delete require.cache[require.resolve(adapter)]
            self.adapters[port] = require(adapter);
        }

        if (!withoutInit && typeof self.adapters[port].initAdapter === 'function') {
            _initAdapter(port);
        }
    };

    this.getAdapter = function (port) {
        var adapter = self.adapters[port];

        if (adapter && !initializedAdapters[port] && typeof adapter.initAdapter === 'function') {
            _initAdapter(port);
        }

        return adapter;
    }

    this._set = function (k, v) {
        self.container[k] = v;
    };

    this._get = function (k) {
        return self.container[k];
    };

    function _initAdapter(port) {
        self.adapters[port].initAdapter(self, adapterConfigs[port]);
        initializedAdapters[port] = true;
    }
};

module.exports = HexConnector;
<commit_msg>add init functionality based on full configuration as parameter; solves dependency issues at adapter.initAdapter call<commit_after>var HexConnector = function () {
    var self = this;
    var initializedAdapters = {};
    var adapterConfigs = {};

    this.initialised = false;
    this.adapters = {};
    this.container = {};

    function _loadAdapter(port, adapter) {
        if (adapter instanceof Object) {
            self.adapters[port] = adapter;
        } else {
            delete require.cache[require.resolve(adapter)];
            self.adapters[port] = require(adapter);
        }
    }

    function _initAdapter(port) {
        self.adapters[port].initAdapter(self, adapterConfigs[port]);
        initializedAdapters[port] = true;
    }

    this._set = function (k, v) {
        self.container[k] = v;
    };

    this._get = function (k) {
        return self.container[k];
    };

    this.init = function (config) {
        if (self.initialized) {
            return Error('Sorry already initialized!');
        }
        self._set('app_config', config);

        Object.keys(config.adapters).forEach(function (port) {
            const adapterConfig = config.adapters[port];
            initializedAdapters[port] = false;
            adapterConfigs[port] = config[adapterConfig.config] || {};
            _loadAdapter(port, adapterConfig.adapter);
        });
        self.initialized = true;
    };

    this.registerAdapter = function (port, adapter, config, withoutInit) {
        initializedAdapters[port] = false;
        adapterConfigs[port] = config || {};

        _loadAdapter(port, adapter);

        if (!withoutInit && typeof self.adapters[port].initAdapter === 'function') {
            _initAdapter(port);
        }
    };

    this.getAdapter = function (port) {
        var adapter = self.adapters[port];

        if (adapter && !initializedAdapters[port] && typeof adapter.initAdapter === 'function') {
            _initAdapter(port);
        }

        return adapter;
    };
};

module.exports = HexConnector;
<|endoftext|>


<commit_before>/**
 *
 * Quote plugin
 */

var quote = (function(quote) {

    /**
     * @private
     *
     * CSS styles
     */
    var elementClasses_ = {

        ce_quote     : 'ce-quote',
        quoteText    : 'ce_quote--text',
        quoteAuthor  : 'ce_quote--author',
        authorsJob   : 'ce_quote--job',
        authorsPhoto : 'authorsPhoto',
        authorsPhotoWrapper : 'authorsPhoto-wrapper',

        simple : {
            text : 'quoteStyle-simple--text'
        },

        withCaption : {
            blockquote : 'quoteStyle-withCaption--blockquote',
            author     : 'quoteStyle-withCaption--author'
        },

        withPhoto : {
            photo   : 'quoteStyle-withPhoto--photo',
            author  : 'quoteStyle-withPhoto--author',
            job     : 'quoteStyle-withPhoto--job',
            quote   : 'quoteStyle-withPhoto--quote',
            wrapper : 'quoteStyle-withPhoto--wrapper',
            authorHolder : 'quoteStyle-withPhoto--authorWrapper'
        },

        settings  : {
            holder  : 'ce_plugin_quote--settings',
            caption : 'ce_plugin_quote--caption',
            buttons : 'ce_plugin_quote--select_button',
            selectedType : 'ce-quote-settings--selected'
        }
    };

    /**
     * @private
     *
     *
     */
    var methods_ = {

        changeStyleClicked : function() {

            var changeStyleButton = this,
                quote = codex.content.currentNode.querySelector('.' + elementClasses_.ce_quote),
                newStyle = changeStyleButton.dataset.style,
                styleSelectors = this.parentNode.childNodes;

            quote.dataset.quoteStyle = newStyle;

            /**
             * Mark selected style button
             */
            for (var i = styleSelectors.length - 1; i >= 0; i--) {
                styleSelectors[i].classList.remove(elementClasses_.settings.selectedType);
            }

            this.classList.add(elementClasses_.settings.selectedType);

        },

        /**
         * @deprecated
         */
        selectTypeQuoteStyle : function(type) {

            var quoteStyleFunction;

            /**
             *  Choose Quote style to replace
             */
            switch (type) {
                case 'simple':
                    quoteStyleFunction = methods_.makeSimpleQuote;
                    break;
                case 'withCaption':
                    quoteStyleFunction = methods_.makeQuoteWithCaption;
                    break;
                case 'withPhoto':
                    quoteStyleFunction = methods_.makeQuoteWithPhoto;
                    break;
            }

            return quoteStyleFunction;

        },

        /**
         * @deprecated
         */
        addSelectTypeClickListener : function(el, quoteStyle) {

            el.addEventListener('click', function () {

                /**
                 * Parsing currentNode to JSON.
                 */
                var parsedOldQuote  = methods_.parseBlockQuote(),
                    newStyledQuote  = quoteStyle(parsedOldQuote);

                var wrapper = codex.content.composeNewBlock(newStyledQuote, 'quote');
                wrapper.appendChild(newStyledQuote);

                codex.content.switchBlock(codex.content.currentNode, newStyledQuote, 'quote');

                /** Close settings after replacing */
                codex.toolbar.settings.close();

            }, false);

        },

        /**
         * @deprecated
         */
        makeSimpleQuote : function(data) {

            var wrapper = ui_.makeBlock('BLOCKQUOTE', [elementClasses_.simple.text, elementClasses_.quoteText]);

            wrapper.innerHTML = data.text || '';

            wrapper.dataset.quoteStyle = 'simple';
            wrapper.classList.add(elementClasses_.ce_quote);
            wrapper.contentEditable = 'true';

            return wrapper;
        },

        /**
         * @deprecated
         */
        makeQuoteWithCaption : function(data) {

            var wrapper = ui_.blockquote(),
                text    = ui_.makeBlock('DIV', [elementClasses_.withCaption.blockquote, elementClasses_.quoteText]),
                author  = ui_.makeBlock('DIV', [elementClasses_.withCaption.author, elementClasses_.quoteAuthor]);

            /* make text block ontentEditable */
            text.contentEditable = 'true';

            text.innerHTML = data.text;

            /* make Author contentEditable */
            author.contentEditable = 'true';

            author.textContent = data.cite;

            /* Appending created components */
            wrapper.dataset.quoteStyle = 'withCaption';
            wrapper.classList.add(elementClasses_.ce_quote);

            wrapper.appendChild(text);
            wrapper.appendChild(author);

            return wrapper;

        },

        makeQuoteWithPhoto : function(data) {

            var wrapper  = ui_.blockquote(),
                photo    = ui_.makeBlock('DIV', [elementClasses_.withPhoto.photo]),
                author   = ui_.makeBlock('DIV', [elementClasses_.withPhoto.author, elementClasses_.quoteAuthor]),
                job      = ui_.makeBlock('DIV', [elementClasses_.withPhoto.job, elementClasses_.authorsJob]),
                quote    = ui_.makeBlock('DIV', [elementClasses_.withPhoto.quote, elementClasses_.quoteText]);

            /* Default Image src */
            if (!data.image) {

                var icon = ui_.makeBlock('SPAN', ['ce-icon-picture']);
                photo.appendChild(icon);

            } else {

                var authorsPhoto = ui_.img(elementClasses_.authorsPhoto);

                authorsPhoto.src = data.image;
                authorsPhoto.dataset.bigUrl = data.image;

                photo.classList.add(elementClasses_.authorsPhotoWrapper);
                photo.appendChild(authorsPhoto);
            }

            photo.addEventListener('click', fileUploadClicked_, false);

            /* make author block contentEditable */
            author.contentEditable = 'true';
            author.textContent = data.cite;

            /*  Author's position and job */
            job.contentEditable = 'true';
            job.textContent = data.caption;

            var authorsWrapper = ui_.makeBlock('DIV', [elementClasses_.withPhoto.authorHolder]);
            authorsWrapper.appendChild(author);
            authorsWrapper.appendChild(job);

            /* make quote text contentEditable */
            quote.contentEditable = 'true';
            quote.innerHTML = data.text;

            wrapper.classList.add(elementClasses_.ce_quote);
            wrapper.classList.add(elementClasses_.withPhoto.wrapper);
            wrapper.dataset.quoteStyle = 'withPhoto';

            wrapper.appendChild(quote);
            wrapper.appendChild(photo);
            wrapper.appendChild(authorsWrapper);

            return wrapper;
        },

        parseBlockQuote : function(block) {

            var currentNode = block || codex.content.currentNode,
                photo       = currentNode.getElementsByTagName('img')[0],
                author      = currentNode.querySelector('.' + elementClasses_.quoteAuthor),
                job         = currentNode.querySelector('.' + elementClasses_.authorsJob),
                quote ;

            /** Simple quote text placed in Blockquote tag*/
            if ( currentNode.dataset.quoteStyle == 'simple' )
                quote = currentNode.innerHTML;
            else
                quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML;

            if (job)
                job = job.textContent;

            if (author)
                author = author.textContent;

            if (photo)
                photo = photo.dataset.bigUrl;

            var data = {
                style       : currentNode.dataset.quoteStyle,
                text        : quote,
                author      : author,
                job         : job,
                photo       : photo
            };

            return data;
        }
    };

    /**
     * @private
     *
     * Author image Uploader
     */
    var fileUploadClicked_ = function() {

        var beforeSend  = photoUploadingCallbacks_.beforeSend,
            success     = photoUploadingCallbacks_.success,
            error       = photoUploadingCallbacks_.error;

        codex.transport.selectAndUpload({
            beforeSend: beforeSend,
            success: success,
            error: error
        });

    };

    /**
     * @private
     *
     */
    var ui_ = {

        wrapper : function($classList) {

            var el = document.createElement('DIV');

            el.classList.add($classList);

            return el;

        },

        blockquote : function() {

            var el = document.createElement('BLOCKQUOTE');

            return el;

        },

        img : function(attribute) {

            var imageTag = document.createElement('IMG');
            imageTag.classList.add(attribute);

            return imageTag;
        },

        makeBlock : function(tag, classList) {

            var el = document.createElement(tag);

            if ( classList ) {

                for( var i = 0; i < classList.length; i++)
                    el.className += ' ' + classList[i];

            }

            return el;

        }

    };

    /**
     * @private
     *
     * Callbacks
     */
    var photoUploadingCallbacks_ = {

        beforeSend : function() {

        },

        /**
         * Success callbacks for uploaded photo.
         * Replace upload icon with uploaded photo
         */
        success : function(result) {

            var parsed   = JSON.parse(result),
                filename = parsed.filename,
                uploadImageWrapper = codex.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo),
                authorsPhoto = ui_.img(elementClasses_.authorsPhoto);

            authorsPhoto.src = parsed.data.file.url;

            /** Remove icon from image wrapper */
            uploadImageWrapper.innerHTML = '';

            /** Appending uploaded image */
            uploadImageWrapper.classList.add(elementClasses_.authorsPhotoWrapper);
            uploadImageWrapper.appendChild(authorsPhoto);

            authorsPhoto.dataset.bigUrl = parsed.data.file.bigUrl;
        },

        /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */
        error : function(result) {
            console.log('Can\'t upload an image');
        }

    };

    /**
     * @private
     *
     * Make Quote from JSON datasets
     */
    var make_ = function(data) {

        var tag;

        if (data && data.size) {

            data.style = quote.config.defaultStyle;

            /**
             * Supported types
             */
            switch (data.style) {

                case 'simple':
                    tag = methods_.makeSimpleQuote(data);
                    break;
                case 'withCaption':
                    tag = methods_.makeQuoteWithCaption(data);
                    break;
                case 'withPhoto':
                    tag = methods_.makeQuoteWithPhoto(data);
                    break;
            }

            tag.dataset.quoteStyle = data.size;

        } else {

            var settings = {
                "text"   : null,
                "format" : "html",
                "cite"   : null,
                "caption": null,
                "size"   : null,
                "image"  : null
            };

            tag = methods_.makeQuoteWithPhoto(settings);
        }

        return tag;
    };

    var prepareDataForSave_ = function(data) {

        if (data.size == 'withPhoto') {
            data.size = 'small';
        }

        console.log(data);

        return data;
    };

    /**
     * @public
     *
     * Renderer
     *
     * @param data
     */
    quote.render = function(data) {
        return make_(data);
    };

    quote.validate = function(output) {

        if (typeof output.text != "string") {
            return;
        }

        return output;
    };

    quote.save = function(blockContent) {

        /**
         * Extracts JSON quote data from HTML block
         * @param {Text} text, {Text} author, {Object} photo
         */
        var parsedblock = methods_.parseBlockQuote(blockContent);

        var data = {
            "text"   : parsedblock.text,
            "format" : "html",
            "cite"   : parsedblock.author,
            "caption": parsedblock.job,
            "size"   : parsedblock.style,
            "image"  : parsedblock.photo
        };

        return prepareDataForSave_(data);
    };

    /**
     * @public
     *
     * Draws settings
     */
    quote.makeSettings = function(data) {

        var holder  = document.createElement('DIV'),
            types   = {
                big : 'По центру',
                small : 'Врезка'
            },
            selectTypeButton;

        /** Add holder classname */
        holder.className = elementClasses_.settings.holder;

        /** Now add type selectors */
        for (var type in types){

            selectTypeButton = document.createElement('SPAN');

            selectTypeButton.textContent = types[type];
            selectTypeButton.className   = elementClasses_.settings.buttons;

            selectTypeButton.dataset.style = type;

            if ( type == quote.config.defaultStyle ){
                selectTypeButton.classList.add(quoteTools.styles.settings.selectedType);
            }

            // var quoteStyle = quoteTools.selectTypeQuoteStyle(type);

            selectTypeButton.addEventListener('click', methods_.changeStyleClicked, false);
            // quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle);

            holder.appendChild(selectTypeButton);

        }

        return holder;

    };

    /**
     * @public
     * Default path to redactors images
     * @type {null}
     */
    quote.path = null;

    /**
     * @public
     *
     * @type {null}
     */
    quote.config = null;

    /**
     * @public
     *
     * @param config
     */
    quote.prepare = function(config) {
        quote.config = config;
    };

    return quote;

})({});<commit_msg>quote modifications<commit_after>/**
 *
 * Quote plugin
 */

var quote = (function(quote) {

    /**
     * @private
     *
     * CSS styles
     */
    var elementClasses_ = {

        ce_quote     : 'ce-quote',
        quoteText    : 'ce_quote--text',
        quoteAuthor  : 'ce_quote--author',
        authorsJob   : 'ce_quote--job',
        authorsPhoto : 'authorsPhoto',
        authorsPhotoWrapper : 'authorsPhoto-wrapper',

        simple : {
            text : 'quoteStyle-simple--text'
        },

        withCaption : {
            blockquote : 'quoteStyle-withCaption--blockquote',
            author     : 'quoteStyle-withCaption--author'
        },

        withPhoto : {
            photo   : 'quoteStyle-withPhoto--photo',
            author  : 'quoteStyle-withPhoto--author',
            job     : 'quoteStyle-withPhoto--job',
            quote   : 'quoteStyle-withPhoto--quote',
            wrapper : 'quoteStyle-withPhoto--wrapper',
            authorHolder : 'quoteStyle-withPhoto--authorWrapper'
        },

        settings  : {
            holder  : 'ce_plugin_quote--settings',
            caption : 'ce_plugin_quote--caption',
            buttons : 'ce_plugin_quote--select_button',
            selectedType : 'ce-quote-settings--selected'
        }
    };

    /**
     * @private
     *
     *
     */
    var methods_ = {

        changeStyleClicked : function() {

            var changeStyleButton = this,
                quote = codex.content.currentNode.querySelector('.' + elementClasses_.ce_quote),
                newStyle = changeStyleButton.dataset.style,
                styleSelectors = this.parentNode.childNodes;

            quote.dataset.quoteStyle = newStyle;

            /**
             * Mark selected style button
             */
            for (var i = styleSelectors.length - 1; i >= 0; i--) {
                styleSelectors[i].classList.remove(elementClasses_.settings.selectedType);
            }

            this.classList.add(elementClasses_.settings.selectedType);

        },

        /**
         * @deprecated
         */
        selectTypeQuoteStyle : function(type) {

            var quoteStyleFunction;

            /**
             *  Choose Quote style to replace
             */
            switch (type) {
                case 'simple':
                    quoteStyleFunction = methods_.makeSimpleQuote;
                    break;
                case 'withCaption':
                    quoteStyleFunction = methods_.makeQuoteWithCaption;
                    break;
                case 'withPhoto':
                    quoteStyleFunction = methods_.makeQuoteWithPhoto;
                    break;
            }

            return quoteStyleFunction;

        },

        /**
         * @deprecated
         */
        addSelectTypeClickListener : function(el, quoteStyle) {

            el.addEventListener('click', function () {

                /**
                 * Parsing currentNode to JSON.
                 */
                var parsedOldQuote  = methods_.parseBlockQuote(),
                    newStyledQuote  = quoteStyle(parsedOldQuote);

                var wrapper = codex.content.composeNewBlock(newStyledQuote, 'quote');
                wrapper.appendChild(newStyledQuote);

                codex.content.switchBlock(codex.content.currentNode, newStyledQuote, 'quote');

                /** Close settings after replacing */
                codex.toolbar.settings.close();

            }, false);

        },

        /**
         * @deprecated
         */
        makeSimpleQuote : function(data) {

            var wrapper = ui_.makeBlock('BLOCKQUOTE', [elementClasses_.simple.text, elementClasses_.quoteText]);

            wrapper.innerHTML = data.text || '';

            wrapper.dataset.quoteStyle = 'simple';
            wrapper.classList.add(elementClasses_.ce_quote);
            wrapper.contentEditable = 'true';

            return wrapper;
        },

        /**
         * @deprecated
         */
        makeQuoteWithCaption : function(data) {

            var wrapper = ui_.blockquote(),
                text    = ui_.makeBlock('DIV', [elementClasses_.withCaption.blockquote, elementClasses_.quoteText]),
                author  = ui_.makeBlock('DIV', [elementClasses_.withCaption.author, elementClasses_.quoteAuthor]);

            /* make text block ontentEditable */
            text.contentEditable = 'true';

            text.innerHTML = data.text;

            /* make Author contentEditable */
            author.contentEditable = 'true';

            author.textContent = data.cite;

            /* Appending created components */
            wrapper.dataset.quoteStyle = 'withCaption';
            wrapper.classList.add(elementClasses_.ce_quote);

            wrapper.appendChild(text);
            wrapper.appendChild(author);

            return wrapper;

        },

        makeQuoteWithPhoto : function(data) {

            var wrapper  = ui_.blockquote(),
                photo    = ui_.makeBlock('DIV', [elementClasses_.withPhoto.photo]),
                author   = ui_.makeBlock('DIV', [elementClasses_.withPhoto.author, elementClasses_.quoteAuthor]),
                job      = ui_.makeBlock('DIV', [elementClasses_.withPhoto.job, elementClasses_.authorsJob]),
                quote    = ui_.makeBlock('DIV', [elementClasses_.withPhoto.quote, elementClasses_.quoteText]);

            /* Default Image src */
            if (!data.image) {

                var icon = ui_.makeBlock('SPAN', ['ce-icon-picture']);
                photo.appendChild(icon);

            } else {

                var authorsPhoto = ui_.img(elementClasses_.authorsPhoto);

                authorsPhoto.src = data.image;
                authorsPhoto.dataset.bigUrl = data.image;

                photo.classList.add(elementClasses_.authorsPhotoWrapper);
                photo.appendChild(authorsPhoto);
            }

            photo.addEventListener('click', fileUploadClicked_, false);

            /* make author block contentEditable */
            author.contentEditable = 'true';
            author.textContent = data.cite;

            /*  Author's position and job */
            job.contentEditable = 'true';
            job.textContent = data.caption;

            var authorsWrapper = ui_.makeBlock('DIV', [elementClasses_.withPhoto.authorHolder]);
            authorsWrapper.appendChild(author);
            authorsWrapper.appendChild(job);

            /* make quote text contentEditable */
            quote.contentEditable = 'true';
            quote.innerHTML = data.text;

            wrapper.classList.add(elementClasses_.ce_quote);
            wrapper.classList.add(elementClasses_.withPhoto.wrapper);
            wrapper.dataset.quoteStyle = 'withPhoto';

            wrapper.appendChild(quote);
            wrapper.appendChild(photo);
            wrapper.appendChild(authorsWrapper);

            return wrapper;
        },

        parseBlockQuote : function(block) {

            var currentNode = block || codex.content.currentNode,
                photo       = currentNode.getElementsByTagName('img')[0],
                author      = currentNode.querySelector('.' + elementClasses_.quoteAuthor),
                job         = currentNode.querySelector('.' + elementClasses_.authorsJob),
                quote ;

            /** Simple quote text placed in Blockquote tag*/
            if ( currentNode.dataset.quoteStyle == 'simple' )
                quote = currentNode.innerHTML;
            else
                quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML;

            if (job)
                job = job.textContent;

            if (author)
                author = author.textContent;

            if (photo)
                photo = photo.dataset.bigUrl;

            var data = {
                style       : currentNode.dataset.quoteStyle,
                text        : quote,
                author      : author,
                job         : job,
                photo       : photo
            };

            return data;
        }
    };

    /**
     * @private
     *
     * Author image Uploader
     */
    var fileUploadClicked_ = function() {

        var beforeSend  = photoUploadingCallbacks_.beforeSend,
            success     = photoUploadingCallbacks_.success,
            error       = photoUploadingCallbacks_.error;

        codex.transport.selectAndUpload({
            beforeSend: beforeSend,
            success: success,
            error: error
        });

    };

    /**
     * @private
     *
     */
    var ui_ = {

        wrapper : function($classList) {

            var el = document.createElement('DIV');

            el.classList.add($classList);

            return el;

        },

        blockquote : function() {

            var el = document.createElement('BLOCKQUOTE');

            return el;

        },

        img : function(attribute) {

            var imageTag = document.createElement('IMG');
            imageTag.classList.add(attribute);

            return imageTag;
        },

        makeBlock : function(tag, classList) {

            var el = document.createElement(tag);

            if ( classList ) {

                for( var i = 0; i < classList.length; i++)
                    el.className += ' ' + classList[i];

            }

            return el;

        }

    };

    /**
     * @private
     *
     * Callbacks
     */
    var photoUploadingCallbacks_ = {

        beforeSend : function() {

        },

        /**
         * Success callbacks for uploaded photo.
         * Replace upload icon with uploaded photo
         */
        success : function(result) {

            var parsed   = JSON.parse(result),
                filename = parsed.filename,
                uploadImageWrapper = codex.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo),
                authorsPhoto = ui_.img(elementClasses_.authorsPhoto);

            authorsPhoto.src = parsed.data.file.url;

            /** Remove icon from image wrapper */
            uploadImageWrapper.innerHTML = '';

            /** Appending uploaded image */
            uploadImageWrapper.classList.add(elementClasses_.authorsPhotoWrapper);
            uploadImageWrapper.appendChild(authorsPhoto);

            authorsPhoto.dataset.bigUrl = parsed.data.file.bigUrl;
        },

        /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */
        error : function(result) {
            console.log('Can\'t upload an image');
        }

    };

    /**
     * @private
     *
     * Make Quote from JSON datasets
     */
    var make_ = function(data) {

        var tag;

        if (data && data.size) {

            data.style = quote.config.defaultStyle;

            /**
             * Supported types
             */
            switch (data.style) {

                case 'simple':
                    tag = methods_.makeSimpleQuote(data);
                    break;
                case 'withCaption':
                    tag = methods_.makeQuoteWithCaption(data);
                    break;
                case 'withPhoto':
                    tag = methods_.makeQuoteWithPhoto(data);
                    break;
            }

            tag.dataset.quoteStyle = data.size;

        } else {

            var settings = {
                "text"   : null,
                "format" : "html",
                "cite"   : null,
                "caption": null,
                "size"   : null,
                "image"  : null
            };

            tag = methods_.makeQuoteWithPhoto(settings);
        }

        return tag;
    };

    var prepareDataForSave_ = function(data) {

        if (data.size == 'withPhoto') {
            data.size = 'small';
        }

        var wrapper = document.createElement('DIV');
        wrapper.innerHTML = data.text;

        var child;

        for (child = 0; child < wrapper.childNodes.length; child++) {
            // is TEXT node ?
            if (wrapper.childNodes[child].nodeType === 3) {

                var paragraph = document.createElement('P');
                paragraph.innerHTML = wrapper.childNodes[child].textContent;

                wrapper.childNodes[child].replaceWith(paragraph);
            }
        }

        data.text = wrapper.innerHTML;

        return data;
    };

    /**
     * @public
     *
     * Renderer
     *
     * @param data
     */
    quote.render = function(data) {
        return make_(data);
    };

    quote.validate = function(output) {

        if (typeof output.text != "string") {
            return;
        }

        return output;
    };

    quote.save = function(blockContent) {

        /**
         * Extracts JSON quote data from HTML block
         * @param {Text} text, {Text} author, {Object} photo
         */
        var parsedblock = methods_.parseBlockQuote(blockContent);

        var data = {
            "text"   : parsedblock.text,
            "format" : "html",
            "cite"   : parsedblock.author,
            "caption": parsedblock.job,
            "size"   : parsedblock.style,
            "image"  : parsedblock.photo
        };

        return prepareDataForSave_(data);
    };

    /**
     * @public
     *
     * Draws settings
     */
    quote.makeSettings = function(data) {

        var holder  = document.createElement('DIV'),
            types   = {
                big : 'По центру',
                small : 'Врезка'
            },
            selectTypeButton;

        /** Add holder classname */
        holder.className = elementClasses_.settings.holder;

        /** Now add type selectors */
        for (var type in types){

            selectTypeButton = document.createElement('SPAN');

            selectTypeButton.textContent = types[type];
            selectTypeButton.className   = elementClasses_.settings.buttons;

            selectTypeButton.dataset.style = type;

            if ( type == quote.config.defaultStyle ){
                selectTypeButton.classList.add(quoteTools.styles.settings.selectedType);
            }

            // var quoteStyle = quoteTools.selectTypeQuoteStyle(type);

            selectTypeButton.addEventListener('click', methods_.changeStyleClicked, false);
            // quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle);

            holder.appendChild(selectTypeButton);

        }

        return holder;

    };

    /**
     * @public
     * Default path to redactors images
     * @type {null}
     */
    quote.path = null;

    /**
     * @public
     *
     * @type {null}
     */
    quote.config = null;

    /**
     * @public
     *
     * @param config
     */
    quote.prepare = function(config) {
        quote.config = config;
    };

    return quote;

})({});<|endoftext|>


<commit_before>const cloudinary = require('cloudinary').v2;
const fs = require('fs');
const path = require('path');

module.exports = async ({ github, context }) => {
    const rootDir = path.resolve(path.join(__dirname, '..'));
    let commentBody = '';

    // Return "https" URLs by setting secure: true
    cloudinary.config({
        secure: true,
    });

    const uploadImages = async () => {
        let promiseArray = [];

        let images = fs.readdirSync(`${rootDir}/var/error-screenshots/`);

        images.forEach((element) => {
            console.log('uploading image to cloudinary..');

            let uplaodedImagePromise = cloudinary.uploader.upload(
                `${rootDir}/var/error-screenshots/${element}`,
                {
                    tags: 'ci,github-actions,e2e,screenshot',
                    folder: `solidinvoice/ci/errors/${context.issue.number}/${context.sha}`,
                    sign_url: true,
                    use_filename: true,
                    unique_filename: false,
                    overwrite: true,
                }
            );
            promiseArray.push(uplaodedImagePromise);
        });

        const urlList = await Promise.all(promiseArray);

        return urlList.map((element) => ({
            url: element.url,
            name: element.original_filename,
        }));
    };

    const urlList = await uploadImages();

    urlList.forEach((element) => {
        commentBody =
            commentBody +
            `### ${element.name} \n <br /> ![screenshot-${element.name}](${element.url}) \n`;
    });

    if (fs.existsSync(`${rootDir}/var/log/test.log`)) {
        const logFileContent = fs.readFileSync(`${rootDir}/var/log/test.log`);

        commentBody += `\n ### Log File\n \`\`\`${logFileContent}\`\`\``;
    }

    github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: `Functional Test Failure 🙀!

        ${commentBody}
        `,
    });
};

<commit_msg>Add workflow name to test failure comment<commit_after>const cloudinary = require('cloudinary').v2;
const fs = require('fs');
const path = require('path');

module.exports = async ({ github, context }) => {
    const rootDir = path.resolve(path.join(__dirname, '..'));
    let commentBody = 'Functional Test Failure 🙀!';
    commentBody += `\n**(${context.workflow})**\n`;

    // Return "https" URLs by setting secure: true
    cloudinary.config({
        secure: true,
    });

    const uploadImages = async () => {
        let promiseArray = [];

        let images = fs.readdirSync(`${rootDir}/var/error-screenshots/`);

        images.forEach((element) => {
            console.log('uploading image to cloudinary..');

            let uplaodedImagePromise = cloudinary.uploader.upload(
                `${rootDir}/var/error-screenshots/${element}`,
                {
                    tags: 'ci,github-actions,e2e,screenshot',
                    folder: `solidinvoice/ci/errors/${context.issue.number}/${context.sha}`,
                    sign_url: true,
                    use_filename: true,
                    unique_filename: false,
                    overwrite: true,
                }
            );
            promiseArray.push(uplaodedImagePromise);
        });

        const urlList = await Promise.all(promiseArray);

        return urlList.map((element) => ({
            url: element.url,
            name: element.original_filename,
        }));
    };

    const urlList = await uploadImages();

    urlList.forEach((element) => {
        commentBody += `![screenshot-${element.name}](${element.url}) \n`;
    });

    if (fs.existsSync(`${rootDir}/var/log/test.log`)) {
        const logFileContent = fs.readFileSync(`${rootDir}/var/log/test.log`);

        commentBody += `\n ### Log File\n \`\`\`${logFileContent}\`\`\``;
    }

    github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: `

        ${commentBody}
        `,
    });
};

<|endoftext|>


<commit_before><commit_msg>Added log in link to script<commit_after><|endoftext|>


<commit_before>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009-2010 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

/**
 * @class Is a base application (should be extended).
 *
 * @extends Options
 * @extends Logging
 *
 * @since 0.1
 * @author DracoBlue
 */
BaseApplication = function(options) {
    this.setOptions(options);
    if (typeof this.run !== "function") {
        throw new Error("Implement the .run method!");
    }
};

extend(true, BaseApplication.prototype, Options.prototype, Logging.prototype);

/**
 * Runs the application.
 */
BaseApplication.prototype.run = function() {
    throw new Error("run method not implemented!");
};

/**
 * Runs a specific path
 */
BaseApplication.executePath = function(path, context, inner) {
    context = context || {};
    inner = inner || null;

    var controller = controller_manager.getController(path);

    return function(cb) {
        var response = "";

        chain(function(chain_cb) {
            controller[0].execute(controller[1], context)(function(chain_response) {
                response = chain_response;
                chain_cb();
            });
        }, function(chain_cb) {
            if (typeof context.view_name !== "undefined") {
                /*
                 * We need the view manager, since the view-name is set!
                 */
                var view = view_manager.getView(context.view_name);
                view.render(controller[1], context, inner)(function(chain_response) {
                    response = chain_response;
                    chain_cb();
                });
            } else {
                chain_cb();
            }
        }, function(chain_cb) {
            if (typeof context.layout_name !== "undefined") {
                /*
                 * We need the view manager, since the view-name is set!
                 */
                var layout_view = view_manager.getView(context.layout_name);
                layout_view.render(controller[1], context, response)(function(chain_response) {
                    response = chain_response;
                    chain_cb();
                });
            } else {
                chain_cb();
            }
        }, function() {
            cb(response);
        });
    };
};
<commit_msg>Response of the action is not ignored anymore.<commit_after>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009-2010 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

/**
 * @class Is a base application (should be extended).
 *
 * @extends Options
 * @extends Logging
 *
 * @since 0.1
 * @author DracoBlue
 */
BaseApplication = function(options) {
    this.setOptions(options);
    if (typeof this.run !== "function") {
        throw new Error("Implement the .run method!");
    }
};

extend(true, BaseApplication.prototype, Options.prototype, Logging.prototype);

/**
 * Runs the application.
 */
BaseApplication.prototype.run = function() {
    throw new Error("run method not implemented!");
};

/**
 * Runs a specific path
 */
BaseApplication.executePath = function(path, context, inner) {
    context = context || {};
    inner = inner || null;

    var controller = controller_manager.getController(path);

    return function(cb) {
        var response = "";

        chain(function(chain_cb) {
            controller[0].execute(controller[1], context)(function(chain_response) {
                response = chain_response || inner;
                chain_cb();
            });
        }, function(chain_cb) {
            if (typeof context.view_name !== "undefined") {
                /*
                 * We need the view manager, since the view-name is set!
                 */
                var view = view_manager.getView(context.view_name);
                view.render(controller[1], context, response)(function(chain_response) {
                    response = chain_response;
                    chain_cb();
                });
            } else {
                chain_cb();
            }
        }, function(chain_cb) {
            if (typeof context.layout_name !== "undefined") {
                /*
                 * We need the view manager, since the view-name is set!
                 */
                var layout_view = view_manager.getView(context.layout_name);
                layout_view.render(controller[1], context, response)(function(chain_response) {
                    response = chain_response;
                    chain_cb();
                });
            } else {
                chain_cb();
            }
        }, function() {
            cb(response);
        });
    };
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name            Top auto scrollbar
// @description     Automatic appearing top horizontal scrollbar if the page length is more than thrice the height of the screen. Bar Height and opacity are ajustable by Greasemonkey custom menu.
// @description:ru  Горизонтальный скроллбар, автоматически появляющийся у верхнего края страницы, если она более чем в три раза длиннее экрана. Ширина и прозрачность настраивается в custom-меню Greasemonkey.
// @namespace       github.com/totalamd
// @match           *://*/*
// @exclude
// @version         1.0.2.1
// @downloadURL     https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @updateURL       https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @grant           GM_listValues
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_deleteValue
// @grant           GM_registerMenuCommand
// @grant           GM_addStyle
// @noframes
// ==/UserScript==

// TODO:
// - [ ] think up how to declarate consts inside init() & make its global

"use strict";
const l = function(){}, i = function(){};

(function(){
	const l = console.log.bind(console, `${GM_info.script.name} debug:`), i = console.info.bind(console, `${GM_info.script.name} debug:`);

	function addToList() {
		let locations = GM_getValue('locations') || {};
		locations[location.hostname] = true;
		GM_setValue('locations', locations);
		location.reload();
	}

	function delFromList() {
		let locations = GM_getValue('locations');
		delete locations[location.hostname];
		GM_setValue('locations', locations);
		location.reload();
	}

	function clearList() {
		if (confirm('Are you sure?')) {
			let locationsList = '';
			for (let item in GM_getValue('locations')) {
				locationsList += '\n' + item;
			}
			console.log('Anti-activation list was:', locationsList);
			GM_deleteValue('locations');
		}
	}

	function showList() {
		if (!GM_getValue('locations')) {
			console.log('Anti-activation list is empty.');
		} else {
			console.log('Activation list:');
			for (let item in GM_getValue('locations')) {
				console.log(item);
			}
		}
	}

	function setHeight(){
		let height;
		if ((height = parseInt(prompt('enter height, in px', 5))) && (height > 0)) {
			GM_setValue('height', height + 'px');
			divContainerStyle.height = height + 'px';
		}
	}

	function setOpacity(){
		let opacity;
		if ((opacity = parseFloat(prompt('enter opacity, from 0 to 1', 0.8))) && (opacity > 0) && (opacity <= 1)) {
			GM_setValue('opacity', opacity);
			divContainerStyle.opacity = opacity;
		}
	}

	function update() {
		const width = Math.min(window.scrollY / (document.body.scrollHeight - window.innerHeight), 1) * 100;
		divBarStyle.width = width + '%';
		divContainer.title = `${width.toFixed()}%\nPage is ${(document.body.scrollHeight / window.innerHeight).toFixed(1)} times as high as screen`;
	}

	if (!(location.hostname in (GM_getValue('locations') || {}))) {
		GM_registerMenuCommand("Don't activate scrollbar on this site", addToList);
	} else {
		GM_registerMenuCommand("Reactivate scrollbar on this site", delFromList);
	}
	if (GM_getValue('locations')) {
		GM_registerMenuCommand("Clear anti-activation list", clearList);
	}
	GM_registerMenuCommand("Show anti-activation list", showList);
	GM_registerMenuCommand("Set bar height", setHeight);
	GM_registerMenuCommand("Set bar opacity", setOpacity);

	if (document.body.scrollHeight / window.innerHeight <= 3) {
		l('Page\'s too short');
		return;
	} else if (location.hostname in (GM_getValue('locations') || {})) {
		l(`'${location.hostname}' is in the anti-activation list.`);
		return;
	}

	// declaration outside init() to make its global
	const divContainer = document.createElement('div');
	const divBar = document.createElement('div');
	let divContainerStyle, divBarStyle;

	function init (){
		GM_addStyle(`
		.topAutoScrollbar-divContainer {
			position: fixed;
			opacity: ${GM_getValue('opacity') || 0.8};
			height: ${GM_getValue('height') || '5px'};
			width: 100%;
			top: 0px;
			left: 0px;
			background-color: cornflowerblue;
			z-index: 2147483647;
			cursor: auto;}
		.topAutoScrollbar-divBar {
			height: 100%;
			background-color: hotpink;
			width: 0;}`);

		// get vars to css properties
		for (let sheet of document.styleSheets) {
			// "Security error" workaround for some external css
			if (!sheet.href) {
				for (let rule of sheet.cssRules) {
					switch (rule.selectorText) {
					case '.topAutoScrollbar-divContainer':
						divContainerStyle = rule.style;
						break;
					case '.topAutoScrollbar-divBar':
						divBarStyle = rule.style;
						break;
					}
				}
			}
		}
		divContainer.className = 'topAutoScrollbar-divContainer';
		divBar.className = 'topAutoScrollbar-divBar';
		divContainer.appendChild(divBar);
		document.body.appendChild(divContainer);
	}

	init();
	update();
	window.addEventListener('scroll', update);
}())
<commit_msg>add user script menu header<commit_after>// ==UserScript==
// @name            Top auto scrollbar
// @description     Automatic appearing top horizontal scrollbar if the page length is more than thrice the height of the screen. Bar Height and opacity are ajustable by Greasemonkey custom menu.
// @description:ru  Горизонтальный скроллбар, автоматически появляющийся у верхнего края страницы, если она более чем в три раза длиннее экрана. Ширина и прозрачность настраивается в custom-меню Greasemonkey.
// @namespace       github.com/totalamd
// @match           *://*/*
// @exclude
// @version         1.0.2.1
// @downloadURL     https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @updateURL       https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @grant           GM_listValues
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_deleteValue
// @grant           GM_registerMenuCommand
// @grant           GM_addStyle
// @noframes
// ==/UserScript==

// TODO:
// - [ ] think up how to declarate consts inside init() & make its global

"use strict";
const l = function(){}, i = function(){};

(function(){
	const l = console.log.bind(console, `${GM_info.script.name} debug:`), i = console.info.bind(console, `${GM_info.script.name} debug:`);

	function addToList() {
		let locations = GM_getValue('locations') || {};
		locations[location.hostname] = true;
		GM_setValue('locations', locations);
		location.reload();
	}

	function delFromList() {
		let locations = GM_getValue('locations');
		delete locations[location.hostname];
		GM_setValue('locations', locations);
		location.reload();
	}

	function clearList() {
		if (confirm('Are you sure?')) {
			let locationsList = '';
			for (let item in GM_getValue('locations')) {
				locationsList += '\n' + item;
			}
			console.log('Anti-activation list was:', locationsList);
			GM_deleteValue('locations');
		}
	}

	function showList() {
		if (!GM_getValue('locations')) {
			console.log('Anti-activation list is empty.');
		} else {
			console.log('Activation list:');
			for (let item in GM_getValue('locations')) {
				console.log(item);
			}
		}
	}

	function setHeight(){
		let height;
		if ((height = parseInt(prompt('enter height, in px', 5))) && (height > 0)) {
			GM_setValue('height', height + 'px');
			divContainerStyle.height = height + 'px';
		}
	}

	function setOpacity(){
		let opacity;
		if ((opacity = parseFloat(prompt('enter opacity, from 0 to 1', 0.8))) && (opacity > 0) && (opacity <= 1)) {
			GM_setValue('opacity', opacity);
			divContainerStyle.opacity = opacity;
		}
	}

	function update() {
		const width = Math.min(window.scrollY / (document.body.scrollHeight - window.innerHeight), 1) * 100;
		divBarStyle.width = width + '%';
		divContainer.title = `${width.toFixed()}%\nPage is ${(document.body.scrollHeight / window.innerHeight).toFixed(1)} times as high as screen`;
	}

	GM_registerMenuCommand(`-- ${GM_info.script.name} MENU --`);
	if (!(location.hostname in (GM_getValue('locations') || {}))) {
		GM_registerMenuCommand("Don't activate scrollbar on this site", addToList);
	} else {
		GM_registerMenuCommand("Reactivate scrollbar on this site", delFromList);
	}
	if (GM_getValue('locations')) {
		GM_registerMenuCommand("Clear anti-activation list", clearList);
	}
	GM_registerMenuCommand("Show anti-activation list", showList);
	GM_registerMenuCommand("Set bar height", setHeight);
	GM_registerMenuCommand("Set bar opacity", setOpacity);
	GM_registerMenuCommand("");

	if (document.body.scrollHeight / window.innerHeight <= 3) {
		l('Page\'s too short');
		return;
	} else if (location.hostname in (GM_getValue('locations') || {})) {
		l(`'${location.hostname}' is in the anti-activation list.`);
		return;
	}

	// declaration outside init() to make its global
	const divContainer = document.createElement('div');
	const divBar = document.createElement('div');
	let divContainerStyle, divBarStyle;

	function init (){
		GM_addStyle(`
		.topAutoScrollbar-divContainer {
			position: fixed;
			opacity: ${GM_getValue('opacity') || 0.8};
			height: ${GM_getValue('height') || '5px'};
			width: 100%;
			top: 0px;
			left: 0px;
			background-color: cornflowerblue;
			z-index: 2147483647;
			cursor: auto;}
		.topAutoScrollbar-divBar {
			height: 100%;
			background-color: hotpink;
			width: 0;}`);

		// get vars to css properties
		for (let sheet of document.styleSheets) {
			// "Security error" workaround for some external css
			if (!sheet.href) {
				for (let rule of sheet.cssRules) {
					switch (rule.selectorText) {
					case '.topAutoScrollbar-divContainer':
						divContainerStyle = rule.style;
						break;
					case '.topAutoScrollbar-divBar':
						divBarStyle = rule.style;
						break;
					}
				}
			}
		}
		divContainer.className = 'topAutoScrollbar-divContainer';
		divBar.className = 'topAutoScrollbar-divBar';
		divContainer.appendChild(divBar);
		document.body.appendChild(divContainer);
	}

	init();
	update();
	window.addEventListener('scroll', update);
}())
<|endoftext|>


<commit_before>var app = angular.module('app', ['ui.router', 'ui.bootstrap', 'ui.select2', 'ngAnimate', 'notify', 'xeditable', 'restangular', 'ui.utils']);

app.config(['$urlRouterProvider', function ($urlRouterProvider) {
    $urlRouterProvider.otherwise('/');
}]);

app.config(['$httpProvider', 'notifyProvider', 'RestangularProvider', function ($httpProvider, notifyProvider, restangularProvider) {
    $httpProvider.interceptors.push("httpBusyInterceptor");

    notifyProvider.globalTimeToLive(5000);
    notifyProvider.onlyUniqueMessages(false);

    //Restangular config
    restangularProvider.setBaseUrl('/api');
    restangularProvider.setRestangularFields({
        id: 'id'
    });
    restangularProvider.setResponseExtractor(function (response, operation) {
        return response.response;
    });
}]);

app.run(['$rootScope', '$http', '$state', 'editableOptions', '$modal', 'growl', function ($rootScope, $http, $state, editableOptions, $modal, growl) {
    //init info
    $rootScope.page = {
        title: 'Index',
        subnav: []
    };

    //x-editable config
    editableOptions.theme = 'bs3'; // bootstrap3 theme.

    $rootScope.user = {};

    $rootScope.openProfileModal = function() {
        $modal.open({
            templateUrl: 'partials/topnav/profileModal.html',
            resolve: {
                user: function() {
                    return $rootScope.user;
                },
                orgUnits: function() {
                    return $http.get('api/organizationunit/?userid2=' + $rootScope.user.id);
                }
            },
            controller: ['$scope', '$modalInstance', 'user', 'orgUnits', function ($modalScope, $modalInstance, user, orgUnits) {
                $modalScope.user = user;
                $modalScope.orgUnits = orgUnits.data.response;

                $modalScope.ok = function () {
                    var userData = {};
                    if ($modalScope.user.name)
                        userData.name = $modalScope.user.name;
                    if ($modalScope.user.defaultOrganizationUnitId)
                        userData.defaultOrganizationUnitId = $modalScope.user.defaultOrganizationUnitId;
                    if ($modalScope.user.email)
                        userData.email = $modalScope.user.email;

                    $http({
                        method: 'PATCH',
                        url: 'api/user/' + user.id,
                        data: userData
                    }).success(function() {
                        growl.addSuccessMessage('OK');
                        $modalInstance.close();
                    }).error(function() {
                        growl.addErrorMessage('Fejl');
                    });
                };

                $modalScope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            }]
        });
    };

    //logout function for top navigation bar
    $rootScope.logout = function () {
        $http.post('api/authorize?logout').success(function (result) {
            $rootScope.user = {};
            $state.go('index');
        });
    };

    $rootScope.saveUser = function (result) {
        var isLocalAdmin = _.some(result.response.adminRights, function(userRight) {
            return userRight.roleName == "LocalAdmin";
        });

        $rootScope.user = {
            id: result.response.id,
            authStatus: 'authorized',
            name: result.response.name,
            email: result.response.email,
            isGlobalAdmin: result.response.isGlobalAdmin,
            isLocalAdmin: isLocalAdmin,
            isLocalAdminFor: _.pluck(result.response.adminRights, 'organizationId')
        };

    };

    var hasInitUser = false;
    var initUser = $http.get('api/authorize').success($rootScope.saveUser).finally(function() {
        hasInitUser = true;
    });

    function auth(toState, toParams) {
        var user = $rootScope.user;

        if (user.authStatus != 'authorized') return false; //user hasn't authorized

        var adminRoles = toState.adminRoles;
        if (!adminRoles) return true; //no specific admin role needed

        //go through each of the roles on the state
        return _.some(adminRoles, function (role) {
            //if the state role is global admin, and the user is global admin, it's cool
            //same for local admin
            return (role == "GlobalAdmin" && user.isGlobalAdmin) || (role == "LocalAdmin" && user.isLocalAdmin);
        });
    }

    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.noAuth) return; //no need to auth

        //need to auth, but first when the initUser call is finished.
        if (!hasInitUser) {

            //initUser is not yet loaded - wait for it
            event.preventDefault();

            initUser.finally(function() {
                var user = $rootScope.user;
                var userRole = user.role;
                var authRoles = toState.authRoles;

                if (!auth(toState)) {
                    $state.go('login', { to: toState.name, toParams: toParams });
                } else {
                    $state.go(toState, toParams);
                }
            });
        } else {
            //initUser has loaded, just run auth()
            if (!auth(toState)) {
                event.preventDefault();
                $state.go('login', { to: toState.name, toParams: toParams });
            }
        }

    });
}]);<commit_msg>Renamed growl to notify<commit_after>var app = angular.module('app', ['ui.router', 'ui.bootstrap', 'ui.select2', 'ngAnimate', 'notify', 'xeditable', 'restangular', 'ui.utils']);

app.config(['$urlRouterProvider', function ($urlRouterProvider) {
    $urlRouterProvider.otherwise('/');
}]);

app.config(['$httpProvider', 'notifyProvider', 'RestangularProvider', function ($httpProvider, notifyProvider, restangularProvider) {
    $httpProvider.interceptors.push("httpBusyInterceptor");

    notifyProvider.globalTimeToLive(5000);
    notifyProvider.onlyUniqueMessages(false);

    //Restangular config
    restangularProvider.setBaseUrl('/api');
    restangularProvider.setRestangularFields({
        id: 'id'
    });
    restangularProvider.setResponseExtractor(function (response, operation) {
        return response.response;
    });
}]);

app.run(['$rootScope', '$http', '$state', 'editableOptions', '$modal', 'notify', function ($rootScope, $http, $state, editableOptions, $modal, notify) {
    //init info
    $rootScope.page = {
        title: 'Index',
        subnav: []
    };

    //x-editable config
    editableOptions.theme = 'bs3'; // bootstrap3 theme.

    $rootScope.user = {};

    $rootScope.openProfileModal = function() {
        $modal.open({
            templateUrl: 'partials/topnav/profileModal.html',
            resolve: {
                user: function() {
                    return $rootScope.user;
                },
                orgUnits: function() {
                    return $http.get('api/organizationunit/?userid2=' + $rootScope.user.id);
                }
            },
            controller: ['$scope', '$modalInstance', 'user', 'orgUnits', function ($modalScope, $modalInstance, user, orgUnits) {
                $modalScope.user = user;
                $modalScope.orgUnits = orgUnits.data.response;

                $modalScope.ok = function () {
                    var userData = {};
                    if ($modalScope.user.name)
                        userData.name = $modalScope.user.name;
                    if ($modalScope.user.defaultOrganizationUnitId)
                        userData.defaultOrganizationUnitId = $modalScope.user.defaultOrganizationUnitId;
                    if ($modalScope.user.email)
                        userData.email = $modalScope.user.email;

                    $http({
                        method: 'PATCH',
                        url: 'api/user/' + user.id,
                        data: userData
                    }).success(function() {
                        notify.addSuccessMessage('OK');
                        $modalInstance.close();
                    }).error(function() {
                        notify.addErrorMessage('Fejl');
                    });
                };

                $modalScope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            }]
        });
    };

    //logout function for top navigation bar
    $rootScope.logout = function () {
        $http.post('api/authorize?logout').success(function (result) {
            $rootScope.user = {};
            $state.go('index');
        });
    };

    $rootScope.saveUser = function (result) {
        var isLocalAdmin = _.some(result.response.adminRights, function(userRight) {
            return userRight.roleName == "LocalAdmin";
        });

        $rootScope.user = {
            id: result.response.id,
            authStatus: 'authorized',
            name: result.response.name,
            email: result.response.email,
            isGlobalAdmin: result.response.isGlobalAdmin,
            isLocalAdmin: isLocalAdmin,
            isLocalAdminFor: _.pluck(result.response.adminRights, 'organizationId')
        };

    };

    var hasInitUser = false;
    var initUser = $http.get('api/authorize').success($rootScope.saveUser).finally(function() {
        hasInitUser = true;
    });

    function auth(toState, toParams) {
        var user = $rootScope.user;

        if (user.authStatus != 'authorized') return false; //user hasn't authorized

        var adminRoles = toState.adminRoles;
        if (!adminRoles) return true; //no specific admin role needed

        //go through each of the roles on the state
        return _.some(adminRoles, function (role) {
            //if the state role is global admin, and the user is global admin, it's cool
            //same for local admin
            return (role == "GlobalAdmin" && user.isGlobalAdmin) || (role == "LocalAdmin" && user.isLocalAdmin);
        });
    }

    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.noAuth) return; //no need to auth

        //need to auth, but first when the initUser call is finished.
        if (!hasInitUser) {

            //initUser is not yet loaded - wait for it
            event.preventDefault();

            initUser.finally(function() {
                var user = $rootScope.user;
                var userRole = user.role;
                var authRoles = toState.authRoles;

                if (!auth(toState)) {
                    $state.go('login', { to: toState.name, toParams: toParams });
                } else {
                    $state.go(toState, toParams);
                }
            });
        } else {
            //initUser has loaded, just run auth()
            if (!auth(toState)) {
                event.preventDefault();
                $state.go('login', { to: toState.name, toParams: toParams });
            }
        }

    });
}]);<|endoftext|>


<commit_before>// ========================================================================
// SproutCore -- JavaScript Application Framework
// Copyright ©2006-2008, Sprout Systems, Inc. and contributors.
// Portions copyright ©2008 Apple Inc.  All rights reserved.
// ========================================================================

/**
  @class

  SelectFieldView displays browser-native popup menu.  To use this view,
  you should either bake into the HTML the preset list of options, or
  you can set the -objects property to an array of items to show.  The
  value is current value of the select.

  @extends SC.FieldView
  @author Charles Jolley
  @author Mike Ball
  @since SproutCore 1.0
*/
SC.SelectFieldView = SC.FieldView.extend(
/** @scope SC.SelectFieldView.prototype */ {

  tagName: 'select',
  classNames: ['sc-select-field-view'],

  /**
    An array of items that will form the menu you want to show.
  */
  objects: [],

  /**
    Binding default for an array of objects
  */
  objectsBindingDefault: SC.Binding.multiple(),

  /**
    If you set this to a non-null value, then the name shown for each
    menu item will be pulled from the object using the named property.
    if this is null, the collection objects themselves will be used.
  */
  nameKey: null,

  /**
   If you set this to a non-null value, then the value of this key will
   be used to sort the objects.  If this is not set, then nameKey will
   be used.
  */
  sortKey: null,

  /**
     Set this to a non-null value to use a key from the passed set of objects
     as the value for the options popup.  If you don't set this, then the
     objects themselves will be used as the value.
  */
  valueKey: null,

  /**
    set this to non-null to place an empty option at the top of the menu.
  */
  emptyName: null,

  /**
    if true, the empty name will be localized.
  */
  localize: false,

  /**
    if true, it means that the nameKey, valueKey or objects changed
  */
  cpDidChange: YES,

  /**
    if true, it means that no sorting will occur, objects will appear
    in the same order as in the array
  */
  disableSort: NO,

  /**
    override this to change the enabled/disabled state of menu items as they
    are built.  Return false if you want the menu item to be disabled.

    @param itemValue the value for the item to validate
    @param itemName the name of the menu item to validate
    @returns YES if the item should be enabled, NO otherwise
  */
  validateMenuItem: function(itemValue, itemName) {
    return true ;
  },

  /**
    override this method to implement your own sorting of the menu. By
    default, menu items are sorted using the value shown or the sortKey

    @param objects the unsorted array of objects to display.
    @returns sorted array of objects
  */
  sortObjects: function(objects) {
    if(!this.get('disableSort')){
      var nameKey = this.get('sortKey') || this.get('nameKey') ;
      objects = objects.sort(function(a,b) {
        if (nameKey) {
          a = a.get ? a.get(nameKey) : a[nameKey] ;
          b = b.get ? b.get(nameKey) : b[nameKey] ;
        }
        return (a<b) ? -1 : ((a>b) ? 1 : 0) ;
      }) ;
    }
    return objects ;
  },

  render: function(context, firstTime) {
    if (this.get('cpDidChange')) {
      this.set('cpDidChange', NO);
      // get list of objects.
      var nameKey = this.get('nameKey') ;
      var valueKey = this.get('valueKey') ;
      var objects = this.get('objects') ;
      var fieldValue = this.get('value') ;
      var el, selectElement;

      // get the localization flag.
      var shouldLocalize = this.get('localize');

      // convert fieldValue to guid, if it is an object.
      if (!valueKey && fieldValue) fieldValue = SC.guidFor(fieldValue) ;
      if ((fieldValue === null) || (fieldValue === '')) fieldValue = '***' ;

      if (objects) {
        objects = this.sortObjects(objects) ; // sort'em.
        // var html = [] ;
        if(!firstTime){
          selectElement=this.$input()[0];
          selectElement.innerHTML='';
        }

        var emptyName = this.get('emptyName') ;
        if (emptyName) {
          if (shouldLocalize) emptyName = emptyName.loc() ;
          if(firstTime){
            context.push('<option value="***">%@</option>'.fmt(emptyName)) ;
            context.push('<option disabled="disabled"></option>') ;
          }else{
            el=document.createElement('option');
            el.value="***";
            el.innerHTML=emptyName;
            selectElement.appendChild(el);
            el=document.createElement('option');
            el.disabled="disabled";
            selectElement.appendChild(el);
          }
        }

          // generate option elements.
        objects.forEach(function(object) {
        if (object) {
          // either get the name from the object or convert object to string.
          var name = nameKey ? (object.get ? object.get(nameKey) : object[nameKey]) : object.toString() ;

          // localize name if specified.
          if(shouldLocalize)
          {
            name = name.loc();
          }

          // get the value using the valueKey or the object if no valueKey.
          // then convert to a string or use _guid if one of available.
          var value = (valueKey) ? (object.get ? object.get(valueKey) : object[valueKey]) : object ;
          if (value) value = (SC.guidFor(value)) ? SC.guidFor(value) : value.toString() ;

          // render HTML
          var disable = (this.validateMenuItem && this.validateMenuItem(value, name)) ? '' : 'disabled="disabled" ' ;
          if(firstTime){
            context.push('<option %@value="%@">%@</option>'.fmt(disable,value,name)) ;
          } else{
            el=document.createElement('option');
            el.value=value;
            el.innerHTML=name;
            if(disable.length>0) el.disable="disabled";
            selectElement.appendChild(el);
          }
        // null value means separator.
        } else {
          if(firstTime){
            context.push('<option disabled="disabled"></option>') ;
          }else{
            el=document.createElement('option');
            el.disabled="disabled";
            selectElement.appendChild(el);
          }
        }
      }, this );

      this.setFieldValue(fieldValue);

      } else {
        this.set('value',null);
      }
    }
  },

  displayProperties: ['objects','nameKey','valueKey'],

  _objectsObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('objects'),

  _nameKeyObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('nameKey'),

  _valueKeyObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('valueKey'),

  // .......................................
  // PRIVATE
  //

  $input: function() { return this.$(); },

  /* @private */
  mouseDown: function(evt) {

    if (!this.get('isEnabled')) {
      evt.stop();
      return YES;
    } else return sc_super();
  },

  // when fetching the raw value, convert back to an object if needed...
  /** @private */
  getFieldValue: function() {
    var value = sc_super(); // get raw value...
    var valueKey = this.get('valueKey') ;
    var objects = this.get('objects') ;
    var found, object;

    // Handle empty selection.
    if (value == '***') {
      value = null ;

    // If no value key was set and there are objects then match back to an
    // object.
    } else if (value && objects) {
      // objects = Array.from(objects) ;

      var loc = (SC.typeOf(objects.length) === SC.T_FUNCTION) ? objects.length() : objects.length;

      found = null ; // matching object goes here.
      while(!found && (--loc >= 0)) {
        object = objects.objectAt? objects.objectAt(loc) : objects[loc] ;

        // get value using valueKey if there is one or use object
        // map to _guid or toString.
        if (valueKey) object = (object.get) ? object.get(valueKey) : object[valueKey] ;
        var ov = (object) ? (SC.guidFor(object) ? SC.guidFor(object) : object.toString()) : null ;

        // use this object value if it matches.
        if (value == ov) found = object ;
      }
    }

    return (valueKey || found) ? found : value;
  },

  setFieldValue: function(newValue) {
    if (SC.none(newValue)) { newValue = '' ; }
    else {
      newValue = ((newValue) ? (SC.guidFor(newValue) ? SC.guidFor(newValue) : newValue.toString()) : null );
    }
    this.$input().val(newValue);
    return this ;
  },

  fieldDidFocus: function() {
    var isFocused = this.get('isFocused');
    if (!isFocused) this.set('isFocused', true);
  },

  fieldDidBlur: function() {
    var isFocused = this.get('isFocused');
    if (isFocused) this.set('isFocused', false);
  },

  _isFocusedObserver: function() {
    this.$().setClass('focus', this.get('isFocused'));
  }.observes('isFocused'),

  didCreateLayer: function() {
    var input = this.$input();
    SC.Event.add(input, 'blur', this, this.fieldDidBlur);
    SC.Event.add(input, 'focus',this, this.fieldDidFocus);
    return sc_super();
  },

  willDestroyLayer: function() {
    var input = this.$input();
    SC.Event.remove(input, 'focus', this, this.fieldDidFocus);
    SC.Event.remove(input, 'blur', this, this.fieldDidBlur);
    return sc_super();
  }

});
<commit_msg>Small patch to fix <rdar://problem/7264532> FORM EDITING: select widgets are not rendered disabled, but only on first view.<commit_after>// ========================================================================
// SproutCore -- JavaScript Application Framework
// Copyright ©2006-2008, Sprout Systems, Inc. and contributors.
// Portions copyright ©2008 Apple Inc.  All rights reserved.
// ========================================================================

/**
  @class

  SelectFieldView displays browser-native popup menu.  To use this view,
  you should either bake into the HTML the preset list of options, or
  you can set the -objects property to an array of items to show.  The
  value is current value of the select.

  @extends SC.FieldView
  @author Charles Jolley
  @author Mike Ball
  @since SproutCore 1.0
*/
SC.SelectFieldView = SC.FieldView.extend(
/** @scope SC.SelectFieldView.prototype */ {

  tagName: 'select',
  classNames: ['sc-select-field-view'],

  /**
    An array of items that will form the menu you want to show.
  */
  objects: [],

  /**
    Binding default for an array of objects
  */
  objectsBindingDefault: SC.Binding.multiple(),

  /**
    If you set this to a non-null value, then the name shown for each
    menu item will be pulled from the object using the named property.
    if this is null, the collection objects themselves will be used.
  */
  nameKey: null,

  /**
   If you set this to a non-null value, then the value of this key will
   be used to sort the objects.  If this is not set, then nameKey will
   be used.
  */
  sortKey: null,

  /**
     Set this to a non-null value to use a key from the passed set of objects
     as the value for the options popup.  If you don't set this, then the
     objects themselves will be used as the value.
  */
  valueKey: null,

  /**
    set this to non-null to place an empty option at the top of the menu.
  */
  emptyName: null,

  /**
    if true, the empty name will be localized.
  */
  localize: false,

  /**
    if true, it means that the nameKey, valueKey or objects changed
  */
  cpDidChange: YES,

  /**
    if true, it means that no sorting will occur, objects will appear
    in the same order as in the array
  */
  disableSort: NO,

  /**
    override this to change the enabled/disabled state of menu items as they
    are built.  Return false if you want the menu item to be disabled.

    @param itemValue the value for the item to validate
    @param itemName the name of the menu item to validate
    @returns YES if the item should be enabled, NO otherwise
  */
  validateMenuItem: function(itemValue, itemName) {
    return true ;
  },

  /**
    override this method to implement your own sorting of the menu. By
    default, menu items are sorted using the value shown or the sortKey

    @param objects the unsorted array of objects to display.
    @returns sorted array of objects
  */
  sortObjects: function(objects) {
    if(!this.get('disableSort')){
      var nameKey = this.get('sortKey') || this.get('nameKey') ;
      objects = objects.sort(function(a,b) {
        if (nameKey) {
          a = a.get ? a.get(nameKey) : a[nameKey] ;
          b = b.get ? b.get(nameKey) : b[nameKey] ;
        }
        return (a<b) ? -1 : ((a>b) ? 1 : 0) ;
      }) ;
    }
    return objects ;
  },

  render: function(context, firstTime) {
    if (this.get('cpDidChange')) {
      this.set('cpDidChange', NO);
      // get list of objects.
      var nameKey = this.get('nameKey') ;
      var valueKey = this.get('valueKey') ;
      var objects = this.get('objects') ;
      var fieldValue = this.get('value') ;
      var el, selectElement;

      // get the localization flag.
      var shouldLocalize = this.get('localize');

      // convert fieldValue to guid, if it is an object.
      if (!valueKey && fieldValue) fieldValue = SC.guidFor(fieldValue) ;
      if ((fieldValue === null) || (fieldValue === '')) fieldValue = '***' ;

      if (objects) {
        objects = this.sortObjects(objects) ; // sort'em.
        // var html = [] ;
        if(!firstTime){
          selectElement=this.$input()[0];
          selectElement.innerHTML='';
        }

        var emptyName = this.get('emptyName') ;
        if (emptyName) {
          if (shouldLocalize) emptyName = emptyName.loc() ;
          if(firstTime){
            context.push('<option value="***">%@</option>'.fmt(emptyName)) ;
            context.push('<option disabled="disabled"></option>') ;
          }else{
            el=document.createElement('option');
            el.value="***";
            el.innerHTML=emptyName;
            selectElement.appendChild(el);
            el=document.createElement('option');
            el.disabled="disabled";
            selectElement.appendChild(el);
          }
        }

          // generate option elements.
        objects.forEach(function(object) {
        if (object) {
          // either get the name from the object or convert object to string.
          var name = nameKey ? (object.get ? object.get(nameKey) : object[nameKey]) : object.toString() ;

          // localize name if specified.
          if(shouldLocalize)
          {
            name = name.loc();
          }

          // get the value using the valueKey or the object if no valueKey.
          // then convert to a string or use _guid if one of available.
          var value = (valueKey) ? (object.get ? object.get(valueKey) : object[valueKey]) : object ;
          if (value) value = (SC.guidFor(value)) ? SC.guidFor(value) : value.toString() ;

          // render HTML
          var disable = (this.validateMenuItem && this.validateMenuItem(value, name)) ? '' : 'disabled="disabled" ' ;
          if(firstTime){
            context.push('<option %@value="%@">%@</option>'.fmt(disable,value,name)) ;
          } else{
            el=document.createElement('option');
            el.value=value;
            el.innerHTML=name;
            if(disable.length>0) el.disable="disabled";
            selectElement.appendChild(el);
          }
        // null value means separator.
        } else {
          if(firstTime){
            context.push('<option disabled="disabled"></option>') ;
          }else{
            el=document.createElement('option');
            el.disabled="disabled";
            selectElement.appendChild(el);
          }
        }
      }, this );

      this.setFieldValue(fieldValue);

      } else {
        this.set('value',null);
      }
    }
  },

  displayProperties: ['objects','nameKey','valueKey'],

  _objectsObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('objects'),

  _nameKeyObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('nameKey'),

  _valueKeyObserver: function() {
    this.set('cpDidChange', YES);
  }.observes('valueKey'),

  // .......................................
  // PRIVATE
  //

  $input: function() { return this.$(); },

  /* @private */
  mouseDown: function(evt) {

    if (!this.get('isEnabled')) {
      evt.stop();
      return YES;
    } else return sc_super();
  },

  // when fetching the raw value, convert back to an object if needed...
  /** @private */
  getFieldValue: function() {
    var value = sc_super(); // get raw value...
    var valueKey = this.get('valueKey') ;
    var objects = this.get('objects') ;
    var found, object;

    // Handle empty selection.
    if (value == '***') {
      value = null ;

    // If no value key was set and there are objects then match back to an
    // object.
    } else if (value && objects) {
      // objects = Array.from(objects) ;

      var loc = (SC.typeOf(objects.length) === SC.T_FUNCTION) ? objects.length() : objects.length;

      found = null ; // matching object goes here.
      while(!found && (--loc >= 0)) {
        object = objects.objectAt? objects.objectAt(loc) : objects[loc] ;

        // get value using valueKey if there is one or use object
        // map to _guid or toString.
        if (valueKey) object = (object.get) ? object.get(valueKey) : object[valueKey] ;
        var ov = (object) ? (SC.guidFor(object) ? SC.guidFor(object) : object.toString()) : null ;

        // use this object value if it matches.
        if (value == ov) found = object ;
      }
    }

    return (valueKey || found) ? found : value;
  },

  setFieldValue: function(newValue) {
    if (SC.none(newValue)) { newValue = '' ; }
    else {
      newValue = ((newValue) ? (SC.guidFor(newValue) ? SC.guidFor(newValue) : newValue.toString()) : null );
    }
    this.$input().val(newValue);
    return this ;
  },

  fieldDidFocus: function() {
    var isFocused = this.get('isFocused');
    if (!isFocused) this.set('isFocused', true);
  },

  fieldDidBlur: function() {
    var isFocused = this.get('isFocused');
    if (isFocused) this.set('isFocused', false);
  },

  _isFocusedObserver: function() {
    this.$().setClass('focus', this.get('isFocused'));
  }.observes('isFocused'),

  didCreateLayer: function() {
    var input = this.$input();
    if (this.get('isEnabled') == false)
      this.$()[0].disabled = true;
    SC.Event.add(input, 'blur', this, this.fieldDidBlur);
    SC.Event.add(input, 'focus',this, this.fieldDidFocus);
    return sc_super();
  },

  willDestroyLayer: function() {
    var input = this.$input();
    SC.Event.remove(input, 'focus', this, this.fieldDidFocus);
    SC.Event.remove(input, 'blur', this, this.fieldDidBlur);
    return sc_super();
  }

});
<|endoftext|>


<commit_before>var lastTrack = null;
var $r = chrome.runtime.sendMessage;

function scrobble(e) {
    var regexp = new RegExp("\\S+\\s(.+)\\s\\S\\s(.+)\\s\\S+", "gi");
    var current = $(".now-playing").text();
    var res = regexp.exec(current);
    var artist = res[1];
    var title = res[2];

    if (lastTrack != artist + " " + title) {
        lastTrack = artist + " " + title;

        $r({type: 'validate', artist: artist, track: title}, function(response) {
            if (response != false) {
                $r({
                    type: 'nowPlaying',
                    artist: response.artist,
                    track: response.track,
                    duration: Math.floor(response.duration / 1000)
                });
            } else {
                $r({type: 'nowPlaying'});
            }
        });
    }
}

$(function() {
    $(window).unload(function() {
        // reset the background scrobbler song data
        chrome.runtime.sendMessage({type: 'reset'});
        return true;
    });

    if ($("#player").length > 0) {
        $(".pl-main-win").bind("DOMSubtreeModified", function(e) {
            if ($("#play").attr("class").indexOf("pause") != -1)
                setTimeout(scrobble, 500);
        });
    }
});

/**
 * Listen for requests from scrobbler.js
 */
chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        switch(request.type) {

            // background calls this to see if the script is already injected
            case 'ping':
                sendResponse(true);
                break;
        }
    }
);<commit_msg>prostopleer duration fix + repeat playing support added<commit_after>var lastTrack = '';
var startTime = 0;

function parseDuration (duration) {
    var res = /(\d+):(\d+)/.exec(duration);
    return parseInt(res[1], 10) * 60 + parseInt(res[2], 10);
}

function scrobble () {
    var res = /\S+\s(.+)\s\S\s(.+)\s\(([^)]+)\)/gi.exec($('.now-playing').text());

    var artist = res[1];
    var title = res[2];
    var duration = parseDuration(res[3]);

    var now = new Date().getTime();
    var isNewPlaying = (lastTrack != artist + ' ' + title) || /* new artist-title pair or */
            ((lastTrack == artist + ' ' + title) && ((now - startTime) > 1000 * duration)); /* repeated playing of same track */

    if (isNewPlaying) {
        lastTrack = artist + ' ' + title;
        startTime = now;

        chrome.runtime.sendMessage({type: 'validate', artist: artist, track: title}, function (response) {
            if (response !== false) {
                chrome.runtime.sendMessage({
                    type: 'nowPlaying',
                    artist: response.artist,
                    track: response.track,
                    duration: duration
                });
            } else
                chrome.runtime.sendMessage({type: 'nowPlaying'}); // unidentified music
        });
    }
}

$(function () {
    $(window).unload(function () {
	// reset the background scrobbler song data
	chrome.runtime.sendMessage({type: 'reset'});
	return true;
    });

    $('.pl-main-win').bind('DOMSubtreeModified', function () {
        if ($('#play').attr('class').indexOf('pause') != -1)
            setTimeout(scrobble, 1000);
    });
});

/**
 * Listen for requests from scrobbler.js
 */
chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        switch(request.type) {

            // background calls this to see if the script is already injected
            case 'ping':
                sendResponse(true);
                break;
        }
    }
);
<|endoftext|>