<commit_before>
window.onload = function () {
    // TODO:: Do your initialization job
    window.logtext = [];

    // Get a reference to the local "service"
    window.msf.local(function(err, service) {
        if (err) {
            console.log('msf.local error: ' + err);
            return;
        }
        // Create a reference to a communication "channel"
        var channel = service.channel('asksepp');
        window.channel = channel;

        // Connect to the channel
        channel.connect(function (err) {
            if(err) return console.error(err);
            console.log('You are connected');
        });

        // Add a message listener. This is where you will receive messages from mobile devices
        channel.on('fireMissile', function(msg, from){
            console.log(from.attributes.name + ' says, ' + msg);
            if(msg == 'testText') {
                console.log('testText request incoming');
                window.channel.publish('getTime', 'DumyTime xx.xx.xx');
            }
        });

        // Add a listener for when another client connects, such as a mobile device
        channel.on('clientConnect', function(client){
            console.log('client connected');
        });
    });

    // add eventListener for tizenhwkey
    document.addEventListener('tizenhwkey', function(e) {
        if(e.keyName == "back")
	try {
	    tizen.application.getCurrentApplication().exit();
	} catch (ignore) {
	}
    });

    /*document.addEventListener('keydown', function(e) {
    	// Down Arrow
    	if(e.keyCode == 40) {
    		debug();
    	}
    });*/
document.addEventListener( 'keyup', debug );
document.addEventListener( 'keydown', setFocusElement );

    // Sample code
    //var url = 'http://vod-level3-psd-progressive.p7s1digital.de/notice/new/not_available_de_640x360.mp4?token=01~~~31343538333936363930~3836343030~0-562304853786eb86d47478dde&ts=1458396690&access_token=s2s_7hack&video=';

    var url = 'http://vod-level3-psd-progressive.p7s1digital.de/clips/08/a8/88772-n961ez-tp06.mp4?token=00~400e~15ac4~56ed7478~15180~0-8d24888d1ffc97d87ff78aac8&ts=1458402424&access_token=s2s_7hack&video=1296000';
    var video = webapis.avplay.open(url);
    // 1920*1080 fullsize 10.100.105.199
    webapis.avplay.setDisplayRect(0, 0, 1920, 1080);
    webapis.avplay.setListener(onerror, listError);
    webapis.avplay.prepareAsync(play, error);

    //$('video').html(video);

    var textbox = document.querySelector('.contents');
    textbox.addEventListener("click", function(){
    	box = document.querySelector('#textbox');
    	box.innerHTML = box.innerHTML == "Basic" ? "Sample" : "Basic";
    });
    window.logtext.push('done');
};

function debug() {
	console.log(window.logtext);
}

function play() {
	//webapis.avplay.prepare();
    webapis.avplay.play();
    //console.log('play prepare successfully');
    window.logtext.push('play prepare successfully');
}

function listError() {
	//webapis.avplay.prepare();
    //webapis.avplay.play();
    //console.log('play prepare failed');
	window.logtext.push('play prepare failed');
}

function error() {
	webapis.avplay.prepare();
    webapis.avplay.play();
    //console.log('gneral error');
    window.logtext.push('general error');
}<commit_msg>cleaning mainpage from video player in background<commit_after>
window.onload = function () {
    // TODO:: Do your initialization job
    window.logtext = [];

    // Get a reference to the local "service"
    window.msf.local(function(err, service) {
        if (err) {
            console.log('msf.local error: ' + err);
            return;
        }
        // Create a reference to a communication "channel"
        var channel = service.channel('asksepp');
        window.channel = channel;

        // Connect to the channel
        channel.connect(function (err) {
            if(err) return console.error(err);
            console.log('You are connected');
        });

        // Add a message listener. This is where you will receive messages from mobile devices
        channel.on('fireMissile', function(msg, from){
            console.log(from.attributes.name + ' says, ' + msg);
            if(msg == 'testText') {
                console.log('testText request incoming');
                window.channel.publish('getTime', 'DumyTime xx.xx.xx');
            }
        });

        // Add a listener for when another client connects, such as a mobile device
        channel.on('clientConnect', function(client){
            console.log('client connected');
        });
    });

    // add eventListener for tizenhwkey
    document.addEventListener('tizenhwkey', function(e) {
        if(e.keyName == "back")
	try {
	    tizen.application.getCurrentApplication().exit();
	} catch (ignore) {
	}
    });

    document.addEventListener( 'keyup', debug );
    document.addEventListener( 'keydown', setFocusElement );
};

function debug() {
	console.log(window.logtext);
}<|endoftext|>


<commit_before>'use strict';

const demFeels = require('dem-feels');
const color = require('../config/color');

exports.parseEmoticons = parseEmoticons;

const emotes = demFeels.getEmotes();

const emotesKeys = Object.keys(emotes);

/**
* Parse emoticons in message.
*
* @param {String} message
* @param {Object} room
* @param {Object} user
* @param {Boolean} pm - returns a string if it is in private messages
* @returns {Boolean|String}
*/
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	let match = false;
	let len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = demFeels(message);

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	const group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	let style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
* Create a two column table listing emoticons.
*
* @return {String} emotes table
*/
function create_table() {
	let emotes_name = Object.keys(emotes);
	let emotes_list = [];
	let emotes_group_list = [];
	let len = emotes_name.length;

	for (let i = 0; i < len; i++) {
		emotes_list.push("" +
			"" +
			emotes_name[i] + "	");
	}

	let emotes_list_right = emotes_list.splice(len / 2, len / 2);

	for (let i = 0; i < len / 2; i++) {
		let emote1 = emotes_list[i];
		let emote2 = emotes_list_right[i];
		if (emote2) {
			emotes_group_list.push("
" + emote1 + emote2 + "
");
		} else {
			emotes_group_list.push("
" + emote1 + "
");
		}
	}

	return "
List of Emoticons" + "

" + "
" + emotes_group_list.join("") + "
" + "

";
}

let emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emotes: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.canBroadcast()) return;
		this.sendReply("|raw|" + emotes_table);
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."],

	rande: 'randemote',
	randemote: function (target, room, user) {
		if (!this.canBroadcast()) return;
		let rng = Math.floor(Math.random() * emotesKeys.length);
		let randomEmote = emotesKeys[rng];
		this.sendReplyBox("");
	},
	randemotehelp: ["/randemote - Get a random emote."],
};
<commit_msg>Update missing folder in module<commit_after>'use strict';

const color = require('../config/color');
let demFeels;
try {
	demFeels = require('dem-feels');
} catch (e) {
	console.error(e);
}

exports.parseEmoticons = parseEmoticons;

const emotes = demFeels.getEmotes();

const emotesKeys = Object.keys(emotes);

/**
* Parse emoticons in message.
*
* @param {String} message
* @param {Object} room
* @param {Object} user
* @param {Boolean} pm - returns a string if it is in private messages
* @returns {Boolean|String}
*/
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	let match = false;
	let len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = demFeels(message);

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	const group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	let style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
* Create a two column table listing emoticons.
*
* @return {String} emotes table
*/
function create_table() {
	let emotes_name = Object.keys(emotes);
	let emotes_list = [];
	let emotes_group_list = [];
	let len = emotes_name.length;

	for (let i = 0; i < len; i++) {
		emotes_list.push("" +
			"" +
			emotes_name[i] + "	");
	}

	let emotes_list_right = emotes_list.splice(len / 2, len / 2);

	for (let i = 0; i < len / 2; i++) {
		let emote1 = emotes_list[i];
		let emote2 = emotes_list_right[i];
		if (emote2) {
			emotes_group_list.push("
" + emote1 + emote2 + "
");
		} else {
			emotes_group_list.push("
" + emote1 + "
");
		}
	}

	return "
List of Emoticons" + "

" + "
" + emotes_group_list.join("") + "
" + "

";
}

let emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emotes: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.canBroadcast()) return;
		this.sendReply("|raw|" + emotes_table);
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."],

	rande: 'randemote',
	randemote: function (target, room, user) {
		if (!this.canBroadcast()) return;
		let rng = Math.floor(Math.random() * emotesKeys.length);
		let randomEmote = emotesKeys[rng];
		this.sendReplyBox("");
	},
	randemotehelp: ["/randemote - Get a random emote."],
};
<|endoftext|>


<commit_before>import '../permalink/permalink.module';
import { DoubleClickZoom, KeyboardPan, KeyboardZoom, MouseWheelZoom, PinchRotate, PinchZoom, DragPan, DragRotate, DragZoom } from 'ol/interaction';
import Kinetic from 'ol/Kinetic';
import Map from 'ol/Map';
import View from 'ol/View';
import { MousePosition, defaults as controlDefaults } from 'ol/control';
import { createStringXY } from 'ol/coordinate';
import { TileWMS, WMTS } from 'ol/source';
import { ImageWMS, ImageArcGISRest } from 'ol/source';
import Feature from 'ol/Feature';
import { Group } from 'ol/layer';
import { Vector } from 'ol/source';

/**
 * This is a workaround.
 * Returns the associated layer.
 * TODO: Not sure if it is used anywhere. Have to check.
 * @param {ol.Map} map.
 * @return {ol.layer.Vector} Layer.
 */
Feature.prototype.getLayer = function (map) {
    var this_ = this,
        layer_, layersToLookFor = [];
    var check = function (layer) {
        var source = layer.getSource();
        if (utils.instOf(source, Vector)) {
            var features = source.getFeatures();
            if (features.length > 0) {
                layersToLookFor.push({
                    layer: layer,
                    features: features
                });
            }
        }
    };
    map.getLayers().forEach(function (layer) {
        if (utils.instOf(layer, Group)) {
            layer.getLayers().forEach(check);
        } else {
            check(layer);
        }
    });
    layersToLookFor.forEach(function (obj) {
        var found = obj.features.some(function (feature) {
            return this_ === feature;
        });
        if (found) {
            layer_ = obj.layer;
        }
    });
    return layer_;
};

