<commit_before>
/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/
if (!ORYX.Plugins)
    ORYX.Plugins = new Object();

ORYX.Plugins.File = Clazz.extend({

    facade: undefined,

	processURI: undefined,

    construct: function(facade){
        this.facade = facade;

        this.facade.offer({
            'name': "Save",
            'functionality': this.save.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/disk.png",
            'description': "Save",
            'index': 1,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.print.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/printer.png",
            'description': "Print current modell",
            'index': 2,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.exportPDF.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/page_white_acrobat.png",
            'description': "Export as PDF",
            'index': 3,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Info",
            'functionality': this.info.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/information.png",
            'description': "Info",
            'index': 4,
            'minShape': 0,
            'maxShape': 0
        });

		window.onbeforeunload = this.onUnLoad.bind(this)

		this.serializedDOM = DataManager.__persistDOM(this.facade);

    },

	onUnLoad: function(){

		if( this.serializedDOM != DataManager.__persistDOM(this.facade) ){

			return "There are unsaved data, please save before you leave, otherwise your changes get lost!";

		}

	},

    saveSynchronously: function(){

        //var resource = location.search.split("resource=");

		//Commented out because with Oles new server, this if check is true,
		// so it won't work.
		/*        if (resource.length == 1) {
	            // SAVE the DOM with ARESS-SERVER
	            DataManager.__syncglobal(this.facade);

        } else { */
            // SAVE the DOM with ORYX-SERVER
            //resource = resource[1].split("&")[0];

		// Get the serialized dom
		this.serializedDOM = DataManager.__persistDOM(this.facade);

		var reqURI = this.processURI ? this.processURI : location.href;

		// Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

        var svgDOM = DataManager.serialize(svgClone);

		// Check if this is the NEW URL
		if( reqURI.include( 'editor' ) ){

			// Define Default values
			var defaultData = {title:'New Process', description:'', type:'bpmn', url: reqURI}

			// Create a Template
			var dialog = new Ext.XTemplate(
						// TODO find some nice words here -- copy from above ;)
						'<form class="oryx_repository_edit_model" action="#" id="edit_model" onsubmit="return false;">',

							'<fieldset><legend>General Properties</legend>',
								'
These properties describe the model.
',

								'
Title<input type="text" class="text" name="title" value="{title}" id="edit_model_title" onfocus="this.className = \'text activated\'" onblur="this.className = \'text\'"/>
',
								'
Description<textarea rows="5" name="description" id="edit_model_summary" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{description}</textarea>
',
								'
Type<input type="text" name="type" class="text disabled" value="{type}" disabled="disabled" id="edit_model_type" />
',

							'</fieldset>',

						'</form>')

			// Create the callback for the template
			callback = function(form){

				var title 		= form.elements["title"].value.strip();
				title 			= title.length == 0 ? defaultData.title : title;

				var description = form.elements["description"].value.strip();
				description 	= description.length == 0 ? defaultData.description : description;

				var type 		= form.elements["type"].value.strip();
				type 			= type.length == 0 ? defaultData.type : type;

				win.hide();

				// Send the request out
				this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM, title: title, description: description, type: type } );

			}.bind(this);

			// Create a new window
			win = new Ext.Window({
				id:'Propertie_Window',
		        width:550,
		        height:244,
		        title:"Save as...",
		        modal:true,
		        html: dialog.apply( defaultData ),
				buttons:[{
					text: 'Save',
					handler: function(){
						callback( $('edit_model') )
					}
				},{
                	text: 'Close',
                	handler: function(){
                    	win.hide();
                	}
				}]
		    });

			win.show();

		} else {

			// Send the request out
			this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM } );

		}
    },

	sendSaveRequest: function(url, params){

		// Send the request to the server.
		new Ajax.Request(url, {
                method: 'POST',
                asynchronous: false,
                parameters: params,
			onSuccess: (function(transport) {
				var loc = transport.getResponseHeader("location");
				if (!this.processURI && loc) {
					this.processURI = loc;
				}

				//show saved status
				this.facade.raiseEvent({
						type:'loading.status',
						text:'Saved!'
					});
			}).bind(this),
			onFailure: function(transport) {
				// raise loading disable event.
                this.facade.raiseEvent({
                    type: 'loading.disable'
                });

			alert("Saving failed.");

			ORYX.log.warn("Saving failed: " + transport.responseText);
		}});

	},

    /**
     * Saves the current process to the server.
     * @param {Object} saveSynchronously when true, this call is synchronous and
     * waits for server reply. In this case, this call doesn't raise events for
     * loading plugin. If false, this will raise loading events and save
     * asynchronously. Use latter if UI responsibility is wanted, Former when
     * you need to be certain that saving is finished.
     */
    save: function(event, synchronously){

        // if not to saved synchronously
        if (synchronously == undefined) {

            // raise loading enable event
            this.facade.raiseEvent({
                type: 'loading.enable',
				text: 'Saving'
            });

            // asynchronously ...
            window.setTimeout((function(){

                // ... save synchronously
                this.saveSynchronously();

            }).bind(this), 10);

        }
        else

            // just save, synchronously.
            this.saveSynchronously();

        return true;
    },

    info: function(){

        //TODO Make this fit in 80 columns.
        var info = "Copyright (c) 2006\n" +
        "Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner\n\n" +
        "Permission is hereby granted, free of charge, to any person " +
        "obtaining a copy of this software and associated documentation files " +
        "(the Software), to deal in the Software without restriction, " +
        "including without limitation the rights to use, copy, modify, merge, " +
        "publish, distribute, sublicense, and/or sell copies of the Software, " +
        "and to permit persons to whom the Software is furnished to do so, " +
        "subject to the following conditions:\n\n" +
        "The above copyright notice and this permission notice shall be " +
        "included in all copies or substantial portions of the Software.\n\n" +
        "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " +
        "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " +
        "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " +
        "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS " +
        "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN " +
        "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " +
        "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE " +
        "SOFTWARE.";

        alert(info);
        return false;
    },

    exportPDF: function(){

        var resource = location.href;

        // Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

        var svgDOM = DataManager.serialize(svgClone);

        // Send the svg to the server.
        //TODO make this better by using content negotiation instead of format parameter.
        //TODO make this better by generating svg on the server, too.
        new Ajax.Request(ORYX.CONFIG.PDF_EXPORT_URL, {
            method: 'POST',
            parameters: {
                resource: resource,
                data: svgDOM,
                format: "pdf"
            },
            onSuccess: function(request){

                // Because the pdf may be opened in the same window as the
                // process, yet the process may not have been saved, we're
                // opening every other representation in a new window.
                // location.href = request.responseText
                window.open(request.responseText);
            }
        });
    },

    print: function(){

        // Set all options for the new window
        var option = $H({
            width: 300,
            height: 400,
            toolbar: "no",
            status: "no",
            menubar: "yes",
            dependent: "yes",
            resizable: "yes",
            scrollbars: "yes"
        });

        // Create the new window with all the settings
        var newWindow = window.open("", "PrintWindow", option.invoke('join', '=').join(','));

        // Add a style tag to the head and hide all controls
        var head = newWindow.document.getElementsByTagName('head')[0];
        var style = document.createElement("style");
        style.innerHTML = " body {padding:0px; margin:0px} .svgcontainer { display:none; }";
        head.appendChild(style);

        // Clone the svg-node and append this to the new body
        newWindow.document.getElementsByTagName('body')[0].appendChild(this.facade.getCanvas().getRootNode().cloneNode(true));
        var svg = newWindow.document.getElementsByTagName('body')[0].getElementsByTagName('svg')[0];

        // Set the width and height
        svg.setAttributeNS(null, 'width', 1100);
        svg.setAttributeNS(null, 'height', 1400);

        // Set the correct size and rotation
        svg.lastChild.setAttributeNS(null, 'transform', 'scale(0.47, 0.47) rotate(270, 1510, 1470)');

        var markers = ['marker-start', 'marker-mid', 'marker-end']
        var path = $A(newWindow.document.getElementsByTagName('path'));
        path.each(function(pathNode){
            markers.each(function(marker){
                // Get the marker value
                var url = pathNode.getAttributeNS(null, marker);
                if (!url) {
                    return
                };

                // Replace the URL and set them new
                url = "url(about:blank#" + url.slice(5);
                pathNode.setAttributeNS(null, marker, url);
            });
        });

        // Get the print dialog
        newWindow.print();

        return true;
    }
});
<commit_msg>some minor things<commit_after>
/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/
if (!ORYX.Plugins)
    ORYX.Plugins = new Object();