export default ['config', '$rootScope', 'hs.utils.service', '$timeout', function (config, $rootScope, utils, $timeout) {
    //timer variable for extent change event
    var timer;
    /**
     * @ngdoc method
     * @name hs.map.service#init
     * @public
     * @description Initialization function for HSLayers map object. Initialize map with basic interaction, scale line and watcher for map view changes. When default controller is used, its called automaticaly, otherwise its must be called before other modules dependent on map object are loaded.
     */
    this.init = function () {
        if (angular.isDefined(me.map)) {
            me.map.getLayers().clear();
        }
        me.map = new Map({
            controls: controlDefaults({
                zoom: false
            }),
            target: 'map',
            interactions: [],
            view: cloneView(config.default_view || createPlaceholderView())
        });

        me.visible = true;

        function extentChanged(e) {
            if (timer != null) clearTimeout(timer);
            timer = setTimeout(function () {
                /**
                 * @ngdoc event
                 * @name hs.map.service#map.extent_changed
                 * @eventType broadcast on $rootScope
                 * @description Fires when map extent change (move, zoom, resize). Fires with two parameters: map element and new calculated {@link http://openlayers.org/en/latest/apidoc/ol.html#.Extent extent}
                 */
                $rootScope.$broadcast('map.extent_changed', e.element, me.map.getView().calculateExtent(me.map.getSize()));
            }, 500);
        }
        me.map.getView().on('change:center', function (e) {
            extentChanged(e);
        });
        me.map.getView().on('change:resolution', function (e) {
            extentChanged(e);
        });

        me.map.on('moveend', function (e) {
            extentChanged(e);
        });

        angular.forEach(me.interactions, function (value, key) {
            me.map.addInteraction(value);
        });
        //me.map.addControl(new ol.control.ZoomSlider());
        // me.map.addControl(new ol.control.ScaleLine());

        me.repopulateLayers();
        /**
         * @ngdoc event
         * @name hs.map.service#map.loaded
         * @eventType broadcast on $rootScope
         * @description Fires when map is loaded (so other map dependent modules can proceed)
         */
        $rootScope.$broadcast('map.loaded');
    }

    //clone View to not overwrite deafult
    function cloneView(template) {
        var view = new View({
            center: template.getCenter(),
            zoom: template.getZoom(),
            projection: template.getProjection(),
            rotation: template.getRotation()
        });
        return view;
    }

    /**
     * @ngdoc property
     * @name hs.map.service#duration
     * @public
     * @type {Number} 400
     * @description Duration of added interactions animation. (400 ms used, default in OpenLayers is 250 ms)
     */
    this.duration = 400;

    /**
     * @ngdoc property
     * @name hs.map.service#interactions
     * @public
     * @type {Object}
     * @description Set of default map interactions used in HSLayers ({@link http://openlayers.org/en/latest/apidoc/ol.interaction.DoubleClickZoom.html DoubleClickZoom},{@link http://openlayers.org/en/latest/apidoc/ol.interaction.KeyboardPan.html KeyboardPan}, {@link http://openlayers.org/en/latest/apidoc/ol.interaction.KeyboardZoom.html KeyboardZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.MouseWheelZoom.html MouseWheelZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.PinchRotate.html PinchRotate} , {@link http://openlayers.org/en/latest/apidoc/ol.interaction.PinchZoom.html PinchZoom}, {@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragPan.html DragPan},{@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragZoom.html DragZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragRotate.html DragRotate} )
     */
    this.interactions = {
        'DoubleClickZoom': new DoubleClickZoom({
            duration: this.duration
        }),
        'KeyboardPan': new KeyboardPan({
            pixelDelta: 256
        }),
        'KeyboardZoom': new KeyboardZoom({
            duration: this.duration
        }),
        'MouseWheelZoom': new MouseWheelZoom({
            duration: this.duration
        }),
        'PinchRotate': new PinchRotate(),
        'PinchZoom': new PinchZoom({
            constrainResolution: true,
            duration: this.duration
        }),
        'DragPan': new DragPan({
            kinetic: new Kinetic(-0.01, 0.1, 200)
        }),
        'DragZoom': new DragZoom(),
        'DragRotate': new DragRotate()
    }

    //Mouse position control, currently not used
    var mousePositionControl = new MousePosition({
        coordinateFormat: createStringXY(4),
        undefinedHTML: ' '
    });

    var me = this;

    /**
     * @ngdoc method
     * @name hs.map.service#findLayerByTitle
     * @public
     * @param {string} title Title of the layer (from layer creation)
     * @returns {Ol.layer} Ol.layer object
     * @description Find layer object by title of layer
     */
    this.findLayerByTitle = function (title) {

        var layers = me.map.getLayers();
        var tmp = null;
        angular.forEach(layers, function (layer) {
            if (layer.get('title') == title) tmp = layer;
        });
        return tmp;
    }

    function layersEqual(existing, lyr) {
        var s_existing = existing.getSource();
        var s_new = lyr.getSource();
        return existing.get("title") == lyr.get("title") &&
            typeof s_existing == typeof s_new &&
            (angular.isUndefined(s_existing.getParams) || s_existing.getParams().LAYERS == s_new.getParams().LAYERS) &&
            (angular.isUndefined(s_existing.getUrl) || s_existing.getUrl() == s_new.getUrl()) &&
            (angular.isUndefined(s_existing.getUrls) || s_existing.getUrls() == s_new.getUrls())
    }

    this.layerDuplicate = function (lyr) {
        return me.map.getLayers().getArray().filter(function (existing) {
            layersEqual(existing, lyr)
        }).length > 0;
    }

    this.removeDuplicate = function (lyr) {
        me.map.getLayers().getArray().filter(function (existing) {
            layersEqual(existing, lyr)
        }).forEach(function (to_remove) { me.map.getLayers().remove(to_remove) });
    }

    this.addLayer = function (lyr) {
        if (me.layerDuplicate(lyr))
            me.removeDuplicate(lyr);
        me.map.addLayer(lyr);
    }

    /**
     * @ngdoc method
     * @name hs.map.service#repopulateLayers
     * @public
     * @param {object} visible_layers List of layers, which should be visible.
     * @description Add all layers from app config (box_layers and default_layers) to the map. Only layers specified in visible_layers parameter will get instantly visible.
     */
    this.repopulateLayers = function (visible_layers) {
        if (angular.isDefined(config.box_layers)) {
            angular.forEach(config.box_layers, function (box) {
                angular.forEach(box.get('layers'), function (lyr) {
                    if (!me.layerDuplicate(lyr)) {
                        lyr.setVisible(me.isLayerVisible(lyr, me.visible_layers));
                        lyr.manuallyAdded = false;
                        if (utils.instOf(lyr.getSource(), ImageWMS))
                            me.proxifyLayerLoader(lyr, false);
                        if (utils.instOf(lyr.getSource(), TileWMS))
                            me.proxifyLayerLoader(lyr, true);
                        if (utils.instOf(lyr.getSource(), Vector))
                            me.getVectorType(lyr);
                        me.map.addLayer(lyr);
                    }
                });
            });
        }

        if (angular.isDefined(config.default_layers)) {
            angular.forEach(config.default_layers, function (lyr) {
                if (!me.layerDuplicate(lyr)) {
                    lyr.setVisible(me.isLayerVisible(lyr, me.visible_layers));
                    lyr.manuallyAdded = false;
                    if (utils.instOf(lyr.getSource(), ImageWMS))
                        me.proxifyLayerLoader(lyr, false);
                    if (utils.instOf(lyr.getSource(), TileWMS))
                        me.proxifyLayerLoader(lyr, true);
                    if (utils.instOf(lyr.getSource(), Vector))
                        me.getVectorType(lyr);
                    me.map.addLayer(lyr);
                }
            });
        }
    }

    this.getVectorType = function (layer) {
        var src = layer.getSource();
        src.hasLine = false;
        src.hasPoly = false;
        src.hasPoint = false;
        if (src.getFeatures().length > 0) {
            vectorSourceTypeComputer(src);
        }
        else {
            src.on('change', function (evt) {
                var source = evt.target;
                if (source.getState() === 'ready') {
                    vectorSourceTypeComputer(source);
                }
            })
        }
    }

    function vectorSourceTypeComputer(src) {
        angular.forEach(src.getFeatures(), function (f) {
            if (f.getGeometry()) {
                switch (f.getGeometry().getType()) {
                    case 'LineString':
                    case 'MultiLineString':
                        src.hasLine = true;
                        break;
                    case 'Polygon':
                    case 'MultiPolygon':
                        src.hasPoly = true;
                        break;
                    case 'Point':
                    case 'MultiPoint':
                        src.hasPoint = true;
                        break;
                }
            }
        })
        if (src.hasLine || src.hasPoly || src.hasPoint) {
            src.styleAble = true;
        }
    }

    /**
     * @ngdoc method
     * @name hs.map.service#reset
     * @public
     * @description Reset map to state configured in app config (reload all layers and set default view)
     */
    this.reset = function () {
        var to_be_removed = [];
        me.map.getLayers().forEach(function (lyr) {
            to_be_removed.push(lyr);
        });
        while (to_be_removed.length > 0) me.map.removeLayer(to_be_removed.shift());
        me.repopulateLayers(null);
        me.resetView();
    }

    /**
     * @ngdoc method
     * @name hs.map.service#resetView
     * @public
     * @description Reset map view to view configured in app config
     */
    this.resetView = function () {
        me.map.setView(cloneView(config.default_view || createPlaceholderView()));
    }

    function createPlaceholderView() {
        return new View({
            center: transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
            zoom: 4,
            units: "m"
        })
    }

    /**
     * @function isLayerVisibleInPermalink
     * @memberOf hs.map.controller.init
     * @param {ol.Layer} lyr - Layer for which to determine visibility
     * @description Finds out if layer is set as visible in URL (permalink)
     */
    /**
     * @ngdoc method
     * @name hs.map.service#isLayerVisible
     * @public
     * @param {ol.Layer} lyr Layer for which to determine visibility
     * @param {Array} visible_layers Layers which should be programmticaly visible
     * @returns {Boolean} Detected visibility of layer
     * @description Determine if layer is visible, either by its visibility status in map, or by its being in visible_layers group
     */
    this.isLayerVisible = function (lyr, visible_layers) {
        if (visible_layers) {
            var found = false;
            angular.forEach(visible_layers, function (vlyr) {
                if (vlyr == lyr.get('title')) found = true;
            })
            return found;
        }
        return lyr.getVisible();
    }

    /**
     * @ngdoc method
     * @name hs.map.service#proxifyLayerLoader
     * @public
     * @param {Ol.layer} lyr Layer to proxify
     * @param {Boolean} tiled Info if layer is tiled
     * @description Proxify layer loader to work with layers from other sources than app
     */
    this.proxifyLayerLoader = function (lyr, tiled) {
        var src = lyr.getSource();
        me.map.getLayers().forEach(function (l) {
            if (l.get("source") == src) {
                return;
            }
        });
        if (tiled) {
            var tile_url_function = src.getTileUrlFunction() || src.tileUrlFunction();
            src.setTileUrlFunction(function (b, c, d) {
                var url = tile_url_function.call(src, b, c, d);
                if (url.indexOf('proxy') == -1) url = decodeURIComponent(url);
                return utils.proxify(url);
            });
        } else {
            lyr.getSource().setImageLoadFunction(function (image, src) {
                if (src.indexOf('proxy') == -1) src = decodeURIComponent(src);
                image.getImage().src = utils.proxify(src); //Previously urlDecodeComponent was called on src, but it breaks in firefox.
            })
        }
    }

    //map.addControl(mousePositionControl);
    /**
     * @ngdoc method
     * @name hs.map.service#puremap
     * @public
     * @description Clean interactions and zoom from map to get pure map
     */
    this.puremap = function () {
        var interactions = me.map.getInteractions();
        var controls = me.map.getControls();
        angular.forEach(interactions, function (interaction) {
            me.map.removeInteraction(interaction);
        })
        angular.forEach(controls, function (control) {
            me.map.removeControl(control);
        })
        $timeout(me.puremap, 1000);
    }

    /**
    * @ngdoc method

    * @public
    * @param {number} x X coordinate of new center
    * @param {number} y Y coordinate of new center
    * @param {number} zoom New zoom level
    * @description Move map and zoom to specified coordinate/zoom level
    */
    this.moveToAndZoom = function (x, y, zoom) {
        var view = me.map.getView();
        view.setCenter([x, y]);
        view.setZoom(zoom);
    }

    /**
     * @ngdoc method
     * @name hs.map.service#getMap
     * @public
     * @description Get ol.map object from service
     */
    this.getMap = function () {
        return OlMap.map;
    }

}]<commit_msg>Fix feature.getLayer fnctn and feature attrs list fixes #242<commit_after>import '../permalink/permalink.module';
import { DoubleClickZoom, KeyboardPan, KeyboardZoom, MouseWheelZoom, PinchRotate, PinchZoom, DragPan, DragRotate, DragZoom } from 'ol/interaction';
import Kinetic from 'ol/Kinetic';
import Map from 'ol/Map';
import View from 'ol/View';
import { MousePosition, defaults as controlDefaults } from 'ol/control';
import { createStringXY } from 'ol/coordinate';
import { TileWMS, WMTS } from 'ol/source';
import { ImageWMS, ImageArcGISRest } from 'ol/source';
import Feature from 'ol/Feature';
import { Group } from 'ol/layer';
import { Vector } from 'ol/source';

export default ['config', '$rootScope', 'hs.utils.service', '$timeout', function (config, $rootScope, utils, $timeout) {

    /**
     * This is a workaround.
     * Returns the associated layer.
     * TODO: Not sure if it is used anywhere. Have to check.
     * @param {ol.Map} map.
     * @return {ol.layer.Vector} Layer.
     */
    Feature.prototype.getLayer = function (map) {
        var this_ = this,
            layer_, layersToLookFor = [];
        var check = function (layer) {
            var source = layer.getSource();
            if (utils.instOf(source, Vector)) {
                var features = source.getFeatures();
                if (features.length > 0) {
                    layersToLookFor.push({
                        layer: layer,
                        features: features
                    });
                }
            }
        };
        map.getLayers().forEach(function (layer) {
            if (utils.instOf(layer, Group)) {
                layer.getLayers().forEach(check);
            } else {
                check(layer);
            }
        });
        layersToLookFor.forEach(function (obj) {
            var found = obj.features.some(function (feature) {
                return this_ === feature;
            });
            if (found) {
                layer_ = obj.layer;
            }
        });
        return layer_;
    };

    //timer variable for extent change event
    var timer;
    /**
     * @ngdoc method
     * @name hs.map.service#init
     * @public
     * @description Initialization function for HSLayers map object. Initialize map with basic interaction, scale line and watcher for map view changes. When default controller is used, its called automaticaly, otherwise its must be called before other modules dependent on map object are loaded.
     */
    this.init = function () {
        if (angular.isDefined(me.map)) {
            me.map.getLayers().clear();
        }
        me.map = new Map({
            controls: controlDefaults({
                zoom: false
            }),
            target: 'map',
            interactions: [],
            view: cloneView(config.default_view || createPlaceholderView())
        });

        me.visible = true;

        function extentChanged(e) {
            if (timer != null) clearTimeout(timer);
            timer = setTimeout(function () {
                /**
                 * @ngdoc event
                 * @name hs.map.service#map.extent_changed
                 * @eventType broadcast on $rootScope
                 * @description Fires when map extent change (move, zoom, resize). Fires with two parameters: map element and new calculated {@link http://openlayers.org/en/latest/apidoc/ol.html#.Extent extent}
                 */
                $rootScope.$broadcast('map.extent_changed', e.element, me.map.getView().calculateExtent(me.map.getSize()));
            }, 500);
        }
        me.map.getView().on('change:center', function (e) {
            extentChanged(e);
        });
        me.map.getView().on('change:resolution', function (e) {
            extentChanged(e);
        });

        me.map.on('moveend', function (e) {
            extentChanged(e);
        });

        angular.forEach(me.interactions, function (value, key) {
            me.map.addInteraction(value);
        });
        //me.map.addControl(new ol.control.ZoomSlider());
        // me.map.addControl(new ol.control.ScaleLine());

        me.repopulateLayers();
        /**
         * @ngdoc event
         * @name hs.map.service#map.loaded
         * @eventType broadcast on $rootScope
         * @description Fires when map is loaded (so other map dependent modules can proceed)
         */
        $rootScope.$broadcast('map.loaded');
    }

    //clone View to not overwrite deafult
    function cloneView(template) {
        var view = new View({
            center: template.getCenter(),
            zoom: template.getZoom(),
            projection: template.getProjection(),
            rotation: template.getRotation()
        });
        return view;
    }

    /**
     * @ngdoc property
     * @name hs.map.service#duration
     * @public
     * @type {Number} 400
     * @description Duration of added interactions animation. (400 ms used, default in OpenLayers is 250 ms)
     */
    this.duration = 400;

    /**
     * @ngdoc property
     * @name hs.map.service#interactions
     * @public
     * @type {Object}
     * @description Set of default map interactions used in HSLayers ({@link http://openlayers.org/en/latest/apidoc/ol.interaction.DoubleClickZoom.html DoubleClickZoom},{@link http://openlayers.org/en/latest/apidoc/ol.interaction.KeyboardPan.html KeyboardPan}, {@link http://openlayers.org/en/latest/apidoc/ol.interaction.KeyboardZoom.html KeyboardZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.MouseWheelZoom.html MouseWheelZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.PinchRotate.html PinchRotate} , {@link http://openlayers.org/en/latest/apidoc/ol.interaction.PinchZoom.html PinchZoom}, {@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragPan.html DragPan},{@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragZoom.html DragZoom} ,{@link http://openlayers.org/en/latest/apidoc/ol.interaction.DragRotate.html DragRotate} )
     */
    this.interactions = {
        'DoubleClickZoom': new DoubleClickZoom({
            duration: this.duration
        }),
        'KeyboardPan': new KeyboardPan({
            pixelDelta: 256
        }),
        'KeyboardZoom': new KeyboardZoom({
            duration: this.duration
        }),
        'MouseWheelZoom': new MouseWheelZoom({
            duration: this.duration
        }),
        'PinchRotate': new PinchRotate(),
        'PinchZoom': new PinchZoom({
            constrainResolution: true,
            duration: this.duration
        }),
        'DragPan': new DragPan({
            kinetic: new Kinetic(-0.01, 0.1, 200)
        }),
        'DragZoom': new DragZoom(),
        'DragRotate': new DragRotate()
    }

    //Mouse position control, currently not used
    var mousePositionControl = new MousePosition({
        coordinateFormat: createStringXY(4),
        undefinedHTML: ' '
    });

    var me = this;

    /**
     * @ngdoc method
     * @name hs.map.service#findLayerByTitle
     * @public
     * @param {string} title Title of the layer (from layer creation)
     * @returns {Ol.layer} Ol.layer object
     * @description Find layer object by title of layer
     */
    this.findLayerByTitle = function (title) {

        var layers = me.map.getLayers();
        var tmp = null;
        angular.forEach(layers, function (layer) {
            if (layer.get('title') == title) tmp = layer;
        });
        return tmp;
    }

    function layersEqual(existing, lyr) {
        var s_existing = existing.getSource();
        var s_new = lyr.getSource();
        return existing.get("title") == lyr.get("title") &&
            typeof s_existing == typeof s_new &&
            (angular.isUndefined(s_existing.getParams) || s_existing.getParams().LAYERS == s_new.getParams().LAYERS) &&
            (angular.isUndefined(s_existing.getUrl) || s_existing.getUrl() == s_new.getUrl()) &&
            (angular.isUndefined(s_existing.getUrls) || s_existing.getUrls() == s_new.getUrls())
    }

    this.layerDuplicate = function (lyr) {
        return me.map.getLayers().getArray().filter(function (existing) {
            layersEqual(existing, lyr)
        }).length > 0;
    }

    this.removeDuplicate = function (lyr) {
        me.map.getLayers().getArray().filter(function (existing) {
            layersEqual(existing, lyr)
        }).forEach(function (to_remove) { me.map.getLayers().remove(to_remove) });
    }

    this.addLayer = function (lyr) {
        if (me.layerDuplicate(lyr))
            me.removeDuplicate(lyr);
        me.map.addLayer(lyr);
    }

    /**
     * @ngdoc method
     * @name hs.map.service#repopulateLayers
     * @public
     * @param {object} visible_layers List of layers, which should be visible.
     * @description Add all layers from app config (box_layers and default_layers) to the map. Only layers specified in visible_layers parameter will get instantly visible.
     */
    this.repopulateLayers = function (visible_layers) {
        if (angular.isDefined(config.box_layers)) {
            angular.forEach(config.box_layers, function (box) {
                angular.forEach(box.get('layers'), function (lyr) {
                    if (!me.layerDuplicate(lyr)) {
                        lyr.setVisible(me.isLayerVisible(lyr, me.visible_layers));
                        lyr.manuallyAdded = false;
                        if (utils.instOf(lyr.getSource(), ImageWMS))
                            me.proxifyLayerLoader(lyr, false);
                        if (utils.instOf(lyr.getSource(), TileWMS))
                            me.proxifyLayerLoader(lyr, true);
                        if (utils.instOf(lyr.getSource(), Vector))
                            me.getVectorType(lyr);
                        me.map.addLayer(lyr);
                    }
                });
            });
        }

        if (angular.isDefined(config.default_layers)) {
            angular.forEach(config.default_layers, function (lyr) {
                if (!me.layerDuplicate(lyr)) {
                    lyr.setVisible(me.isLayerVisible(lyr, me.visible_layers));
                    lyr.manuallyAdded = false;
                    if (utils.instOf(lyr.getSource(), ImageWMS))
                        me.proxifyLayerLoader(lyr, false);
                    if (utils.instOf(lyr.getSource(), TileWMS))
                        me.proxifyLayerLoader(lyr, true);
                    if (utils.instOf(lyr.getSource(), Vector))
                        me.getVectorType(lyr);
                    me.map.addLayer(lyr);
                }
            });
        }
    }

    this.getVectorType = function (layer) {
        var src = layer.getSource();
        src.hasLine = false;
        src.hasPoly = false;
        src.hasPoint = false;
        if (src.getFeatures().length > 0) {
            vectorSourceTypeComputer(src);
        }
        else {
            src.on('change', function (evt) {
                var source = evt.target;
                if (source.getState() === 'ready') {
                    vectorSourceTypeComputer(source);
                }
            })
        }
    }

    function vectorSourceTypeComputer(src) {
        angular.forEach(src.getFeatures(), function (f) {
            if (f.getGeometry()) {
                switch (f.getGeometry().getType()) {
                    case 'LineString':
                    case 'MultiLineString':
                        src.hasLine = true;
                        break;
                    case 'Polygon':
                    case 'MultiPolygon':
                        src.hasPoly = true;
                        break;
                    case 'Point':
                    case 'MultiPoint':
                        src.hasPoint = true;
                        break;
                }
            }
        })
        if (src.hasLine || src.hasPoly || src.hasPoint) {
            src.styleAble = true;
        }
    }

    /**
     * @ngdoc method
     * @name hs.map.service#reset
     * @public
     * @description Reset map to state configured in app config (reload all layers and set default view)
     */
    this.reset = function () {
        var to_be_removed = [];
        me.map.getLayers().forEach(function (lyr) {
            to_be_removed.push(lyr);
        });
        while (to_be_removed.length > 0) me.map.removeLayer(to_be_removed.shift());
        me.repopulateLayers(null);
        me.resetView();
    }

    /**
     * @ngdoc method
     * @name hs.map.service#resetView
     * @public
     * @description Reset map view to view configured in app config
     */
    this.resetView = function () {
        me.map.setView(cloneView(config.default_view || createPlaceholderView()));
    }

    function createPlaceholderView() {
        return new View({
            center: transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
            zoom: 4,
            units: "m"
        })
    }

    /**
     * @function isLayerVisibleInPermalink
     * @memberOf hs.map.controller.init
     * @param {ol.Layer} lyr - Layer for which to determine visibility
     * @description Finds out if layer is set as visible in URL (permalink)
     */
    /**
     * @ngdoc method
     * @name hs.map.service#isLayerVisible
     * @public
     * @param {ol.Layer} lyr Layer for which to determine visibility
     * @param {Array} visible_layers Layers which should be programmticaly visible
     * @returns {Boolean} Detected visibility of layer
     * @description Determine if layer is visible, either by its visibility status in map, or by its being in visible_layers group
     */
    this.isLayerVisible = function (lyr, visible_layers) {
        if (visible_layers) {
            var found = false;
            angular.forEach(visible_layers, function (vlyr) {
                if (vlyr == lyr.get('title')) found = true;
            })
            return found;
        }
        return lyr.getVisible();
    }

    /**
     * @ngdoc method
     * @name hs.map.service#proxifyLayerLoader
     * @public
     * @param {Ol.layer} lyr Layer to proxify
     * @param {Boolean} tiled Info if layer is tiled
     * @description Proxify layer loader to work with layers from other sources than app
     */
    this.proxifyLayerLoader = function (lyr, tiled) {
        var src = lyr.getSource();
        me.map.getLayers().forEach(function (l) {
            if (l.get("source") == src) {
                return;
            }
        });
        if (tiled) {
            var tile_url_function = src.getTileUrlFunction() || src.tileUrlFunction();
            src.setTileUrlFunction(function (b, c, d) {
                var url = tile_url_function.call(src, b, c, d);
                if (url.indexOf('proxy') == -1) url = decodeURIComponent(url);
                return utils.proxify(url);
            });
        } else {
            lyr.getSource().setImageLoadFunction(function (image, src) {
                if (src.indexOf('proxy') == -1) src = decodeURIComponent(src);
                image.getImage().src = utils.proxify(src); //Previously urlDecodeComponent was called on src, but it breaks in firefox.
            })
        }
    }

    //map.addControl(mousePositionControl);
    /**
     * @ngdoc method
     * @name hs.map.service#puremap
     * @public
     * @description Clean interactions and zoom from map to get pure map
     */
    this.puremap = function () {
        var interactions = me.map.getInteractions();
        var controls = me.map.getControls();
        angular.forEach(interactions, function (interaction) {
            me.map.removeInteraction(interaction);
        })
        angular.forEach(controls, function (control) {
            me.map.removeControl(control);
        })
        $timeout(me.puremap, 1000);
    }

    /**
    * @ngdoc method

    * @public
    * @param {number} x X coordinate of new center
    * @param {number} y Y coordinate of new center
    * @param {number} zoom New zoom level
    * @description Move map and zoom to specified coordinate/zoom level
    */
    this.moveToAndZoom = function (x, y, zoom) {
        var view = me.map.getView();
        view.setCenter([x, y]);
        view.setZoom(zoom);
    }

    /**
     * @ngdoc method
     * @name hs.map.service#getMap
     * @public
     * @description Get ol.map object from service
     */
    this.getMap = function () {
        return OlMap.map;
    }

}]<|endoftext|>