ORYX.Plugins.File = Clazz.extend({

    facade: undefined,

	processURI: undefined,

    construct: function(facade){
        this.facade = facade;

        this.facade.offer({
            'name': "Save",
            'functionality': this.save.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/disk.png",
            'description': "Save",
            'index': 1,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.print.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/printer.png",
            'description': "Print current modell",
            'index': 2,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Print",
            'functionality': this.exportPDF.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/page_white_acrobat.png",
            'description': "Export as PDF",
            'index': 3,
            'minShape': 0,
            'maxShape': 0
        });

        this.facade.offer({
            'name': "Info",
            'functionality': this.info.bind(this),
            'group': "File",
            'icon': ORYX.PATH + "images/information.png",
            'description': "Info",
            'index': 4,
            'minShape': 0,
            'maxShape': 0
        });

		window.onbeforeunload = this.onUnLoad.bind(this)

		this.serializedDOM = DataManager.__persistDOM(this.facade);

    },

	onUnLoad: function(){

		if( this.serializedDOM != DataManager.__persistDOM(this.facade) ){

			return "There are unsaved data, please save before you leave, otherwise your changes get lost!";

		}

	},

    saveSynchronously: function(){

        //var resource = location.search.split("resource=");

		//Commented out because with Oles new server, this if check is true,
		// so it won't work.
		/*        if (resource.length == 1) {
	            // SAVE the DOM with ARESS-SERVER
	            DataManager.__syncglobal(this.facade);

        } else { */
            // SAVE the DOM with ORYX-SERVER
            //resource = resource[1].split("&")[0];

		// Get the serialized dom
		this.serializedDOM = DataManager.__persistDOM(this.facade);

		var reqURI = this.processURI ? this.processURI : location.href;

		// Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

        var svgDOM = DataManager.serialize(svgClone);

		// Check if this is the NEW URL
		if( reqURI.include( ORYX.CONFIG.ORYX_NEW_URL ) ){

			// Define Default values
			var defaultData = {title:'New Process', description:'', type:'bpmn', url: reqURI}

			// Create a Template
			var dialog = new Ext.XTemplate(
						// TODO find some nice words here -- copy from above ;)
						'<form class="oryx_repository_edit_model" action="#" id="edit_model" onsubmit="return false;">',

							'<fieldset><legend>General Properties</legend>',
								'
These properties describe the model.
',

								'
Title<input type="text" class="text" name="title" value="{title}" id="edit_model_title" onfocus="this.className = \'text activated\'" onblur="this.className = \'text\'"/>
',
								'
Description<textarea rows="5" name="description" id="edit_model_summary" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{description}</textarea>
',
								'
Type<input type="text" name="type" class="text disabled" value="{type}" disabled="disabled" id="edit_model_type" />
',

							'</fieldset>',

						'</form>')

			// Create the callback for the template
			callback = function(form){

				var title 		= form.elements["title"].value.strip();
				title 			= title.length == 0 ? defaultData.title : title;

				var description = form.elements["description"].value.strip();
				description 	= description.length == 0 ? defaultData.description : description;

				var type 		= form.elements["type"].value.strip();
				type 			= type.length == 0 ? defaultData.type : type;

				win.hide();

				// Send the request out
				this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM, title: title, description: description, type: type } );

			}.bind(this);

			// Create a new window
			win = new Ext.Window({
				id:'Propertie_Window',
		        width:550,
		        height:244,
		        title:"Save as...",
		        modal:true,
		        html: dialog.apply( defaultData ),
				buttons:[{
					text: 'Save',
					handler: function(){
						callback( $('edit_model') )
					}
				},{
                	text: 'Close',
                	handler: function(){
                    	win.hide();
                	}
				}]
		    });

			win.show();

		} else {

			// Send the request out
			this.sendSaveRequest( reqURI, { data: this.serializedDOM, svg: svgDOM } );

		}
    },

	sendSaveRequest: function(url, params){

		// Send the request to the server.
		new Ajax.Request(url, {
                method: 'POST',
                asynchronous: false,
                parameters: params,
			onSuccess: (function(transport) {
				var loc = transport.getResponseHeader("location");
				if (!this.processURI && loc) {
					this.processURI = loc;
				}

				//show saved status
				this.facade.raiseEvent({
						type:'loading.status',
						text:'Saved!'
					});
			}).bind(this),
			onFailure: function(transport) {
				// raise loading disable event.
                this.facade.raiseEvent({
                    type: 'loading.disable'
                });

			alert("Saving failed.");

			ORYX.log.warn("Saving failed: " + transport.responseText);
		}});

	},

    /**
     * Saves the current process to the server.
     * @param {Object} saveSynchronously when true, this call is synchronous and
     * waits for server reply. In this case, this call doesn't raise events for
     * loading plugin. If false, this will raise loading events and save
     * asynchronously. Use latter if UI responsibility is wanted, Former when
     * you need to be certain that saving is finished.
     */
    save: function(event, synchronously){

        // if not to saved synchronously
        if (synchronously == undefined) {

            // raise loading enable event
            this.facade.raiseEvent({
                type: 'loading.enable',
				text: 'Saving'
            });

            // asynchronously ...
            window.setTimeout((function(){

                // ... save synchronously
                this.saveSynchronously();

            }).bind(this), 10);

        }
        else

            // just save, synchronously.
            this.saveSynchronously();

        return true;
    },

    info: function(){

        //TODO Make this fit in 80 columns.
        var info = "Copyright (c) 2006\n" +
        "Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner\n\n" +
        "Permission is hereby granted, free of charge, to any person " +
        "obtaining a copy of this software and associated documentation files " +
        "(the Software), to deal in the Software without restriction, " +
        "including without limitation the rights to use, copy, modify, merge, " +
        "publish, distribute, sublicense, and/or sell copies of the Software, " +
        "and to permit persons to whom the Software is furnished to do so, " +
        "subject to the following conditions:\n\n" +
        "The above copyright notice and this permission notice shall be " +
        "included in all copies or substantial portions of the Software.\n\n" +
        "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " +
        "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " +
        "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " +
        "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS " +
        "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN " +
        "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " +
        "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE " +
        "SOFTWARE.";

        alert(info);
        return false;
    },

    exportPDF: function(){

        var resource = location.href;

        // Get the serialized svg image source
        var svgClone = this.facade.getCanvas().getRootNode().cloneNode(true);

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', 2800);
        svgClone.setAttributeNS(null, 'height', 2200);

        var svgDOM = DataManager.serialize(svgClone);

        // Send the svg to the server.
        //TODO make this better by using content negotiation instead of format parameter.
        //TODO make this better by generating svg on the server, too.
        new Ajax.Request(ORYX.CONFIG.PDF_EXPORT_URL, {
            method: 'POST',
            parameters: {
                resource: resource,
                data: svgDOM,
                format: "pdf"
            },
            onSuccess: function(request){

                // Because the pdf may be opened in the same window as the
                // process, yet the process may not have been saved, we're
                // opening every other representation in a new window.
                // location.href = request.responseText
                window.open(request.responseText);
            }
        });
    },

    print: function(){

        // Set all options for the new window
        var option = $H({
            width: 300,
            height: 400,
            toolbar: "no",
            status: "no",
            menubar: "yes",
            dependent: "yes",
            resizable: "yes",
            scrollbars: "yes"
        });

        // Create the new window with all the settings
        var newWindow = window.open("", "PrintWindow", option.invoke('join', '=').join(','));

        // Add a style tag to the head and hide all controls
        var head = newWindow.document.getElementsByTagName('head')[0];
        var style = document.createElement("style");
        style.innerHTML = " body {padding:0px; margin:0px} .svgcontainer { display:none; }";
        head.appendChild(style);

        // Clone the svg-node and append this to the new body
        newWindow.document.getElementsByTagName('body')[0].appendChild(this.facade.getCanvas().getRootNode().cloneNode(true));
        var svg = newWindow.document.getElementsByTagName('body')[0].getElementsByTagName('svg')[0];

        // Set the width and height
        svg.setAttributeNS(null, 'width', 1100);
        svg.setAttributeNS(null, 'height', 1400);

        // Set the correct size and rotation
        svg.lastChild.setAttributeNS(null, 'transform', 'scale(0.47, 0.47) rotate(270, 1510, 1470)');

        var markers = ['marker-start', 'marker-mid', 'marker-end']
        var path = $A(newWindow.document.getElementsByTagName('path'));
        path.each(function(pathNode){
            markers.each(function(marker){
                // Get the marker value
                var url = pathNode.getAttributeNS(null, marker);
                if (!url) {
                    return
                };

                // Replace the URL and set them new
                url = "url(about:blank#" + url.slice(5);
                pathNode.setAttributeNS(null, marker, url);
            });
        });

        // Get the print dialog
        newWindow.print();

        return true;
    }
});
<|endoftext|>


<commit_before>const noble = require('noble');
const SBrickChannel = require('./SBrickChannel');
const SBrickAdvertisementData = require('./SBrickAdvertisementData');

function SBrick (uuid) {
    this.uuid = uuid;
    this.connected = false;
    this.characteristic = null;
    this.runInterval = null;
    this.blocking = false;

    this.channels = [
        new SBrickChannel(0),
        new SBrickChannel(1),
        new SBrickChannel(2),
        new SBrickChannel(3)
    ];
}

SBrick.prototype.start = function (callback, startFunction) {
    this.connect((err) => {
        if (err) {
            return callback(err);
        }
        if (startFunction) {
            startFunction(this);
        }
        this.run(callback);
    })
};

SBrick.prototype.connect = function (callback) {
    if (!this.connected) {
        if (noble.state === 'poweredOn') {
            this.startScan(callback);
        } else {
            noble.on('stateChange', (state) => {
                if (state === 'poweredOn') {
                    this.startScan(callback);
                }
            });
        }
    }
};

SBrick.prototype.startScan = function (callback) {
    console.log('scanning for', this.uuid);
    noble.on('discover', (peripheral) => {
        console.log('found', peripheral.uuid);
        if (peripheral.uuid === this.uuid) {
            console.log('done');
            noble.stopScanning();

            peripheral.connect((err) => {
                if (err) {
                    return callback(err);
                }

                this.connected = true;
                console.log('connected to peripheral: ' + peripheral.uuid, peripheral.advertisement);

                peripheral.once('disconnect', () => {
                    clearInterval(this.runInterval);
                    this.connected = false;
                    console.log('disconnect peripheral', this.uuid);
                    console.log('reconnecting');
                    this.connect();
                });

                peripheral.discoverServices(['4dc591b0857c41deb5f115abda665b0c'], (err, services) => {
                    if (err) {
                        console.log("service discovery error", err);
                        return callback(err);
                    }

                    console.log('remote control service found');

                    services[0].discoverCharacteristics(['02b8cbcc0e254bda8790a15f53e6010f'], (err, characteristics) => {
                        console.log('remote control characteristic found');
                        this.characteristic = characteristics[0];
                        return callback(null);
                    });
                });
            });
        }
    });

    noble.startScanning()
};