<commit_before>'use strict';

var ROSE_DATA_PATH = config.dataPath ? config.dataPath : '/data/';

var ZZ_SCALE_IN = 0.01;
var ZZ_SCALE_OUT = 100;
var ZZ_TICK_PER_SEC = 4800;

var ROSELoader = {};

var EXPERIMENTAL_WS_LOAD = false;
if (EXPERIMENTAL_WS_LOAD) {

  var iopReqIdx = 1;
  var iopReqHandlers = {};
  iop.on('fr', function(reqIdx, data) {
    var callback = iopReqHandlers[reqIdx];
    if (callback) {
      callback(new BinaryReader(data));
      delete iopReqHandlers[reqIdx];
    }
  });
  ROSELoader.load = function(path, callback) {
    var thisReqIdx = iopReqIdx++;
    iopReqHandlers[thisReqIdx] = callback;
    iop.emit('fr', thisReqIdx, path);
  };

} else {

  ROSELoader.load = function(path, callback) {
    // Check for errors.
    var normPath = normalizePath(path);
    if (normPath !== path) {
      //console.warn('Unnormalized path used.', path);
      path = normPath;
    }

    var loader = new THREE.XHRLoader();
    loader.setResponseType('arraybuffer');
    loader.load(ROSE_DATA_PATH + path, function (buffer) {
      callback(new BinaryReader(buffer));
    });
  };

}

var ZZ_BLEND = {
  ZERO: 1,
  ONE: 2,
  SRC_COLOR: 3,
  INV_SRC_COLOR: 4,
  SRC_ALPHA: 5,
  INV_SRC_ALPHA: 6,
  DEST_ALPHA: 7,
  INV_DEST_ALPHA: 8,
  DEST_COLOR: 9,
  INV_DEST_COLOR: 10,
  SRC_ALPHA_SAT: 11,
  BOTH_SRC_ALPHA: 12,
  BOTH_INV_SRC_ALPHA: 13,
  BLEND_FACTOR: 14,
  INV_BLEND_FACTOR: 15
};

function convertZnzinBlendType(znzin) {
  switch(znzin) {
    case ZZ_BLEND.ZERO:
      return THREE.ZeroFactor;
    case ZZ_BLEND.ONE:
      return THREE.OneFactor;
    case ZZ_BLEND.SRC_COLOR:
      return THREE.SrcColorFactor;
    case ZZ_BLEND.INV_SRC_COLOR:
      return THREE.OneMinusSrcColorFactor;
    case ZZ_BLEND.SRC_ALPHA:
      return THREE.SrcAlphaFactor;
    case ZZ_BLEND.INV_SRC_ALPHA:
      return THREE.OneMinusSrcAlphaFactor;
    case ZZ_BLEND.DEST_ALPHA:
      return THREE.DstAlphaFactor;
    case ZZ_BLEND.INV_DEST_ALPHA:
      return THREE.OneMinusDstAlphaFactor;
    case ZZ_BLEND.DEST_COLOR:
      return THREE.DstColorFactor;
    case ZZ_BLEND.INV_DEST_COLOR:
      return THREE.OneMinusDstColorFactor;
    case ZZ_BLEND.SRC_ALPHA_SAT:
      return THREE.SrcAlphaSaturateFactor;
    case ZZ_BLEND.BOTH_SRC_ALPHA:
    case ZZ_BLEND.BOTH_INV_SRC_ALPHA:
    case ZZ_BLEND.BLEND_FACTOR:
    case ZZ_BLEND.INV_BLEND_FACTOR:
      throw 'Unsupported znzin blend type ' + znzin;
  }
}

var ZZ_BLEND_OP = {
  ADD: 1,
  SUBTRACT: 2,
  REV_SUBTRACT: 3,
  MIN: 4,
  MAX: 5
};

function convertZnzinBlendOp(znzin) {
  switch(znzin) {
    case ZZ_BLEND_OP.ADD:
      return THREE.AddEquation;
    case ZZ_BLEND_OP.SUBTRACT:
      return THREE.SubtractEquation;
    case ZZ_BLEND_OP.REV_SUBTRACT:
      return THREE.ReverseSubtractEquation;
    case ZZ_BLEND_OP.MIN:
      return THREE.MinEquation;
    case ZZ_BLEND_OP.MAX:
      return THREE.MaxEquation;
  }
}
<commit_msg>Added fallback for unsupported ROSE blend modes.<commit_after>'use strict';

var ROSE_DATA_PATH = config.dataPath ? config.dataPath : '/data/';

var ZZ_SCALE_IN = 0.01;
var ZZ_SCALE_OUT = 100;
var ZZ_TICK_PER_SEC = 4800;

var ROSELoader = {};

var EXPERIMENTAL_WS_LOAD = false;
if (EXPERIMENTAL_WS_LOAD) {

  var iopReqIdx = 1;
  var iopReqHandlers = {};
  iop.on('fr', function(reqIdx, data) {
    var callback = iopReqHandlers[reqIdx];
    if (callback) {
      callback(new BinaryReader(data));
      delete iopReqHandlers[reqIdx];
    }
  });
  ROSELoader.load = function(path, callback) {
    var thisReqIdx = iopReqIdx++;
    iopReqHandlers[thisReqIdx] = callback;
    iop.emit('fr', thisReqIdx, path);
  };

} else {

  ROSELoader.load = function(path, callback) {
    // Check for errors.
    var normPath = normalizePath(path);
    if (normPath !== path) {
      //console.warn('Unnormalized path used.', path);
      path = normPath;
    }

    var loader = new THREE.XHRLoader();
    loader.setResponseType('arraybuffer');
    loader.load(ROSE_DATA_PATH + path, function (buffer) {
      callback(new BinaryReader(buffer));
    });
  };

}

var ZZ_BLEND = {
  ZERO: 1,
  ONE: 2,
  SRC_COLOR: 3,
  INV_SRC_COLOR: 4,
  SRC_ALPHA: 5,
  INV_SRC_ALPHA: 6,
  DEST_ALPHA: 7,
  INV_DEST_ALPHA: 8,
  DEST_COLOR: 9,
  INV_DEST_COLOR: 10,
  SRC_ALPHA_SAT: 11,
  BOTH_SRC_ALPHA: 12,
  BOTH_INV_SRC_ALPHA: 13,
  BLEND_FACTOR: 14,
  INV_BLEND_FACTOR: 15
};

function convertZnzinBlendType(znzin) {
  switch(znzin) {
    case ZZ_BLEND.ZERO:
      return THREE.ZeroFactor;
    case ZZ_BLEND.ONE:
      return THREE.OneFactor;
    case ZZ_BLEND.SRC_COLOR:
      return THREE.SrcColorFactor;
    case ZZ_BLEND.INV_SRC_COLOR:
      return THREE.OneMinusSrcColorFactor;
    case ZZ_BLEND.SRC_ALPHA:
      return THREE.SrcAlphaFactor;
    case ZZ_BLEND.INV_SRC_ALPHA:
      return THREE.OneMinusSrcAlphaFactor;
    case ZZ_BLEND.DEST_ALPHA:
      return THREE.DstAlphaFactor;
    case ZZ_BLEND.INV_DEST_ALPHA:
      return THREE.OneMinusDstAlphaFactor;
    case ZZ_BLEND.DEST_COLOR:
      return THREE.DstColorFactor;
    case ZZ_BLEND.INV_DEST_COLOR:
      return THREE.OneMinusDstColorFactor;
    case ZZ_BLEND.SRC_ALPHA_SAT:
      return THREE.SrcAlphaSaturateFactor;
    case ZZ_BLEND.BOTH_SRC_ALPHA:
    case ZZ_BLEND.BOTH_INV_SRC_ALPHA:
    case ZZ_BLEND.BLEND_FACTOR:
    case ZZ_BLEND.INV_BLEND_FACTOR:
      throw 'Unsupported znzin blend type ' + znzin;
  }
}

var ZZ_BLEND_OP = {
  ADD: 1,
  SUBTRACT: 2,
  REV_SUBTRACT: 3,
  MIN: 4,
  MAX: 5
};

function convertZnzinBlendOp(znzin) {
  switch(znzin) {
    case ZZ_BLEND_OP.ADD:
      return THREE.AddEquation;
    case ZZ_BLEND_OP.SUBTRACT:
      return THREE.SubtractEquation;
    case ZZ_BLEND_OP.REV_SUBTRACT:
      return THREE.ReverseSubtractEquation;
  }

  if (renderer.supportsBlendMinMax()) {
    if (znzin === ZZ_BLEND_OP.MIN) {
      return THREE.MinEquation;
    } else if (znzin === ZZ_BLEND_OP.MAX) {
      return THREE.MaxEquation;
    }
  } else {
    return THREE.AddEquation;
  }
}
<|endoftext|>


<commit_before>/* Emoticons Plugin
 * This is a chat-plugin for Emoticons
 * You will need a line in parser to actually
 * parse this so that it works. (See command-parser.js)
 * Credits: panpawn, jd
 */

var fs = require('fs');
var path = require('path');
var serialize = require('node-serialize');
var emotes = {};

if (typeof Gold === 'undefined') global.Gold = {};