SBrick.prototype.run = function (callback) {
    this.characteristic.on('data',function (data) {
        if (!this.blocking) {
            //console.log('data', data, data.readInt16LE(0), data.readInt16LE(2));
            console.log('voltage', data.readInt16LE(0) * 0.83875 / 2047.0);
            console.log('temperature', data.readInt16LE(2) / 118.85795 - 160)

        }
    });

    this.characteristic.subscribe(function (err) {
        console.log('subscriptbe1', err);
    });

    this.readCommand("0a");

    this.runInterval = setInterval(() => {
        if (!this.blocking) {
            this.channels.forEach((channel) => {
                var b = channel.getCommand();
                this.writeCommand(b);
            });
        }
    }, 200);

    callback(null);
};

SBrick.prototype.writeCommand = function (cmd) {
    if (!(cmd instanceof Buffer)) {
        cmd = new Buffer(cmd, "hex");
    }

    this.characteristic.write(cmd, false, (err) => {
        if (err) {
            console.log("write error", err, cmd);
        }
    });
};

SBrick.prototype.readCommand = function (cmd, callback) {
    callback = callback || () => {};

    if (!this.blocking) {
        this.writeCommand(cmd);

        this.blocking = true;

        this.characteristic.read((err, data) => {
            if (err) {
                console.log("read error", err, cmd);
            } else {
                console.log(data);
            }

            this.blocking = false;

            callback(err, data);
        });
    } else {
        console.log('other read in progress');
        callback('other read in progress');
    }
};

SBrick.scanSBricks = function (callback) {
    if (noble.state === 'poweredOn') {
        scanSBricks(callback);
    } else {
        noble.on('stateChange', (state) => {
            if (state === 'poweredOn') {
                noble.off('stateChange');
                scanSBricks(callback);
            }
        });
    }
};

const scanSBricks = function (callback) {
    var sbrickUuids = [];
    noble.on('discover', (peripheral) => {

        try {
            SBrickAdvertisementData.parse(peripheral.advertisement.manufacturerData);
            console.log(peripheral.uuid, 'SBrick');
            sbrickUuids.push(peripheral.uuid);
        } catch (err) {
            console.log(peripheral.uuid, err);
        }
    });

    noble.startScanning();

    setTimeout(() => {
        noble.stopScanning();
        noble.removeAllListeners('discover');
        callback(null, sbrickUuids);
    }, 1000);
};

module.exports = SBrick;<commit_msg>winston logger<commit_after>const noble = require('noble');
const winston = require('winston');
const SBrickChannel = require('./SBrickChannel');
const SBrickAdvertisementData = require('./SBrickAdvertisementData');

function SBrick (uuid) {
    this.uuid = uuid;
    this.connected = false;
    this.characteristic = null;
    this.runInterval = null;
    this.blocking = false;

    this.channels = [
        new SBrickChannel(0),
        new SBrickChannel(1),
        new SBrickChannel(2),
        new SBrickChannel(3)
    ];
}

SBrick.prototype.start = function (callback, startFunction) {
    this.connect((err) => {
        if (err) {
            return callback(err);
        }
        if (startFunction) {
            startFunction(this);
        }
        this.run(callback);
    })
};

SBrick.prototype.connect = function (callback) {
    if (!this.connected) {
        if (noble.state === 'poweredOn') {
            this.startScan(callback);
        } else {
            noble.on('stateChange', (state) => {
                if (state === 'poweredOn') {
                    this.startScan(callback);
                }
            });
        }
    }
};

SBrick.prototype.startScan = function (callback) {
    winston.info('scanning for', this.uuid);
    noble.on('discover', (peripheral) => {
        winston.info('found', peripheral.uuid);
        if (peripheral.uuid === this.uuid) {
            noble.stopScanning();

            peripheral.connect((err) => {
                if (err) {
                    return callback(err);
                }

                this.connected = true;
                winston.info('connected to peripheral: ' + peripheral.uuid, peripheral.advertisement);

                peripheral.once('disconnect', () => {
                    clearInterval(this.runInterval);
                    this.connected = false;
                    winston.warn('disconnect peripheral', this.uuid);
                    winston.info('reconnecting');
                    this.connect();
                });

                peripheral.discoverServices(['4dc591b0857c41deb5f115abda665b0c'], (err, services) => {
                    if (err) {
                        winston.warn("service discovery error", err);
                        return callback(err);
                    }

                    winston.info('remote control service found');

                    services[0].discoverCharacteristics(['02b8cbcc0e254bda8790a15f53e6010f'], (err, characteristics) => {
                        winston.info('remote control characteristic found');
                        this.characteristic = characteristics[0];
                        return callback(null);
                    });
                });
            });
        }
    });

    noble.startScanning()
};

SBrick.prototype.run = function (callback) {
    this.characteristic.on('data',function (data) {
        if (!this.blocking) {
            winston.info('voltage', data.readInt16LE(0) * 0.83875 / 2047.0);
            winston.info('temperature', data.readInt16LE(2) / 118.85795 - 160)
        }
    });

    this.characteristic.subscribe(function (err) {
        winston.warn('subscribe error', err);
    });

    this.readCommand("0a");

    this.runInterval = setInterval(() => {
        if (!this.blocking) {
            this.channels.forEach((channel) => {
                var b = channel.getCommand();
                this.writeCommand(b);
            });
        }
    }, 200);

    callback(null);
};

SBrick.prototype.writeCommand = function (cmd) {
    if (!(cmd instanceof Buffer)) {
        cmd = new Buffer(cmd, "hex");
    }

    this.characteristic.write(cmd, false, (err) => {
        if (err) {
            winston.warn("write error", err, cmd);
        }
    });
};

SBrick.prototype.readCommand = function (cmd, callback) {
    callback = callback || () => {};

    if (!this.blocking) {
        this.writeCommand(cmd);

        this.blocking = true;

        this.characteristic.read((err, data) => {
            if (err) {
                winston.warn("read error", err, cmd);
            } else {
                console.log(data);
            }

            this.blocking = false;

            callback(err, data);
        });
    } else {
        winston.info('other read in progress');
        callback('other read in progress');
    }
};

SBrick.scanSBricks = function (callback) {
    if (noble.state === 'poweredOn') {
        scanSBricks(callback);
    } else {
        noble.on('stateChange', (state) => {
            if (state === 'poweredOn') {
                noble.off('stateChange');
                scanSBricks(callback);
            }
        });
    }
};

const scanSBricks = function (callback) {
    var sbrickUuids = [];
    noble.on('discover', (peripheral) => {

        try {
            SBrickAdvertisementData.parse(peripheral.advertisement.manufacturerData);
            winston.info(peripheral.uuid, 'SBrick');
            sbrickUuids.push(peripheral.uuid);
        } catch (err) {
            winston.info(peripheral.uuid, err);
        }
    });

    noble.startScanning();

    setTimeout(() => {
        noble.stopScanning();
        noble.removeAllListeners('discover');
        callback(null, sbrickUuids);
    }, 1000);
};

module.exports = SBrick;<|endoftext|>


<commit_before>// Handles CRUD requests for reports.
'use strict';

var express = require('express');
var Report = require('../../../models/report');
var _ = require('underscore');
var writelog = require('../../writeLog');
var tags = require('../../../shared/tags');
var ReportQuery = require('../../../models/query/report-query');

module.exports = function(app, user) {
  app = app || express();

  // Get a list of all Reports
  app.get('/api/v1/test', function(req, res) {
    var filterResults = {
      _id: 1,
      authoredAt: 1,
      author: 1,
      tags: 1,
      flagged: 1,
      _media: 1,
      "metadata.ct_tag": 1
    };
    var count = req.query.count;
    if (count) delete req.query.count;
    var query = new ReportQuery(req.query);
    if (count){
      Report.find(query.toMongooseFilter(), filterResults, function(err, reports) {
        if (err) res.send(err.status, err.message);
        else res.send(200, reports.map(function (report) {
          return Object.assign({}, report._doc, {_media: report._doc._media[0]})
        }))
      }).limit(parseInt(count));
    } else {
      Report.find(query.toMongooseFilter(), filterResults, function(err, reports) {
        if (err) res.send(err.status, err.message);
        else res.send(200, reports.map(function (report) {
          return Object.assign({}, report._doc, {_media: report._doc._media[0]})
        }))
      })
    }
  });

  // Get Report by id
  app.get('/api/v1/test/:_id', function(req, res) {
    Report.findById(req.params._id, function(err, report) {
      if (err) res.send(err.status, err.message);
      else if (!report) res.send(404);
      else {
        writelog.writeReport(req, report, 'viewReport');
        res.send(200, report);
      }
    });
  });

  return app;
};

// Determine the search keywords
function parseQueryData(queryString) {
  if (!queryString) return {};
  // Data passed through URL parameters
  var query = _.pick(queryString, ['keywords', 'status', 'after', 'before', 'media',
                                   'sourceId', 'incidentId', 'author', 'tags', 'list']);
  if (query.tags) query.tags = tags.toArray(query.tags);
  return query;
}
<commit_msg>getting a few more elements<commit_after>// Handles CRUD requests for reports.
'use strict';

var express = require('express');
var Report = require('../../../models/report');
var _ = require('underscore');
var writelog = require('../../writeLog');
var tags = require('../../../shared/tags');
var ReportQuery = require('../../../models/query/report-query');