Gold.emoticons = {
	chatEmotes: {},
	processEmoticons: function(text) {
		var patterns = [],
		metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g,
		self = this;
		for (var i in this.chatEmotes) {
			if (this.chatEmotes.hasOwnProperty(i)) {
				patterns.push('(' + i.replace(metachars, "\\$&") + ')');
			}
		}
		return text.replace(new RegExp(patterns.join('|'), 'g'), function(match) {
			return typeof self.chatEmotes[match] != 'undefined' ?
				'' :
				match;
		});
	},
	processChatData: function(user, room, connection, message) {
		var match = false;
		for (var i in this.chatEmotes) {
			if (message.indexOf(i) >= 0) {
				match = true;
			}
		}
		switch (Users.ShadowBan.checkBanned(user) && match) {
			case true:
				origmsg = message;
				message = Tools.escapeHTML(message);
				message = this.processEmoticons(message);
				user.sendTo(room, '|html|' +
					user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
					user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
'
				);
				room.update();
				Users.ShadowBan.addMessage(user, "To " + room, origmsg);
				break;
			case false:
				if (!room.emoteStatus && room.type === 'chat' || !room.type === 'battle') {
					kitty = message = this.processEmoticons(message);
					var message = Tools.escapeHTML(kitty);
					return (message);
					return;
				} else if (room.emoteStatus || room.type === 'battle') {
					if (!match || message.charAt(0) === '!') return true;
					message = Tools.escapeHTML(message);
					message = this.processEmoticons(message);
					if (user.hiding) {
						room.addRaw(' <button class="astext" name="parseCommand" value="/user ' +
						user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
						room.update();
					}
					room.addRaw(user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
					user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
					room.update();
					return false;
				}
				break;
		}
	},
	processPMsParsing: function (message) {
		emoteRegex = [];
		for (var emote in this.chatEmotes) {
			emoteRegex.push(emote);
		}
		emoteRegex = new RegExp('(' + emoteRegex.join('|') + ')', 'g');
		self = this;
		if (emoteRegex.test(message)) {
			message = message.replace(emoteRegex, function (match) {
				return '';
			});
			return message;
		}
		return false;
	}
};

//commands

function loadEmotes() {
	try {
		emotes = serialize.unserialize(fs.readFileSync('config/emotes.json', 'utf8'));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}
setTimeout(function(){loadEmotes();},1000);

function saveEmotes() {
	try {
		fs.writeFileSync('config/emotes.json',serialize.serialize(emotes));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}

exports.commands = {
	emotes: 'ezemote',
	temotes: 'ezemote',
	temote: 'ezemote',
	emote: 'ezemote',
	ec: 'ezemote',
	ezemote: function (target, room, user) {
		if (!target) target = "help";
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		try {
			switch (toId(parts[0])) {
				case 'add':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!(parts[2] || parts[3])) return this.sendReply("Usage: /ezemote add, [emoticon], [link]");
					var emoteName = parts[1];
					if (~toId(emoteName).indexOf("fukya")) return this.sendReply("This emoticon cannot be added to the server.");
					if (Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emoticon: " + emoteName + " already exists.");
					var link = parts.splice(2, parts.length).join(',');
					var fileTypes = [".gif",".png",".jpg"];
					if (fileTypes.indexOf(link.substr(-4)) < 0) return this.sendReply("ERROR: the emoticon you are trying to add must be a gif, png, or jpg.");
					emotes[emoteName] = Gold.emoticons.chatEmotes[emoteName] = link;
					saveEmotes();
					this.sendReply("The emoticon " + emoteName + " has been added.");
					this.logModCommand(user.name + " added the emopticon " + emoteName);
					Rooms.rooms.staff.add(Tools.escapeHTML(user.name) + " added the emoticon " + emoteName);
					room.update();
					break;
				case 'rem':
				case 'remove':
				case 'del':
				case 'delete':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!parts[1]) return this.sendReplyBox("/ezemote remove, [emoticon]");
					var emoteName = parts[1];
					if (!Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emoticon: " + emoteName + " does not exist.");
					delete Gold.emoticons.chatEmotes[emoteName];
					delete emotes[emoteName];
					saveEmotes();
					this.sendReply("The emoticon " + emoteName + " was removed.");
					this.logModCommand("The emoticon " + emoteName + " was removed by " + user.name);
					Rooms.rooms.staff.add("The emoticon " + emoteName + " was removed by " + Tools.escapeHTML(user.name));
					room.update();
					break;
				case 'list':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var output = "There's a total of " + Object.size(emotes) + " emoticons added with this command:
";
					for (var e in emotes) {
						output += e + "
";
					}
					this.sendReplyBox(output);
					break;
				case 'view':
					if (!this.canBroadcast()) return;
					//if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var name = Object.keys(Gold.emoticons.chatEmotes);
					emoticons = [];
					var len = name.length;
					while (len--) {
						emoticons.push((Gold.emoticons.processEmoticons(name[(name.length - 1) - len]) + ' ' + name[(name.length - 1) - len]));
					}
					this.sendReplyBox("List of emoticons (" + Object.size(emotes) + "):

" + emoticons.join(' ').toString());
					break;
				case 'object':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					this.sendReplyBox("Gold.emoticons.chatEmotes = " + fs.readFileSync('config/emotes.json','utf8'));
					break;
				case 'status':
					if (!this.canBroadcast()) return;
					if (!parts[1]) {
						switch (room.emoteStatus) {
							case true:
								this.sendReply("Chat emoticons are currently enabled in this room.");
								break;
							case false:
								this.sendReply("Chat emoticons are currently disabled in this room.");
								break;
						}
					} else {
						switch (toId(parts[1])) {
							case 'on':
							case 'enable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.type === 'battle') return this.sendReply("Chat emoticons are already enabled in battle rooms by default and cannot be turned off.");
								if (room.emoteStatus) return this.sendReply("Chat emoticons are already enabled in this room.");
								room.emoteStatus = true;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								//room.add(Tools.escapeHTML(user.name) + ' has enabled chat emoticons in this room.');
								this.add("|raw|
Chat Emoticons have been enabled!
Everyone in this room may use chat emoticons.");
								room.update();
								this.privateModCommand("(" + user.name + " has enabled chat emoticons in this room)");
								break;
							case 'off':
							case 'disable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.type === 'battle') return this.sendReply("Chat emoticons are already enabled in battle rooms by default and cannot be turned off.");
								if (!room.emoteStatus) return this.sendReply("Chat emoticons are already disabled in this room.");
								room.emoteStatus = false;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								//room.add(Tools.escapeHTML(user.name) + " has disabled chat emoticons in this room.");
								this.add("|raw|
Chat Emoticons have been disabled!
No one in this room may use chat emoticons.");
								room.update();
								this.privateModCommand("(" + user.name + " has disabled chat emoticons in this room)");
								break;
							default:
								this.sendReply("Usage: /ezemote status, [on / off] - Enables or disables the current chat emoticon status.  Requires #, &, ~.");
						}
					}
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					this.sendReplyBox(
						"
" +
							"EZ-Emoticon Commands:
" +
							"(By: panpawn)
" +
							"/ezemote add, [emote], [link] - Adds a chat emoticon. Requires @, &, ~.
" +
							"/ezemote remove, [emote] - Removes a chat emoticon. Requires @, &, ~.
" +
							"/ezemote status, [on / off] - Enables or disables the status of chat emoticons in the respected room. Requires #, &, ~.
" +
							"/ezemote status - Views the current status of chat emoticons.
" +
							"/ezemote list - Shows the chat emoticons in a list form.
" +
							"/ezemote view - Shows all of the current chat emoticons with the respected image.
" +
							"/ezemote object - Shows the object of Gold.emoticons.chatEmotes. (Mostly for development usage)
" +
							"/ezemote help - Shows this help command.
" +
						"
"
					);
			}
		} catch (e) {
			try {
				Rooms.rooms.development.add(e.stack);
			} catch (e) {
				console.log("ERROR!  The EZ-Emote script has crashed!\n" + e.stack);
			}
		}
	}
};<commit_msg>New way of checking file extension in new emoticons<commit_after>/* Emoticons Plugin
 * This is a chat-plugin for Emoticons
 * You will need a line in parser to actually
 * parse this so that it works. (See command-parser.js)
 * Credits: panpawn, jd
 */

var fs = require('fs');
var path = require('path');
var serialize = require('node-serialize');
var emotes = {};

if (typeof Gold === 'undefined') global.Gold = {};

Gold.emoticons = {
	chatEmotes: {},
	processEmoticons: function(text) {
		var patterns = [],
		metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g,
		self = this;
		for (var i in this.chatEmotes) {
			if (this.chatEmotes.hasOwnProperty(i)) {
				patterns.push('(' + i.replace(metachars, "\\$&") + ')');
			}
		}
		return text.replace(new RegExp(patterns.join('|'), 'g'), function(match) {
			return typeof self.chatEmotes[match] != 'undefined' ?
				'' :
				match;
		});
	},
	processChatData: function(user, room, connection, message) {
		var match = false;
		for (var i in this.chatEmotes) {
			if (message.indexOf(i) >= 0) {
				match = true;
			}
		}
		switch (Users.ShadowBan.checkBanned(user) && match) {
			case true:
				origmsg = message;
				message = Tools.escapeHTML(message);
				message = this.processEmoticons(message);
				user.sendTo(room, '|html|' +
					user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
					user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
'
				);
				room.update();
				Users.ShadowBan.addMessage(user, "To " + room, origmsg);
				break;
			case false:
				if (!room.emoteStatus && room.type === 'chat' || !room.type === 'battle') {
					kitty = message = this.processEmoticons(message);
					var message = Tools.escapeHTML(kitty);
					return (message);
					return;
				} else if (room.emoteStatus || room.type === 'battle') {
					if (!match || message.charAt(0) === '!') return true;
					message = Tools.escapeHTML(message);
					message = this.processEmoticons(message);
					if (user.hiding) {
						room.addRaw(' <button class="astext" name="parseCommand" value="/user ' +
						user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
						room.update();
					}
					room.addRaw(user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
					user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
					room.update();
					return false;
				}
				break;
		}
	},
	processPMsParsing: function (message) {
		emoteRegex = [];
		for (var emote in this.chatEmotes) {
			emoteRegex.push(emote);
		}
		emoteRegex = new RegExp('(' + emoteRegex.join('|') + ')', 'g');
		self = this;
		if (emoteRegex.test(message)) {
			message = message.replace(emoteRegex, function (match) {
				return '';
			});
			return message;
		}
		return false;
	}
};

//commands

function loadEmotes() {
	try {
		emotes = serialize.unserialize(fs.readFileSync('config/emotes.json', 'utf8'));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}
setTimeout(function(){loadEmotes();},1000);

function saveEmotes() {
	try {
		fs.writeFileSync('config/emotes.json',serialize.serialize(emotes));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}

exports.commands = {
	emotes: 'ezemote',
	temotes: 'ezemote',
	temote: 'ezemote',
	emote: 'ezemote',
	ec: 'ezemote',
	ezemote: function (target, room, user) {
		if (!target) target = "help";
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		try {
			switch (toId(parts[0])) {
				case 'add':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!(parts[2] || parts[3])) return this.sendReply("Usage: /ezemote add, [emoticon], [link]");
					var emoteName = parts[1];
					if (~toId(emoteName).indexOf("fukya")) return this.sendReply("This emoticon cannot be added to the server.");
					if (Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emoticon: " + emoteName + " already exists.");
					var link = parts.splice(2, parts.length).join(',');
					var fileTypes = [".gif",".png",".jpg"];
					if (!~fileTypes.indexOf(link.substr(-4))) return this.sendReply("ERROR: the emoticon you are trying to add must be a gif, png, or jpg.");
					emotes[emoteName] = Gold.emoticons.chatEmotes[emoteName] = link;
					saveEmotes();
					this.sendReply("The emoticon " + emoteName + " has been added.");
					this.logModCommand(user.name + " added the emopticon " + emoteName);
					Rooms.rooms.staff.add(Tools.escapeHTML(user.name) + " added the emoticon " + emoteName);
					room.update();
					break;
				case 'rem':
				case 'remove':
				case 'del':
				case 'delete':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!parts[1]) return this.sendReplyBox("/ezemote remove, [emoticon]");
					var emoteName = parts[1];
					if (!Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emoticon: " + emoteName + " does not exist.");
					delete Gold.emoticons.chatEmotes[emoteName];
					delete emotes[emoteName];
					saveEmotes();
					this.sendReply("The emoticon " + emoteName + " was removed.");
					this.logModCommand("The emoticon " + emoteName + " was removed by " + user.name);
					Rooms.rooms.staff.add("The emoticon " + emoteName + " was removed by " + Tools.escapeHTML(user.name));
					room.update();
					break;
				case 'list':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var output = "There's a total of " + Object.size(emotes) + " emoticons added with this command:
";
					for (var e in emotes) {
						output += e + "
";
					}
					this.sendReplyBox(output);
					break;
				case 'view':
					if (!this.canBroadcast()) return;
					//if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var name = Object.keys(Gold.emoticons.chatEmotes);
					emoticons = [];
					var len = name.length;
					while (len--) {
						emoticons.push((Gold.emoticons.processEmoticons(name[(name.length - 1) - len]) + ' ' + name[(name.length - 1) - len]));
					}
					this.sendReplyBox("List of emoticons (" + Object.size(emotes) + "):

" + emoticons.join(' ').toString());
					break;
				case 'object':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					this.sendReplyBox("Gold.emoticons.chatEmotes = " + fs.readFileSync('config/emotes.json','utf8'));
					break;
				case 'status':
					if (!this.canBroadcast()) return;
					if (!parts[1]) {
						switch (room.emoteStatus) {
							case true:
								this.sendReply("Chat emoticons are currently enabled in this room.");
								break;
							case false:
								this.sendReply("Chat emoticons are currently disabled in this room.");
								break;
						}
					} else {
						switch (toId(parts[1])) {
							case 'on':
							case 'enable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.type === 'battle') return this.sendReply("Chat emoticons are already enabled in battle rooms by default and cannot be turned off.");
								if (room.emoteStatus) return this.sendReply("Chat emoticons are already enabled in this room.");
								room.emoteStatus = true;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								//room.add(Tools.escapeHTML(user.name) + ' has enabled chat emoticons in this room.');
								this.add("|raw|
Chat Emoticons have been enabled!
Everyone in this room may use chat emoticons.");
								room.update();
								this.privateModCommand("(" + user.name + " has enabled chat emoticons in this room)");
								break;
							case 'off':
							case 'disable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.type === 'battle') return this.sendReply("Chat emoticons are already enabled in battle rooms by default and cannot be turned off.");
								if (!room.emoteStatus) return this.sendReply("Chat emoticons are already disabled in this room.");
								room.emoteStatus = false;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								//room.add(Tools.escapeHTML(user.name) + " has disabled chat emoticons in this room.");
								this.add("|raw|
Chat Emoticons have been disabled!
No one in this room may use chat emoticons.");
								room.update();
								this.privateModCommand("(" + user.name + " has disabled chat emoticons in this room)");
								break;
							default:
								this.sendReply("Usage: /ezemote status, [on / off] - Enables or disables the current chat emoticon status.  Requires #, &, ~.");
						}
					}
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					this.sendReplyBox(
						"
" +
							"EZ-Emoticon Commands:
" +
							"(By: panpawn)
" +
							"/ezemote add, [emote], [link] - Adds a chat emoticon. Requires @, &, ~.
" +
							"/ezemote remove, [emote] - Removes a chat emoticon. Requires @, &, ~.
" +
							"/ezemote status, [on / off] - Enables or disables the status of chat emoticons in the respected room. Requires #, &, ~.
" +
							"/ezemote status - Views the current status of chat emoticons.
" +
							"/ezemote list - Shows the chat emoticons in a list form.
" +
							"/ezemote view - Shows all of the current chat emoticons with the respected image.
" +
							"/ezemote object - Shows the object of Gold.emoticons.chatEmotes. (Mostly for development usage)
" +
							"/ezemote help - Shows this help command.
" +
						"
"
					);
			}
		} catch (e) {
			try {
				Rooms.rooms.development.add(e.stack);
			} catch (e) {
				console.log("ERROR!  The EZ-Emote script has crashed!\n" + e.stack);
			}
		}
	}
};<|endoftext|>


<commit_before>/* global DOM, CloudCmd */

'use strict';

const exec = require('execon');
const itype = require('itype/legacy');
const currify = require('currify/legacy');
const clipboard = require('@cloudcmd/clipboard');

const getRange = require('./get-range');
const getIndex = currify(require('./get-index'));
const uploadFiles = require('../dom/upload-files');

const {
    FS,
    apiURL
} = require('../../common/cloudfunc');

const NBSP_REG = RegExp(String.fromCharCode(160), 'g');
const SPACE = ' ';

module.exports.init = () => {
    contextMenu();
    dragndrop();
    unload();
    pop();
    resize();
    config();
    header();
};

CloudCmd.Listeners = module.exports;

const unselect = (event) => {
    const isMac = /Mac/.test(window.navigator.platform);
    const {
        shiftKey,
        metaKey,
        ctrlKey,
    } = event;

    if (shiftKey || isMac && metaKey || ctrlKey)
        return;

    DOM.unselectFiles();
};

const execAll = currify((funcs, event) => {
    funcs.forEach((fn) => {
        fn(event);
    });
});

const Info = DOM.CurrentInfo;
const Events = DOM.Events;
const EventsFiles = {
    mousedown: exec.with(execIfNotUL, setCurrentFileByEvent),
    click: execAll([
        onClick,
        unselect,
    ]),
    dragstart: exec.with(execIfNotUL, onDragStart),
    dblclick: exec.with(execIfNotUL, onDblClick),
    touchstart: exec.with(execIfNotUL, onTouch),
};

let EXT;

function header() {
    const fm = DOM.getFM();
    const isDataset = (el) => el.dataset;
    const isPanel = (el) => {
        return /^js-(left|right)$/.test(el.dataset.name);
    };

    Events.addClick(fm, (event) => {
        const el = event.target;
        const parent = el.parentElement;

        if (parent.dataset.name !== 'js-fm-header')
            return;

        const name = (el.dataset.name || '')
            .replace('js-', '');

        if (!/^(name|size|date)$/.test(name))
            return;

        const panel = getPath(el)
            .filter(isDataset)
            .filter(isPanel)
            .pop();

        CloudCmd.sortPanel(name, panel);
    });
}

function getPath(el, path = []) {
    if (!el)
        return path;

    return getPath(el.parentElement, path.concat(el));
}

function config() {
    DOM.Files.get('config', (e, config) => {
        const type = config && config.packer;
        EXT = DOM.getPackerExt(type);
    });
}

module.exports.initKeysPanel = () => {
    const keysElement = DOM.getById('js-keyspanel');

    if (!keysElement)
        return;

    Events.addClick(keysElement, ({target}) => {
        const id = target.id;
        const operation = (name) => {
            const Operation = CloudCmd.Operation;
            const fn = Operation.show.bind(null, name);

            return fn;
        };

        const clickFuncs = {
            'f1'        : CloudCmd.Help.show,
            'f2'        : DOM.renameCurrent,
            'f3'        : CloudCmd.View.show,
            'f4'        : CloudCmd.EditFile.show,
            'f5'        : operation('copy'),
            'f6'        : operation('move'),
            'f7'        : DOM.promptNewDir,
            'f8'        : operation('delete'),
            'f9'        : CloudCmd.Menu.show,
            'f10'       : CloudCmd.Config.show,
            '~'         : CloudCmd.Konsole.show,
            'shift~'    : CloudCmd.Terminal.show,
            'contact'   : CloudCmd.Contact.show,
        };

        exec(clickFuncs[id]);
    });
};

const getPanel = (side) => {
    if (!itype.string(side))
        return side;

    return DOM.getByDataName('js-' + side);
};

module.exports.setOnPanel = (side) => {
    const panel = getPanel(side);

    const filesElement = DOM.getByDataName('js-files', panel);
    const pathElement = DOM.getByDataName('js-path', panel);

    /* ставим загрузку гифа на клик*/
    Events.addClick(pathElement, getPathListener(panel));
    Events.add(filesElement, EventsFiles);
};

function getPathListener(panel) {
    return onPathElementClick.bind(null, panel);
}

function isNoCurrent(panel) {
    const infoPanel = Info.panel;
    const namePanel = panel.getAttribute('data-name');
    const nameInfoPanel = infoPanel.getAttribute('data-name');

    return namePanel !== nameInfoPanel;
}

function decodePath(path){
    const url = CloudCmd.HOST;
    const prefix = CloudCmd.PREFIX;
    const prefixReg = RegExp('^' + prefix + FS);

    return decodeURI(path)
        .replace(url, '')
        .replace(prefixReg, '')
    // browser doesn't replace % -> %25% do it for him
        .replace('%%', '%25%')
        .replace(NBSP_REG, SPACE) || '/';
}

function onPathElementClick(panel, event) {
    event.preventDefault();

    const element = event.target;
    const attr = element.getAttribute('data-name');
    const noCurrent = isNoCurrent(panel);

    if (attr === 'js-copy-path')
        return copyPath(element);

    if (attr === 'js-refresh')
        return CloudCmd.refresh({
            panel,
            noCurrent
        });

    if (attr !== 'js-path-link')
        return;

    const {href} = element;
    const path = decodePath(href);

    CloudCmd.loadDir({
        path,
        isRefresh: false,
        panel: noCurrent ? panel : Info.panel
    });
}

function copyPath(el) {
    clipboard.writeText(el.parentElement.title)
        .then(CloudCmd.log)
        .catch(CloudCmd.log);
}

function execIfNotUL(callback, event) {
    const {target} = event;
    const {tagName} = target;

    if (tagName !== 'UL')
        callback(event);
}

function onClick(event) {
    const ctrl = event.ctrlKey;

    if (!ctrl)
        event.preventDefault();

    changePanel(event.target);
}

function toggleSelect(key, files) {
    const isMac = /Mac/.test(window.navigator.platform);

    if (!key)
        throw Error('key should not be undefined!');

    const [file] = files;

    if (isMac && key.meta || key.ctrl)
        return DOM.toggleSelectedFile(file);

    if (key.shift)
        return files.forEach(DOM.selectFile);
}

function changePanel(element) {
    const {panel} = Info;
    const files = DOM.getByDataName('js-files', panel);
    const ul = getULElement(element);

    if (ul !== files)
        DOM.changePanel();
}

function onDblClick(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);
    const path = DOM.getCurrentPath(current);

    if (isDir) {
        CloudCmd.loadDir({
            path: path === '/' ? '/' : path + '/'
        });

        event.preventDefault();
    }
}

function onTouch(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);

    if (!isDir)
        return;

    const isCurrent = DOM.isCurrentFile(current);

    if (!isCurrent)
        return;

    CloudCmd.loadDir({
        path: DOM.getCurrentPath(current)
    });
}

/*
  * download file from browser to desktop
  * in Chrome (HTML5)
  */
function onDragStart(event) {
    const element = getLIElement(event.target);
    const isDir = Info.isDir;
    let link = DOM.getCurrentLink(element);
    let name = DOM.getCurrentName(element);

    /* if it's directory - adding json extension */
    if (isDir) {
        name += EXT;
        link = document.createElement('a');
        link.textContent = name;
        link.href = apiURL + '/pack' + Info.path + EXT;
    }

    event.dataTransfer.setData('DownloadURL',
        'application/octet-stream'  + ':' +
        name                        + ':' +
        link);
}

function getLIElement(element) {
    if (!element)
        return element;

    while (element.tagName !== 'LI')
        element = element.parentElement;

    return element;
}

function getULElement(element) {
    while (element.tagName !== 'UL')
        element = element.parentElement;

    return element;
}

function setCurrentFileByEvent(event) {
    const BUTTON_LEFT = 0;

    const key = {
        alt: event.altKey,
        ctrl: event.ctrlKey,
        meta: event.metaKey,
        shift: event.shiftKey
    };

    const element = getLIElement(event.target);

    const fromName = Info.name;
    DOM.setCurrentFile(element);
    const toName = Info.name;

    let files = [];

    if (key.shift)
        files = getFilesRange(fromName, toName);
    else
        files.push(Info.element);

    if (event.button === BUTTON_LEFT)
        toggleSelect(key, files);
}

function getFilesRange(from, to) {
    const files = DOM.getAllFiles();
    const names = DOM.getFilenames(files);
    const getNameIndex = getIndex(names);

    const indexFrom = getNameIndex(from);
    const indexTo = getNameIndex(to);

    return getRange(indexFrom, indexTo, files);
}

function contextMenu() {
    const fm = DOM.getFM();

    Events.addOnce('contextmenu', fm, (event) => {
        CloudCmd.Menu.show({
            x: event.clientX,
            y: event.clientY
        });
    });

    Events.addContextMenu(fm, (event) => {
        CloudCmd.Menu.ENABLED || event.preventDefault();
    });
}

function dragndrop() {
    const panels = DOM.getByClassAll('panel');
    const select = () => {
        [...panels].forEach((panel) => {
            panel.classList.add('selected-panel');
        });
    };

    const unselect = () => {
        [...panels].forEach((panel) => {
            panel.classList.remove('selected-panel');
        });
    };

    const onDrop = (event) => {
        const files = event.dataTransfer.files;
        const items = event.dataTransfer.items;
        const {length: filesCount} = files;

        event.preventDefault();

        if (filesCount && (!items || !items.length || !items[0].webkitGetAsEntry))
            return uploadFiles(files);

        const isFile = (item) => item.kind === 'file';
        const dirFiles = [...items].filter(isFile);

        if (dirFiles.length)
            return DOM.uploadDirectory(dirFiles);

        const {Operation} = CloudCmd;
        const operation = event.shiftKey ? 'move' : 'copy';

        return Operation.show(operation);
    };

    /**
     * In Mac OS Chrome dropEffect = 'none'
     * so drop do not firing up when try
     * to upload file from download bar
     */
    const onDragOver = (event) => {
        const dataTransfer = event.dataTransfer;
        const effectAllowed = dataTransfer.effectAllowed;

        if (/move|linkMove/.test(effectAllowed))
            dataTransfer.dropEffect = 'move';
        else
            dataTransfer.dropEffect = 'copy';

        event.preventDefault();
    };

    Events.add('dragenter', select);
    Events.add(['dragleave', 'drop'], unselect);

    [...panels].forEach((panel) => {
        Events.add('dragover', panel, onDragOver)
            .add('drop', panel, onDrop);
    });
}

function unload() {
    DOM.Events.add(['unload', 'beforeunload'], (event) => {
        const Key = CloudCmd.Key;
        const isBind = Key && Key.isBind();

        if (isBind)
            return;

        event.preventDefault();
        return 'Please make sure that you saved all work.';
    });
}

function pop() {
    Events.add('popstate', ({state}) => {
        const path = (state || '').replace(FS, '');

        if (!path)
            return CloudCmd.route(location.hash);

        const history = false;
        CloudCmd.loadDir({
            path,
            history,
        });
    });
}

function resize() {
    Events.add('resize', () => {
        const is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;

        if (!is)
            return;

        const {panel} = Info;
        const isEmptyRoot = !panel;

        if (isEmptyRoot)
            return;

        const name = panel.getAttribute('data-name');
        const isLeft = name === 'js-left';

        if (isLeft)
            return;

        DOM.changePanel();
    });
}

<commit_msg>chore(listeners) add ","<commit_after>/* global DOM, CloudCmd */

'use strict';

const exec = require('execon');
const itype = require('itype/legacy');
const currify = require('currify/legacy');
const clipboard = require('@cloudcmd/clipboard');

const getRange = require('./get-range');
const getIndex = currify(require('./get-index'));
const uploadFiles = require('../dom/upload-files');

const {
    FS,
    apiURL,
} = require('../../common/cloudfunc');

const NBSP_REG = RegExp(String.fromCharCode(160), 'g');
const SPACE = ' ';

module.exports.init = () => {
    contextMenu();
    dragndrop();
    unload();
    pop();
    resize();
    config();
    header();
};

CloudCmd.Listeners = module.exports;

const unselect = (event) => {
    const isMac = /Mac/.test(window.navigator.platform);
    const {
        shiftKey,
        metaKey,
        ctrlKey,
    } = event;

    if (shiftKey || isMac && metaKey || ctrlKey)
        return;

    DOM.unselectFiles();
};

const execAll = currify((funcs, event) => {
    funcs.forEach((fn) => {
        fn(event);
    });
});

const Info = DOM.CurrentInfo;
const Events = DOM.Events;
const EventsFiles = {
    mousedown: exec.with(execIfNotUL, setCurrentFileByEvent),
    click: execAll([
        onClick,
        unselect,
    ]),
    dragstart: exec.with(execIfNotUL, onDragStart),
    dblclick: exec.with(execIfNotUL, onDblClick),
    touchstart: exec.with(execIfNotUL, onTouch),
};

let EXT;

function header() {
    const fm = DOM.getFM();
    const isDataset = (el) => el.dataset;
    const isPanel = (el) => {
        return /^js-(left|right)$/.test(el.dataset.name);
    };

    Events.addClick(fm, (event) => {
        const el = event.target;
        const parent = el.parentElement;

        if (parent.dataset.name !== 'js-fm-header')
            return;

        const name = (el.dataset.name || '')
            .replace('js-', '');

        if (!/^(name|size|date)$/.test(name))
            return;

        const panel = getPath(el)
            .filter(isDataset)
            .filter(isPanel)
            .pop();

        CloudCmd.sortPanel(name, panel);
    });
}

function getPath(el, path = []) {
    if (!el)
        return path;

    return getPath(el.parentElement, path.concat(el));
}

function config() {
    DOM.Files.get('config', (e, config) => {
        const type = config && config.packer;
        EXT = DOM.getPackerExt(type);
    });
}

module.exports.initKeysPanel = () => {
    const keysElement = DOM.getById('js-keyspanel');

    if (!keysElement)
        return;

    Events.addClick(keysElement, ({target}) => {
        const id = target.id;
        const operation = (name) => {
            const Operation = CloudCmd.Operation;
            const fn = Operation.show.bind(null, name);

            return fn;
        };

        const clickFuncs = {
            'f1'        : CloudCmd.Help.show,
            'f2'        : DOM.renameCurrent,
            'f3'        : CloudCmd.View.show,
            'f4'        : CloudCmd.EditFile.show,
            'f5'        : operation('copy'),
            'f6'        : operation('move'),
            'f7'        : DOM.promptNewDir,
            'f8'        : operation('delete'),
            'f9'        : CloudCmd.Menu.show,
            'f10'       : CloudCmd.Config.show,
            '~'         : CloudCmd.Konsole.show,
            'shift~'    : CloudCmd.Terminal.show,
            'contact'   : CloudCmd.Contact.show,
        };

        exec(clickFuncs[id]);
    });
};

const getPanel = (side) => {
    if (!itype.string(side))
        return side;

    return DOM.getByDataName('js-' + side);
};

module.exports.setOnPanel = (side) => {
    const panel = getPanel(side);

    const filesElement = DOM.getByDataName('js-files', panel);
    const pathElement = DOM.getByDataName('js-path', panel);

    /* ставим загрузку гифа на клик*/
    Events.addClick(pathElement, getPathListener(panel));
    Events.add(filesElement, EventsFiles);
};

function getPathListener(panel) {
    return onPathElementClick.bind(null, panel);
}

function isNoCurrent(panel) {
    const infoPanel = Info.panel;
    const namePanel = panel.getAttribute('data-name');
    const nameInfoPanel = infoPanel.getAttribute('data-name');

    return namePanel !== nameInfoPanel;
}

function decodePath(path){
    const url = CloudCmd.HOST;
    const prefix = CloudCmd.PREFIX;
    const prefixReg = RegExp('^' + prefix + FS);

    return decodeURI(path)
        .replace(url, '')
        .replace(prefixReg, '')
    // browser doesn't replace % -> %25% do it for him
        .replace('%%', '%25%')
        .replace(NBSP_REG, SPACE) || '/';
}

function onPathElementClick(panel, event) {
    event.preventDefault();

    const element = event.target;
    const attr = element.getAttribute('data-name');
    const noCurrent = isNoCurrent(panel);

    if (attr === 'js-copy-path')
        return copyPath(element);

    if (attr === 'js-refresh')
        return CloudCmd.refresh({
            panel,
            noCurrent
        });

    if (attr !== 'js-path-link')
        return;

    const {href} = element;
    const path = decodePath(href);

    CloudCmd.loadDir({
        path,
        isRefresh: false,
        panel: noCurrent ? panel : Info.panel
    });
}

function copyPath(el) {
    clipboard.writeText(el.parentElement.title)
        .then(CloudCmd.log)
        .catch(CloudCmd.log);
}

function execIfNotUL(callback, event) {
    const {target} = event;
    const {tagName} = target;

    if (tagName !== 'UL')
        callback(event);
}

function onClick(event) {
    const ctrl = event.ctrlKey;

    if (!ctrl)
        event.preventDefault();

    changePanel(event.target);
}

function toggleSelect(key, files) {
    const isMac = /Mac/.test(window.navigator.platform);

    if (!key)
        throw Error('key should not be undefined!');

    const [file] = files;

    if (isMac && key.meta || key.ctrl)
        return DOM.toggleSelectedFile(file);

    if (key.shift)
        return files.forEach(DOM.selectFile);
}

function changePanel(element) {
    const {panel} = Info;
    const files = DOM.getByDataName('js-files', panel);
    const ul = getULElement(element);

    if (ul !== files)
        DOM.changePanel();
}

function onDblClick(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);
    const path = DOM.getCurrentPath(current);

    if (isDir) {
        CloudCmd.loadDir({
            path: path === '/' ? '/' : path + '/'
        });

        event.preventDefault();
    }
}

function onTouch(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);

    if (!isDir)
        return;

    const isCurrent = DOM.isCurrentFile(current);

    if (!isCurrent)
        return;

    CloudCmd.loadDir({
        path: DOM.getCurrentPath(current)
    });
}

/*
  * download file from browser to desktop
  * in Chrome (HTML5)
  */
function onDragStart(event) {
    const element = getLIElement(event.target);
    const isDir = Info.isDir;
    let link = DOM.getCurrentLink(element);
    let name = DOM.getCurrentName(element);

    /* if it's directory - adding json extension */
    if (isDir) {
        name += EXT;
        link = document.createElement('a');
        link.textContent = name;
        link.href = apiURL + '/pack' + Info.path + EXT;
    }

    event.dataTransfer.setData('DownloadURL',
        'application/octet-stream'  + ':' +
        name                        + ':' +
        link);
}

function getLIElement(element) {
    if (!element)
        return element;

    while (element.tagName !== 'LI')
        element = element.parentElement;

    return element;
}

function getULElement(element) {
    while (element.tagName !== 'UL')
        element = element.parentElement;

    return element;
}

function setCurrentFileByEvent(event) {
    const BUTTON_LEFT = 0;

    const key = {
        alt: event.altKey,
        ctrl: event.ctrlKey,
        meta: event.metaKey,
        shift: event.shiftKey
    };

    const element = getLIElement(event.target);

    const fromName = Info.name;
    DOM.setCurrentFile(element);
    const toName = Info.name;

    let files = [];

    if (key.shift)
        files = getFilesRange(fromName, toName);
    else
        files.push(Info.element);

    if (event.button === BUTTON_LEFT)
        toggleSelect(key, files);
}

function getFilesRange(from, to) {
    const files = DOM.getAllFiles();
    const names = DOM.getFilenames(files);
    const getNameIndex = getIndex(names);

    const indexFrom = getNameIndex(from);
    const indexTo = getNameIndex(to);

    return getRange(indexFrom, indexTo, files);
}

function contextMenu() {
    const fm = DOM.getFM();

    Events.addOnce('contextmenu', fm, (event) => {
        CloudCmd.Menu.show({
            x: event.clientX,
            y: event.clientY
        });
    });

    Events.addContextMenu(fm, (event) => {
        CloudCmd.Menu.ENABLED || event.preventDefault();
    });
}

function dragndrop() {
    const panels = DOM.getByClassAll('panel');
    const select = () => {
        [...panels].forEach((panel) => {
            panel.classList.add('selected-panel');
        });
    };

    const unselect = () => {
        [...panels].forEach((panel) => {
            panel.classList.remove('selected-panel');
        });
    };

    const onDrop = (event) => {
        const files = event.dataTransfer.files;
        const items = event.dataTransfer.items;
        const {length: filesCount} = files;

        event.preventDefault();

        if (filesCount && (!items || !items.length || !items[0].webkitGetAsEntry))
            return uploadFiles(files);

        const isFile = (item) => item.kind === 'file';
        const dirFiles = [...items].filter(isFile);

        if (dirFiles.length)
            return DOM.uploadDirectory(dirFiles);

        const {Operation} = CloudCmd;
        const operation = event.shiftKey ? 'move' : 'copy';

        return Operation.show(operation);
    };

    /**
     * In Mac OS Chrome dropEffect = 'none'
     * so drop do not firing up when try
     * to upload file from download bar
     */
    const onDragOver = (event) => {
        const dataTransfer = event.dataTransfer;
        const effectAllowed = dataTransfer.effectAllowed;

        if (/move|linkMove/.test(effectAllowed))
            dataTransfer.dropEffect = 'move';
        else
            dataTransfer.dropEffect = 'copy';

        event.preventDefault();
    };

    Events.add('dragenter', select);
    Events.add(['dragleave', 'drop'], unselect);

    [...panels].forEach((panel) => {
        Events.add('dragover', panel, onDragOver)
            .add('drop', panel, onDrop);
    });
}

function unload() {
    DOM.Events.add(['unload', 'beforeunload'], (event) => {
        const Key = CloudCmd.Key;
        const isBind = Key && Key.isBind();

        if (isBind)
            return;

        event.preventDefault();
        return 'Please make sure that you saved all work.';
    });
}

function pop() {
    Events.add('popstate', ({state}) => {
        const path = (state || '').replace(FS, '');

        if (!path)
            return CloudCmd.route(location.hash);

        const history = false;
        CloudCmd.loadDir({
            path,
            history,
        });
    });
}

function resize() {
    Events.add('resize', () => {
        const is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;

        if (!is)
            return;

        const {panel} = Info;
        const isEmptyRoot = !panel;

        if (isEmptyRoot)
            return;

        const name = panel.getAttribute('data-name');
        const isLeft = name === 'js-left';

        if (isLeft)
            return;

        DOM.changePanel();
    });
}

<|endoftext|>