module.exports = function(app, user) {
  app = app || express();

  // Get a list of all Reports
  app.get('/api/v1/test', function(req, res) {
    var filterResults = {
      _id: 1,
      authoredAt: 1,
      author: 1,
      tags: 1,
      flagged: 1,
      _media: 1,
      "metadata.ct_tag": 1,
      "metadata.actualStatistics": 1,
      "metadata.expectedStatistics": 1,
      "metadata.rawAPIResponse.score": 1,
    };
    var count = req.query.count;
    if (count) delete req.query.count;
    var query = new ReportQuery(req.query);
    if (count){
      Report.find(query.toMongooseFilter(), filterResults, function(err, reports) {
        if (err) res.send(err.status, err.message);
        else res.send(200, reports.map(function (report) {
          var fixed = Object.assign({}, report._doc, {_media: report._doc._media[0]});
          if (fixed.metadata.expectedStatistics || fixed.metadata.actualStatistics) {
            var expected = JSON.parse(JSON.stringify(fixed.metadata.expectedStatistics).replace(/(")(.*?")/g, "$1expected_$2"))
            var actual = JSON.parse(JSON.stringify(fixed.metadata.actualStatistics).replace(/(")(.*?")/g, "$1actual_$2"))
            fixed = Object.assign(fixed, expected, actual);
            delete fixed.metadata.actualStatistics;
            delete fixed.metadata.expectedStatistics;
          }
          if (fixed.metadata.rawAPIResponse) {
            fixed = Object.assign(fixed, {score: fixed.metadata.rawAPIResponse.score})
            delete fixed.metadata.rawAPIResponse;
          }
          return fixed;
        }))
      }).limit(parseInt(count));
    } else {
      Report.find(query.toMongooseFilter(), filterResults, function(err, reports) {
        if (err) res.send(err.status, err.message);
        else res.send(200, reports.map(function (report) {
          return Object.assign({}, report._doc, {_media: report._doc._media[0]})
        }))
      })
    }
  });

  // Get Report by id
  app.get('/api/v1/test/:_id', function(req, res) {
    Report.findById(req.params._id, function(err, report) {
      if (err) res.send(err.status, err.message);
      else if (!report) res.send(404);
      else {
        writelog.writeReport(req, report, 'viewReport');
        res.send(200, report);
      }
    });
  });

  return app;
};

// Determine the search keywords
function parseQueryData(queryString) {
  if (!queryString) return {};
  // Data passed through URL parameters
  var query = _.pick(queryString, ['keywords', 'status', 'after', 'before', 'media',
                                   'sourceId', 'incidentId', 'author', 'tags', 'list']);
  if (query.tags) query.tags = tags.toArray(query.tags);
  return query;
}
<|endoftext|>


<commit_before>var app = angular.module('myApp', []);

/**
* @ngDoc directive
* @name ng.directive:paging
*
* @description
* The paging directive allows you to specify custom
*
* @element E
*
* todo: figure out best commenting structure
*
*/
app.directive('paging', function () {

    // Private Count Variable
    var pageCount = 0,
        dots = '...',
        adjacent = 2,
        selectedClass = 'selected';

    // Add Dots ie: 1 2 [...] 10 11 12 [...] 56 57
    function addDots(scope) {
        scope.List.push({
            value: dots
        });
    }

    // Add Range of Numbers
    function addRange(start, finish, scope) {

        var i = 0;
        for (i = start; i <= finish; i++) {

            var item = {
                value: i,
                title: 'Page ' + i,
                class: scope.page == i ? selectedClass : '',
                click: function (page) {

                    scope.page = page;
                }
            }

            scope.List.push(item);
        }
    }

    // Add First Pages
    function addFirst(scope) {
        addRange(1, 2, scope);
        addDots(scope);
    }

    // Add Last Pages
    function addLast(scope) {
        addDots(scope);
        addRange(pageCount - 1, pageCount, scope);
    }

    function build(scope) {

        if (!scope.pagesize) {
            // to block divide by 0
            return;
        }

        if (!scope.page) {
            // default page is 1
            scope.page = 1;
        }

        // variables
        var size = adjacent * 2;
        scope.page = parseInt(scope.page);
        scope.List = [];
        pageCount = Math.ceil(scope.total / scope.pagesize);

        if (pageCount < (5 + size)) {
            addRange(start, pageCount, scope);
        }
        else {

            if (scope.page <= (1 + size)) {
                var start = 1;
                var finish = 2 + size;
                addRange(start, finish, scope);
                addLast(scope);
            }
            else if (pageCount - size > scope.page && scope.page > size) {
                var start = scope.page - adjacent;
                var finish = scope.page + adjacent;
                addFirst(scope);
                addRange(start, finish, scope);
                addLast(scope);
            }
            else {
                var start = pageCount - (1 + size);
                var finish = pageCount;
                addFirst(scope);
                addRange(start, finish, scope);
            }
        }
    }

    return {
        restrict: 'EA',
        scope: {
            page: '@',
            pagesize: '@',
            total: '@'
        },
        template:
        '<ul> \
        	<li \
				title="{{Item.title}}" \
				class="{{Item.class}}" \
				ng-click="Item.click(Item.value)" \
        		ng-repeat="Item in List track by $index"> \
				{{Item.value}} \
        </ul>',
        link: function (scope, element, attrs) {
            build(scope);

            scope.$watch('total', function () {
                build(scope);
            });

            scope.$watch('page', function () {
                build(scope);
            });

            scope.$watch('pagesize', function () {
                build(scope);
            });
        }
    }
});<commit_msg>Spacing<commit_after>var app = angular.module('myApp', []);

/**
* @ngDoc directive
* @name ng.directive:paging
*
* @description
* The paging directive allows you to specify custom
*
* @element E
*
* todo: figure out best commenting structure
*
*/
app.directive('paging', function () {

    // Private Count Variable
    var pageCount = 0,
        dots = '...',
        adjacent = 2,
        selectedClass = 'selected';

    // Add Dots ie: 1 2 [...] 10 11 12 [...] 56 57
    function addDots(scope) {
        scope.List.push({
            value: dots
        });
    }

    // Add Range of Numbers
    function addRange(start, finish, scope) {

        var i = 0;
        for (i = start; i <= finish; i++) {

            var item = {
                value: i,
                title: 'Page ' + i,
                class: scope.page == i ? selectedClass : '',
                click: function (page) {

                    scope.page = page;
                }
            }

            scope.List.push(item);
        }
    }

    // Add First Pages
    function addFirst(scope) {
        addRange(1, 2, scope);
        addDots(scope);
    }

    // Add Last Pages
    function addLast(scope) {
        addDots(scope);
        addRange(pageCount - 1, pageCount, scope);
    }

    function build(scope) {

        if (!scope.pagesize) {
            // to block divide by 0
            return;
        }

        if (!scope.page) {
            // default page is 1
            scope.page = 1;
        }

        // variables
        var size = adjacent * 2;
        scope.page = parseInt(scope.page);
        scope.List = [];
        pageCount = Math.ceil(scope.total / scope.pagesize);

        if (pageCount < (5 + size)) {
            addRange(start, pageCount, scope);
        }
        else {

            if (scope.page <= (1 + size)) {
                var start = 1;
                var finish = 2 + size;
                addRange(start, finish, scope);
                addLast(scope);
            }
            else if (pageCount - size > scope.page && scope.page > size) {
                var start = scope.page - adjacent;
                var finish = scope.page + adjacent;
                addFirst(scope);
                addRange(start, finish, scope);
                addLast(scope);
            }
            else {
                var start = pageCount - (1 + size);
                var finish = pageCount;
                addFirst(scope);
                addRange(start, finish, scope);
            }
        }
    }

    return {
        restrict: 'EA',
        scope: {
            page: '@',
            pagesize: '@',
            total: '@'
        },
        template:
        '<ul> \
			<li \
                title="{{Item.title}}" \
                class="{{Item.class}}" \
                ng-click="Item.click(Item.value)" \
                ng-repeat="Item in List track by $index"> \
                {{Item.value}} \
        </ul>',
        link: function (scope, element, attrs) {
            build(scope);

            scope.$watch('total', function () {
                build(scope);
            });

            scope.$watch('page', function () {
                build(scope);
            });

            scope.$watch('pagesize', function () {
                build(scope);
            });
        }
    }
});<|endoftext|>


<commit_before>var crypto = require('crypto');
var _ = require('underscore');

function TokenContainer() {
  this._tokens = {};
  this._startGarbageCollecting();
}

TokenContainer._hourMs = 60 * 60 * 1000;
TokenContainer._collectorIntervalMs = 12 * TokenContainer._hourMs;
TokenContainer._oudatedTimeMs = 48 * TokenContainer._hourMs;

TokenContainer.prototype.saveToken = function(res, token) {
  var cookie = crypto.randomBytes(32).toString('hex');
  this._tokens[cookie] = {token: token, lastUsage: Date.now()};
  res.cookies.set('userid', cookie, {path: '/'});
};

TokenContainer.prototype.hasToken = function(tokenKey) {
  var info = this._tokens[tokenKey];
  if (info) {
    info.lastUsage = Date.now();
  }
  return !!info;
};

TokenContainer.prototype.extractTokenKeyFromRequest = function(req) {
  return req.cookies.get('userid');
};

TokenContainer.prototype._startGarbageCollecting = function() {
  setInterval(function() {
    var now = Date.now();
    _.each(this._tokens, function(info, cookie, cookies) {
      if (now - info.lastUsage > TokenContainer._oudatedTimeMs) {
        delete cookies[cookie];
      }
    });
  }.bind(this), TokenContainer._collectorIntervalMs);
};

module.exports = TokenContainer;
<commit_msg>Return back httpOnly=false.<commit_after>var crypto = require('crypto');
var _ = require('underscore');

function TokenContainer() {
  this._tokens = {};
  this._startGarbageCollecting();
}

TokenContainer._hourMs = 60 * 60 * 1000;
TokenContainer._collectorIntervalMs = 12 * TokenContainer._hourMs;
TokenContainer._oudatedTimeMs = 48 * TokenContainer._hourMs;

TokenContainer.prototype.saveToken = function(res, token) {
  var cookie = crypto.randomBytes(32).toString('hex');
  this._tokens[cookie] = {token: token, lastUsage: Date.now()};
  res.cookies.set('userid', cookie, {path: '/', httpOnly: false});
};

TokenContainer.prototype.hasToken = function(tokenKey) {
  var info = this._tokens[tokenKey];
  if (info) {
    info.lastUsage = Date.now();
  }
  return !!info;
};

TokenContainer.prototype.extractTokenKeyFromRequest = function(req) {
  return req.cookies.get('userid');
};

TokenContainer.prototype._startGarbageCollecting = function() {
  setInterval(function() {
    var now = Date.now();
    _.each(this._tokens, function(info, cookie, cookies) {
      if (now - info.lastUsage > TokenContainer._oudatedTimeMs) {
        delete cookies[cookie];
      }
    });
  }.bind(this), TokenContainer._collectorIntervalMs);
};

module.exports = TokenContainer;
<|endoftext|>


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

//a shorthand writting
const Ci = Components.interfaces;
const Cc = Components.classes;

/**
 * Object used to observe DnD on the suiteTree
 */
var suiteTreeDragObserver = {

    onDragStart: function (aEvent, aXferData, aDragAction) {

        try{
            var selectedIndex = document.getElementById('suiteTree').currentIndex;
            if (selectedIndex == -1)
                return;

            aXferData.data = new TransferData();
            aXferData.data.addDataForFlavour("text/unicode", selectedIndex.toString());
            aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_MOVE;

        }catch(e){
            new Log("DND").error("onDragStart error: "+e);
        }
    },
    onDrop: function (aEvent, aXferData, aDragSession) {},
    onDragExit: function (aEvent, aDragSession) {},
    onDragOver: function (aEvent, aFlavour, aDragSession) {},
    getSupportedFlavours: function() {return null; }
};

/**
 * Object used to observe dnd on the commands of the current testcase
 */
var commandsDragObserver = {

    onDragStart: function (aEvent, aXferData, aDragAction) {

        try{
            var selectedIndex = document.getElementById('commands').currentIndex;
            if (selectedIndex == -1)
                return;

            aXferData.data = new TransferData();
            aXferData.data.addDataForFlavour("text/unicode", selectedIndex.toString());
            aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_MOVE;

        }catch(e){
            new Log("DND").error("onDragStart error: "+e);
        }
    },
    onDrop: function (aEvent, aXferData, aDragSession) {},
    onDragExit: function (aEvent, aDragSession) {},
    onDragOver: function (aEvent, aFlavour, aDragSession) {},
    getSupportedFlavours: function() {return null; }
};<commit_msg>jeremy.herault: delete the copyright<commit_after>/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//a shorthand writting
const Ci = Components.interfaces;
const Cc = Components.classes;

/**
 * Object used to observe DnD on the suiteTree
 */
var suiteTreeDragObserver = {

    onDragStart: function (aEvent, aXferData, aDragAction) {

        try{
            var selectedIndex = document.getElementById('suiteTree').currentIndex;
            if (selectedIndex == -1)
                return;

            aXferData.data = new TransferData();
            aXferData.data.addDataForFlavour("text/unicode", selectedIndex.toString());
            aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_MOVE;

        }catch(e){
            new Log("DND").error("onDragStart error: "+e);
        }
    },
    onDrop: function (aEvent, aXferData, aDragSession) {},
    onDragExit: function (aEvent, aDragSession) {},
    onDragOver: function (aEvent, aFlavour, aDragSession) {},
    getSupportedFlavours: function() {return null; }
};

/**
 * Object used to observe dnd on the commands of the current testcase
 */
var commandsDragObserver = {

    onDragStart: function (aEvent, aXferData, aDragAction) {

        try{
            var selectedIndex = document.getElementById('commands').currentIndex;
            if (selectedIndex == -1)
                return;

            aXferData.data = new TransferData();
            aXferData.data.addDataForFlavour("text/unicode", selectedIndex.toString());
            aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_MOVE;

        }catch(e){
            new Log("DND").error("onDragStart error: "+e);
        }
    },
    onDrop: function (aEvent, aXferData, aDragSession) {},
    onDragExit: function (aEvent, aDragSession) {},
    onDragOver: function (aEvent, aFlavour, aDragSession) {},
    getSupportedFlavours: function() {return null; }
};<|endoftext|>


<commit_before>var rating = require('rating'),
  day = 24 * 60 * 60 * 1000;

module.exports = render;
module.exports.section = 1;

// .powder
//   .powder-rating= resort.powder.rating
//   .notice
//     a

function render(div, powder) {
  var el;
  if (Date.now() - powder.timestamp > day) {
    return false;
  }
  el = div.querySelector('.powder-rating');
  el.innerHTML = '';
  if (typeof powder.rating === 'number') {
    rating(el, {
      star: '',
      value: powder.rating
    });
  }
  div.querySelector('.notice a')
    .setAttribute('href', 'http://whereshouldiski.com/resorts?resort=' + powder.id);
  return true;
}
<commit_msg>fix whereshouldiski links<commit_after>var rating = require('rating'),
  day = 24 * 60 * 60 * 1000;

module.exports = render;
module.exports.section = 1;

// .powder
//   .powder-rating= resort.powder.rating
//   .notice
//     a

function render(div, powder) {
  var el;
  if (Date.now() - powder.timestamp > day) {
    return false;
  }
  el = div.querySelector('.powder-rating');
  el.innerHTML = '';
  if (typeof powder.rating === 'number') {
    rating(el, {
      star: '',
      value: powder.rating
    });
  }
  div.querySelector('.notice a')
    .setAttribute('href', 'http://whereshouldiski.com/#/resort/' + powder.id);
  return true;
}
<|endoftext|>


<commit_before>'use strict';
var _ = require('lodash');

var themeFunctions = require('theme').functions || {};

var MdHelper = require('./elements/MdHelper');
var itemHooks = require('./itemHooks');
var config = require('config');
var siteFunctions = config.functions || {} ;

function allItems() {
  var items = [].concat.apply([], _.keys(config.paths).map(function(sectionName) {
    var section = config.paths[sectionName];

    var paths = parseModules(sectionName, section, section.path());

    var draftPaths = [];
    if(__DEV__ && section.draft) {
      draftPaths = parseModules(sectionName, section, section.draft()).map(function(module) {
        module.file.isDraft = true;

        return module;
      });
    }

    return (section.sort || defaultSort)(paths.concat(draftPaths));
  }));

  items = itemHooks.preProcessItems(items);
  items = _.map(items, function(o) {
    return processItem(o.file, o.url, o.name, o.sectionName, o.section);
  });
  items = itemHooks.postProcessItems(items);

  var ret = {};

  _.each(items, function(o) {
    ret[o.url] = o;
  });
  return ret;
}
exports.allItems = allItems;

function defaultSort(files) {
    return _.sortBy(files, 'date').reverse();
}

function parseModules(sectionName, section, modules) {
  return _.map(modules.keys(), function(name) {
    return {
      name: name.slice(2),
      file: modules(name),
      section: section,
      sectionName: sectionName === '/' ? '' : sectionName,
    };
  });
}

function itemForPath(path) {
  var items = allItems();

  // check both to make root paths work (they have extra /)
  return items[path] || items['/' + path];
}
exports.itemForPath = itemForPath;

function processItem(o, url, fileName, sectionName, section) {
  var layout = section.layout;
  var sectionFunctions = section.processItem || {};

  var functions = _.assign({
    isDraft: function(o) {
      return o.file.isDraft || o.isDraft;
    },
    date: function(o) {
      return o.file.date || null;
    },
    content: function(o) {
      return MdHelper.render(o.file.__content);
    },
    preview: function(o) {
      var file = o.file;

      if (file.preview) {
        return file.preview;
      }

      return MdHelper.renderPreview(file.__content, 100, '…');
    },
    title: function(o) {
      return o.file.title;
    },
    url: function(o) {
      return o.sectionName + '/' + o.fileName.split('.')[0].toLowerCase();
    },
    layout: function(o) {
      return layout;
    },
  }, themeFunctions, siteFunctions, sectionFunctions);

  _.forEach(functions, function(fn, name) {
    o[name] = fn({
      file: o,
      fileName: fileName,
      sectionName: sectionName
    });
  });

  o.section = sectionName;

  return o;
}
<commit_msg>Filter out drafts from a production build<commit_after>'use strict';
var _ = require('lodash');

var themeFunctions = require('theme').functions || {};

var MdHelper = require('./elements/MdHelper');
var itemHooks = require('./itemHooks');
var config = require('config');
var siteFunctions = config.functions || {} ;

function allItems() {
  var items = [].concat.apply([], _.keys(config.paths).map(function(sectionName) {
    var section = config.paths[sectionName];

    var paths = parseModules(sectionName, section, section.path());

    var draftPaths = [];
    if(__DEV__ && section.draft) {
      draftPaths = parseModules(sectionName, section, section.draft()).map(function(module) {
        module.file.isDraft = true;

        return module;
      });
    }

    return (section.sort || defaultSort)(paths.concat(draftPaths));
  }));

  items = itemHooks.preProcessItems(items);
  items = _.map(items, function(o) {
    return processItem(o.file, o.url, o.name, o.sectionName, o.section);
  });
  items = itemHooks.postProcessItems(items);

  var ret = {};

  if(__DEV__) {
    _.each(items, function(o) {
      ret[o.url] = o;
    });
  }
  else {
    _.each(items, function(o) {
      if(!o.isDraft) {
        ret[o.url] = o;
      }
    });
  }

  return ret;
}
exports.allItems = allItems;

function defaultSort(files) {
    return _.sortBy(files, 'date').reverse();
}

function parseModules(sectionName, section, modules) {
  return _.map(modules.keys(), function(name) {
    return {
      name: name.slice(2),
      file: modules(name),
      section: section,
      sectionName: sectionName === '/' ? '' : sectionName,
    };
  });
}

function itemForPath(path) {
  var items = allItems();

  // check both to make root paths work (they have extra /)
  return items[path] || items['/' + path];
}
exports.itemForPath = itemForPath;

function processItem(o, url, fileName, sectionName, section) {
  var layout = section.layout;
  var sectionFunctions = section.processItem || {};

  var functions = _.assign({
    isDraft: function(o) {
      return o.file.isDraft || o.isDraft;
    },
    date: function(o) {
      return o.file.date || null;
    },
    content: function(o) {
      return MdHelper.render(o.file.__content);
    },
    preview: function(o) {
      var file = o.file;

      if (file.preview) {
        return file.preview;
      }

      return MdHelper.renderPreview(file.__content, 100, '…');
    },
    title: function(o) {
      return o.file.title;
    },
    url: function(o) {
      return o.sectionName + '/' + o.fileName.split('.')[0].toLowerCase();
    },
    layout: function(o) {
      return layout;
    },
  }, themeFunctions, siteFunctions, sectionFunctions);

  _.forEach(functions, function(fn, name) {
    o[name] = fn({
      file: o,
      fileName: fileName,
      sectionName: sectionName
    });
  });

  o.section = sectionName;

  return o;
}
<|endoftext|>


<commit_before>var pathSeparator = '.',
    wildcard = '*';

function pathToParts(path){
    if(!path){
        return [];
    }
    return path.split(pathSeparator);
}

function concat(){
    var resultPaths = [],
        arg;
    for(var i = 0; i < arguments.length; i++) {
        arg = arguments[i];

        if(Array.isArray(arg)){
            resultPaths.push(join(arg));
            continue;
        }
        resultPaths.push(pathSegment);
    }

    return join(resultPaths);
}

function join(paths){
    var resultPaths = [],
        path;

    for(var i = 0; i < paths.length; i++) {
        path = paths[i];

        if(path == null || path === ''){
            continue;
        }
        resultPaths.push(path);
    }

    return resultPaths.join(pathSeparator);
}

function up(path, number){
    number = number || 1;
    return join(pathToParts(path).slice(0,-number));
}

module.exports = {
    join: join,
    concat: concat,
    toParts: pathToParts,
    up: up,
    constants:{
        separator: pathSeparator,
        wildcard: wildcard
    }
};<commit_msg>join perf improvments<commit_after>var pathSeparator = '.',
    wildcard = '*';

function pathToParts(path){
    if(!path){
        return [];
    }
    return path.split(pathSeparator);
}

function concat(){
    var resultPaths = [],
        arg;
    for(var i = 0; i < arguments.length; i++) {
        arg = arguments[i];

        if(Array.isArray(arg)){
            resultPaths.push(join(arg));
            continue;
        }
        resultPaths.push(pathSegment);
    }

    return join(resultPaths);
}

// This is an extremely hot function
// string concat is used over array.join
// for performance.
function join(paths){
    var result = '',
        path;

    for(var i = 0; i < paths.length; i++) {
        path = paths[i];

        if(path == null || path === ''){
            continue;
        }

        if(result === ''){
            result = path;
            continue;
        }

        result += '.' + path;
    }

    return result;
}

function up(path, number){
    number = number || 1;
    return join(pathToParts(path).slice(0,-number));
}

module.exports = {
    join: join,
    concat: concat,
    toParts: pathToParts,
    up: up,
    constants:{
        separator: pathSeparator,
        wildcard: wildcard
    }
};<|endoftext|>


<commit_before>// Notifications collection
Push.notifications = new Mongo.Collection('_raix_push_notifications');

// This is a general function to validate that the data added to notifications
// is in the correct format. If not this function will throw errors
var _validateDocument = function(notification) {

  // Check the general notification
  check(notification, {
    from: String,
    title: String,
    text: String,
    count: Number,
    query: Match.Optional(Object),
    token: Match.Optional(_matchToken),
    tokens: Match.Optional([_matchToken]),
    createdAt: Date,
    createdBy: Match.OneOf(String, null)
  });

  // Make sure a token selector or query have been set
  if (!notification.token && !notification.tokens && !notification.query)
    throw new Error('No token selector or query found');

  // If tokens array is set it should not be empty
  if (notification.tokens && !notification.tokens.length)
    throw new Error('No tokens in array');
};

Push.send = function(options) {
  // If on the client we set the user id - on the server we need an option
  // set or we default to "<SERVER>" as the creator of the notification
  // If current user not set see if we can set it to the logged in user
  // this will only run on the client if Meteor.userId is available
  var currentUser = Meteor.userId && Meteor.userId() ||
          Meteor.isServer && (options.createdBy || '<SERVER>') || null;

  // Rig the notification object
  var notification = {
    from: options.from,
    title: options.title,
    text: options.text,
    count: options.count || 0,
    createdAt: new Date(),
    createdBy: currentUser
  };

  // Set one token selector, this can be token, array of tokens or query
  if (options.query) {
    // Set query
    notification.query = options.query;
  } else if (options.token) {
    // Set token
    notification.token = options.token;
  } else if (options.tokens) {
    // Set tokens
    notification.tokens = options.tokens;
  }

  // Validate the notification
  _validateDocument(notification);

  // Try to add the notification to send, we return an id to keep track
  return Push.notifications.insert(notification);
};

Push.allow = function(rules) {
  if (rules.send) {
    Push.notifications.allow({
      'insert': function(userId, notification) {
        // Validate the notification
        _validateDocument(notification);
        // Set the user defined "send" rules
        return rules.send.apply(this, [userId, notification]);
      }
    });
  }
};

Push.deny = function(rules) {
  if (rules.send) {
    Push.notifications.deny({
      'insert': function(userId, notification) {
        // Validate the notification
        _validateDocument(notification);
        // Set the user defined "send" rules
        return rules.send.apply(this, [userId, notification]);
      }
    });
  }
};
<commit_msg>add badge and sound<commit_after>// Notifications collection
Push.notifications = new Mongo.Collection('_raix_push_notifications');

// This is a general function to validate that the data added to notifications
// is in the correct format. If not this function will throw errors
var _validateDocument = function(notification) {

  // Check the general notification
  check(notification, {
    from: String,
    title: String,
    text: String,
    badge: Match.Optional(Number),
    sound: Match.Optional(String),
    query: Match.Optional(Object),
    token: Match.Optional(_matchToken),
    tokens: Match.Optional([_matchToken]),
    createdAt: Date,
    createdBy: Match.OneOf(String, null)
  });

  // Make sure a token selector or query have been set
  if (!notification.token && !notification.tokens && !notification.query)
    throw new Error('No token selector or query found');

  // If tokens array is set it should not be empty
  if (notification.tokens && !notification.tokens.length)
    throw new Error('No tokens in array');
};

Push.send = function(options) {
  // If on the client we set the user id - on the server we need an option
  // set or we default to "<SERVER>" as the creator of the notification
  // If current user not set see if we can set it to the logged in user
  // this will only run on the client if Meteor.userId is available
  var currentUser = Meteor.userId && Meteor.userId() ||
          Meteor.isServer && (options.createdBy || '<SERVER>') || null;

  // Rig the notification object
  var notification = {
    from: options.from,
    title: options.title,
    text: options.text,
    count: options.count || 0,
    createdAt: new Date(),
    createdBy: currentUser
  };

  // Set one token selector, this can be token, array of tokens or query
  if (options.query) {
    // Set query
    notification.query = options.query;
  } else if (options.token) {
    // Set token
    notification.token = options.token;
  } else if (options.tokens) {
    // Set tokens
    notification.tokens = options.tokens;
  }

  // Validate the notification
  _validateDocument(notification);

  // Try to add the notification to send, we return an id to keep track
  return Push.notifications.insert(notification);
};

Push.allow = function(rules) {
  if (rules.send) {
    Push.notifications.allow({
      'insert': function(userId, notification) {
        // Validate the notification
        _validateDocument(notification);
        // Set the user defined "send" rules
        return rules.send.apply(this, [userId, notification]);
      }
    });
  }
};

Push.deny = function(rules) {
  if (rules.send) {
    Push.notifications.deny({
      'insert': function(userId, notification) {
        // Validate the notification
        _validateDocument(notification);
        // Set the user defined "send" rules
        return rules.send.apply(this, [userId, notification]);
      }
    });
  }
};
<|endoftext|>


<commit_before>import {InvalidElement} from "../errors.js";

// Private attributes
const _owner = new WeakMap();
const _tfmList = new WeakMap();
const _area = new WeakMap();

/**
 * The Transform class is in charge of the effects applied to components.
 */
class Transform {

  /**
   * @param {SVGElement} svgElement - The element to which apply the transformations.
   * @throws {InvalidElement} When the `svgElement` argument is wrong or not transformable.
   */
  constructor(svgElement) {
    if (!svgElement.viewportElement) {
      throw new InvalidElement("A not `viewport` SVGElement");
    }

    _owner.set(this, svgElement.ownerSVGElement);
    _tfmList.set(this, svgElement.transform.baseVal);
    _area.set(this, svgElement.viewportElement.viewBox.baseVal);
  }

  /**
   * Clear all the transformations applied to the svg element.
   */
  clear() {
    _tfmList.get(this).clear();
  }

  /**
   * Performs a rotation about a given point.
   * @param {!number} a - The rotate angle degrees.
   * @param {?number} x - The x-axis position
   * @param {?number} y - The y-axis position
   */
  rotate(a, x, y) {
    x = x || _area.get(this).width / 2;
    y = y || _area.get(this).height / 2;
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setRotate(a, x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Performs a horizontal flip.
   */
  flipX() {
    const x = _area.get(this).width * -1;
    const y = 0;
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setScale(-1, 1);
    tfm.setTranslate(x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Performs a vertical flip.
   */
  flipY() {
    const x = 0;
    const y = _area.get(this).height * -1;
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setScale(1, -1);
    tfm.setTranslate(x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Moves along the axis
   * @param {?number} x - The x-axis position
   * @param {?number} y - The y-axis position
   */
  translate(x, y) {
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setTranslate(x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Cleans the component before its destruction.
   */
  remove() {
    this.clear();
    _owner.delete(this);
    _tfmList.delete(this);
    _area.delete(this);
  }

}

export default Transform;
<commit_msg>Fix problem with flipX and flipY transformations<commit_after>import {InvalidElement} from "../errors.js";

// Private attributes
const _owner = new WeakMap();
const _tfmList = new WeakMap();
const _area = new WeakMap();

/**
 * The Transform class is in charge of the effects applied to components.
 */
class Transform {

  /**
   * @param {SVGElement} svgElement - The element to which apply the transformations.
   * @throws {InvalidElement} When the `svgElement` argument is wrong or not transformable.
   */
  constructor(svgElement) {
    if (!svgElement.viewportElement) {
      throw new InvalidElement("A not `viewport` SVGElement");
    }

    _owner.set(this, svgElement.ownerSVGElement);
    _tfmList.set(this, svgElement.transform.baseVal);
    _area.set(this, svgElement.viewportElement.viewBox.baseVal);
  }

  /**
   * Clear all the transformations applied to the svg element.
   */
  clear() {
    _tfmList.get(this).clear();
  }

  /**
   * Performs a rotation about a given point.
   * @param {!number} a - The rotate angle degrees.
   * @param {?number} x - The x-axis position
   * @param {?number} y - The y-axis position
   */
  rotate(a, x, y) {
    x = x || _area.get(this).width / 2;
    y = y || _area.get(this).height / 2;
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setRotate(a, x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Performs a horizontal flip.
   */
  flipX() {
    const x = _area.get(this).width * -1;
    const y = 0;
    const tfm1 = _owner.get(this).createSVGTransform();
    const tfm2 = _owner.get(this).createSVGTransform();
    const tfmList = _tfmList.get(this);

    tfm1.setScale(-1, 1);
    tfmList.appendItem(tfm1);
    tfm2.setTranslate(x, y);
    tfmList.appendItem(tfm2);
  }

  /**
   * Performs a vertical flip.
   */
  flipY() {
    const x = 0;
    const y = _area.get(this).height * -1;
    const tfm1 = _owner.get(this).createSVGTransform();
    const tfm2 = _owner.get(this).createSVGTransform();
    const tfmList = _tfmList.get(this);

    tfm1.setScale(1, -1);
    tfmList.appendItem(tfm1);
    tfm2.setTranslate(x, y);
    tfmList.appendItem(tfm2);
  }

  /**
   * Moves along the axis
   * @param {?number} x - The x-axis position
   * @param {?number} y - The y-axis position
   */
  translate(x, y) {
    const tfm = _owner.get(this).createSVGTransform();
    tfm.setTranslate(x, y);
    _tfmList.get(this).appendItem(tfm);
  }

  /**
   * Cleans the component before its destruction.
   */
  remove() {
    this.clear();
    _owner.delete(this);
    _tfmList.delete(this);
    _area.delete(this);
  }

}

export default Transform;
<|endoftext|>


<commit_before>$.panels = (function($, window, document, undefined) {
    var containerID = '#panels-container',
        wrapperID = '#panels-wrapper',
        panelClass = '.panel',
        container, // Container that holds the wrapper
        wrapper, // Wrapper that contains the panels
        panels, // jQuery-wrapped array of the panels
        columns, // An array of the panels, grouped by column
        margin = {}, // Stores margin.top and margin.left of the first panel in the lists
        wrapperHeight, // The current height of the wrapper
        lastHeight, // The previous height of the wrapper
        initialized = false,
        allWidth = 0, // The grand total width of all of the panels (and their margins)
        groupedWidth, // The width of the current columnized layout
        lastGroupedWidth, // The previous width of the columnized layout
        resizing, // setTimeout that handles the onResize delay
        delay = 333, // setting for how long to wait before reflowing after resize
        duration = 500, // how long each reflow should take (ms)
        resizeTimeout; // The timeout to delay the resizing of the wrapper

    var init = function(options) {
        containerID = options.containerID || containerID;
        wrapperID = options.wrapperID || wrapperID;
        panelClass = options.panelClass || panelClass;

        container = $(containerID);
        wrapper = $(wrapperID);
        panels = $(containerID).find(wrapperID).find(panelClass); // Endure that the panels are located properly

        // If the mousewheel plugin is supplied, use it
        if ($().mousewheel) {
            container.mousewheel(function(e, delta) {
                if (Math.abs(e.deltaX)) {
                    this.scrollLeft -= (e.deltaX * 100);
                } else {
                    this.scrollLeft -= (e.deltaY * 100);
                }
                e.preventDefault();
            });
        }

        // TODO Fix CSS of panels -- should be display: block; float: left; transition: margin 500ms ease;
        // and make sure the wrapper and container are have the right CSS
        // use duration

        // Ensure that panels and wrapper are found
        if (!panels.length && !wrapper.lenth) throw ['Panels could not be initialized.', panels, wrapper].join(' ');

        margin.top = parseInt($(panelClass).css('margin-top'));
        margin.left = parseInt($(panelClass).css('margin-left'));

        // Set data to be used in relayout
        panels.each(function() {
            $(this).data('height', $(this).height())
                .data('width', $(this).width());
            allWidth += $(this).data('width') + (margin.left * 2);
            // Reset margins
            $(this).css({
                marginRight: 0,
                marginBottom: 0,
            });
        });

        lastHeight = wrapper.height() - margin.top;

        updateOnResize(options.onResize || options.onResize === undefined);
        return initialized = true;
    }

    // Go through the list of panels and group them into colums with a total height
    // of equal or less than the wrapper. Fits as many panels as possible into each
    // column, each of which is an array.
    // Return: False if the wrapper height has not changed, or if the new columns
    //         are all the same length of the pregrouping is the same
    var panelsToColumns = function() {
        if (wrapper.height() === wrapperHeight - margin.top) {
            return false;
        } else {
            wrapperHeight = wrapper.height() - margin.top;
        }

        var newCols = [];
        var layoutWidth = margin.left,
            currentWidth = 0,
            lastGroupedWidth = 0;

        // Need a holder for each column and a way to track the amassed height
        for (var i = 0, currentGroup = [], runningHeight = 0, panelLength = panels.length; i < panelLength; i++) {

            if ($(panels[i]).data('height') + margin.top + runningHeight > wrapperHeight && i > 0) { // not on the first one
                // we're done here, push the column and clear our holders
                newCols.push(currentGroup);
                layoutWidth += currentWidth;
                currentGroup = [];
                runningHeight = 0;
                currentWidth = 0;
            }

            currentGroup.push(panels[i]);
            runningHeight += $(panels[i]).data('height') + margin.top;

            var panelWidth = $(panels[i]).data('width') + (margin.left) // Calculate the width of the current panel
            if (panelWidth > currentWidth) currentWidth = panelWidth; // Take the widest panel in the current column
        }
        layoutWidth += currentWidth; // For the last panel
        newCols.push(currentGroup);

        // This compares the stored columns and the new newCols, column by column,
        // to see if the elements are changed, returns true if they are changed,
        // and false if they are not.
        // If there are the same number of columns, the layout might be the same
        if (columns && columns.length === newCols.length) {
            for (var j = 0; j < columns.length; j++) {
                if (columns[j].length !== newCols[j].length) return columns = newCols, lastGroupedWidth = groupedWidth, groupedWidth = layoutWidth; // If the column has a different number of panels, layout is changed
            }
        } else {
            return columns = newCols, lastGroupedWidth = groupedWidth, groupedWidth = layoutWidth;
        }
        return false; // There is no previous columns array built, or the new and old ones are the same
    }

    // Redo the layout of the panels

    var doLayout = function() {

        clearTimeout(resizeTimeout);

        // No combination of these seemed to keep it from flickering
        // var tempWidth = Math.max(lastGroupedWidth, groupedWidth);
        // tempWidth     = Math.min(allWidth, tempWidth * 2);
        wrapper.width(allWidth); // Give the panels enough space to keep them from jumping to the next row

        resizeTimeout = setTimeout(function() {
            wrapper.animate({
                'width': groupedWidth
            }, duration);
        }, duration / 2) // Delays the resize wrt. the proportion of the full width

        for (var i = 0, columnsLength = columns.length; i < columnsLength; i++) {

            // $(columns[i][0]).animate({
            //     'margin-top': margin.top,
            //     'margin-left': margin.left
            // }, duration);

            $(columns[i][0]).animate({
                marginTop: margin.top,
            }, duration / parseInt($(columns[i][0]).css('margin-top'))).animate({
                marginLeft: margin.left
            }, duration / parseInt($(columns[i][0]).css('margin-left')));

            var prevTopMargin = 0 // margin.top; again, to make the inner margins match the top and left margins
            for (var j = 1, columnLength = columns[i].length; j < columnLength; j++) {

                var thisPanelWidth = $(columns[i][j]).data('width') + (margin.left * 2);

                var thisTopMargin = $(columns[i][j - 1]).data('height') + (margin.top * 2) + prevTopMargin;
                prevTopMargin = thisTopMargin - margin.top;

                // $(columns[i][j]).animate({
                //     'margin-top': thisTopMargin,
                //     'margin-left': -$(columns[i][j - 1]).data('width') // - (margin.left) // this is not needed if the panel-inner margin is to match the margin it makes with the wrapper
                // }, duration);

                $(columns[i][j]).animate({
                    marginTop: thisTopMargin,
                }, duration / thisTopMargin).animate({
                    marginLeft: -$(columns[i][j - 1]).data('width')
                }, duration / $(columns[i][j - 1]).data('width'))
            }
        }
    };

    var updateOnResize = function() {
        $(window).resize(function() {
            clearTimeout(resizing);
            resizing = setTimeout(function() {
                if (panelsToColumns()) {

                    doLayout();
                    lastHeight = wrapperHeight;
                }
            }, delay);
        });
    };

    // Options is an initializer object with the following optional parameters
    //    containerID:    a hash-prefixed string specifying the ID of the panels continer
    //    wrapperID:      same as above, but for the wrapper
    //    panelClass:     class name for the panels
    //    reinitialize:   whether or not to throw out the stored data and refresh
    //    onResize:       whether or not to update the layout on resize
    //    delay:    how long to wait after resize starts to redo the layout
    //    duration: how long each element should take to move into place
    // TODO: Use $.fn.extend() and make this callable on the container
    return function(options) {
        if (!initialized || (options.hasOwnProperty('reinitialize') && options.reinitialize)) init(options);

        if (panelsToColumns()) {
            doLayout(true);
        }
        return $;
    }

})(jQuery, window, document);
<commit_msg>Finally squashed the animation bug<commit_after>$.panels = (function($, window, document, undefined) {
    var containerID = '#panels-container',
        wrapperID = '#panels-wrapper',
        panelClass = '.panel',
        container, // Container that holds the wrapper
        wrapper, // Wrapper that contains the panels
        panels, // jQuery-wrapped array of the panels
        columns, // An array of the panels, grouped by column
        margin = {}, // Stores margin.top and margin.left of the first panel in the lists
        wrapperHeight, // The current height of the wrapper
        lastHeight, // The previous height of the wrapper
        initialized = false,
        allWidth = 0, // The grand total width of all of the panels (and their margins)
        groupedWidth, // The width of the current columnized layout
        lastGroupedWidth, // The previous width of the columnized layout
        resizing, // setTimeout that handles the onResize delay
        delay = 333, // setting for how long to wait before reflowing after resize
        duration = 500, // how long each reflow should take (ms)
        resizeTimeout; // The timeout to delay the resizing of the wrapper

    var init = function(options) {
        containerID = options.containerID || containerID;
        wrapperID = options.wrapperID || wrapperID;
        panelClass = options.panelClass || panelClass;

        container = $(containerID);
        wrapper = $(wrapperID);
        panels = $(containerID).find(wrapperID).find(panelClass); // Endure that the panels are located properly

        // If the mousewheel plugin is supplied, use it
        if ($().mousewheel) {
            container.mousewheel(function(e, delta) {
                if (Math.abs(e.deltaX)) {
                    this.scrollLeft -= (e.deltaX * 100);
                } else {
                    this.scrollLeft -= (e.deltaY * 100);
                }
                e.preventDefault();
            });
        }

        // TODO Fix CSS of panels -- should be display: block; float: left; transition: margin 500ms ease;
        // and make sure the wrapper and container are have the right CSS
        // use duration

        // Ensure that panels and wrapper are found
        if (!panels.length && !wrapper.lenth) throw ['Panels could not be initialized.', panels, wrapper].join(' ');

        margin.top = parseInt($(panelClass).css('margin-top'));
        margin.left = parseInt($(panelClass).css('margin-left'));

        // Set data to be used in relayout
        panels.each(function() {
            $(this).data('height', $(this).height())
                .data('width', $(this).width());
            allWidth += $(this).data('width') + (margin.left * 2);
            // Reset margins
            $(this).css({
                marginRight: 0,
                marginBottom: 0,
            });
        });

        lastHeight = wrapper.height() - margin.top;

        updateOnResize(options.onResize || options.onResize === undefined);
        return initialized = true;
    }

    // Go through the list of panels and group them into colums with a total height
    // of equal or less than the wrapper. Fits as many panels as possible into each
    // column, each of which is an array.
    // Return: False if the wrapper height has not changed, or if the new columns
    //         are all the same length of the pregrouping is the same
    var panelsToColumns = function() {
        if (wrapper.height() === wrapperHeight - margin.top) {
            return false;
        } else {
            wrapperHeight = wrapper.height() - margin.top;
        }

        var newCols = [];
        var layoutWidth = margin.left,
            currentWidth = 0,
            lastGroupedWidth = 0;

        // Need a holder for each column and a way to track the amassed height
        for (var i = 0, currentGroup = [], runningHeight = 0, panelLength = panels.length; i < panelLength; i++) {

            if ($(panels[i]).data('height') + margin.top + runningHeight > wrapperHeight && i > 0) { // not on the first one
                // we're done here, push the column and clear our holders
                newCols.push(currentGroup);
                layoutWidth += currentWidth;
                currentGroup = [];
                runningHeight = 0;
                currentWidth = 0;
            }

            currentGroup.push(panels[i]);
            runningHeight += $(panels[i]).data('height') + margin.top;

            var panelWidth = $(panels[i]).data('width') + (margin.left) // Calculate the width of the current panel
            if (panelWidth > currentWidth) currentWidth = panelWidth; // Take the widest panel in the current column
        }
        layoutWidth += currentWidth; // For the last panel
        newCols.push(currentGroup);

        // This compares the stored columns and the new newCols, column by column,
        // to see if the elements are changed, returns true if they are changed,
        // and false if they are not.
        // If there are the same number of columns, the layout might be the same
        if (columns && columns.length === newCols.length) {
            for (var j = 0; j < columns.length; j++) {
                if (columns[j].length !== newCols[j].length) return columns = newCols, lastGroupedWidth = groupedWidth, groupedWidth = layoutWidth; // If the column has a different number of panels, layout is changed
            }
        } else {
            return columns = newCols, lastGroupedWidth = groupedWidth, groupedWidth = layoutWidth;
        }
        return false; // There is no previous columns array built, or the new and old ones are the same
    }

    // Redo the layout of the panels

    var doLayout = function() {

        clearTimeout(resizeTimeout);

        // No combination of these seemed to keep it from flickering
        // var tempWidth = Math.max(lastGroupedWidth, groupedWidth);
        // tempWidth     = Math.min(allWidth, tempWidth * 2);
        wrapper.width(allWidth); // Give the panels enough space to keep them from jumping to the next row

        resizeTimeout = setTimeout(function() {
            wrapper.animate({
                'width': groupedWidth
            }, duration);
        }, duration / 2) // Delays the resize wrt. the proportion of the full width

        for (var i = 0, columnsLength = columns.length; i < columnsLength; i++) {

            // $(columns[i][0]).animate({
            //     'margin-top': margin.top,
            //     'margin-left': margin.left
            // }, duration);

            $(columns[i][0]).animate({
                marginTop: margin.top,
                marginLeft: margin.left
            }, duration);

            var prevTopMargin = 0 // margin.top; again, to make the inner margins match the top and left margins
            for (var j = 1, columnLength = columns[i].length; j < columnLength; j++) {

                var thisPanelWidth = $(columns[i][j]).data('width') + (margin.left * 2);

                var thisTopMargin = $(columns[i][j - 1]).data('height') + (margin.top * 2) + prevTopMargin;
                prevTopMargin = thisTopMargin - margin.top;

                // $(columns[i][j]).animate({
                //     'margin-top': thisTopMargin,
                //     'margin-left': -$(columns[i][j - 1]).data('width') // - (margin.left) // this is not needed if the panel-inner margin is to match the margin it makes with the wrapper
                // }, duration);

                $(columns[i][j]).animate({
                    marginTop: thisTopMargin,
                    marginLeft: -$(columns[i][j - 1]).data('width')
                }, duration);
            }
        }
    };

    var updateOnResize = function() {
        $(window).resize(function() {
            clearTimeout(resizing);
            resizing = setTimeout(function() {
                if (panelsToColumns()) {

                    doLayout();
                    lastHeight = wrapperHeight;
                }
            }, delay);
        });
    };

    // Options is an initializer object with the following optional parameters
    //    containerID:    a hash-prefixed string specifying the ID of the panels continer
    //    wrapperID:      same as above, but for the wrapper
    //    panelClass:     class name for the panels
    //    reinitialize:   whether or not to throw out the stored data and refresh
    //    onResize:       whether or not to update the layout on resize
    //    delay:    how long to wait after resize starts to redo the layout
    //    duration: how long each element should take to move into place
    // TODO: Use $.fn.extend() and make this callable on the container
    return function(options) {
        if (!initialized || (options.hasOwnProperty('reinitialize') && options.reinitialize)) init(options);

        if (panelsToColumns()) {
            doLayout(true);
        }
        return $;
    }

})(jQuery, window, document);
<|endoftext|>