<commit_before>/**
 * This file is part of Wizkers.io
 *
 * The MIT License (MIT)
 *  Copyright (c) 2016 Edouard Lafargue, ed@wizkers.io
 *
 * 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.
 */

// This detects whether we are in a server situation and act accordingly:
if (typeof define !== 'function') {
    var define = require('amdefine')(module);
    var vizapp = { type: 'server'},
    DataView = require('buffer-dataview'), // Important for compatibility
    events = require('events'),
    dbs = require('pouch-config');
}

define(function (require) {
    "use strict";

    var Serialport = require('serialport'), // Used for parsing only
        abutils = require('app/lib/abutils'),
        btleConnection = require('connections/btle');

    var parser = function (socket) {

        var self = this,
            socket = socket,
            streaming = true,
            port = null,
            port_close_requested = false,
            port_open_requested = false,
            isopen = false;

        // We have to have those in lowercase
        var KESTREL_SERVICE_UUID  = '03290000-eab4-dea1-b24e-44ec023874db';
        var WX1_UUID     = '03290310-eab4-dea1-b24e-44ec023874db';
        var WX2_UUID     = '03290320-eab4-dea1-b24e-44ec023874db';
        var WX3_UUID     = '03290330-eab4-dea1-b24e-44ec023874db';

        // small utility to convert DDMM.MMM or DDDMM.MMM to decimal
        var parseDecDeg = function (c, hemi) {
            var i = c.indexOf('.');
            var deg = c.substring(0, i - 2);
            var decMin = c.substring(i - 2, c.length - 1);
            var decDeg = parseInt(deg, 10) + (decMin / 60);
            if (hemi === 'W' || hemi === 'S')
                decDeg *= -1;
            return decDeg;
        };

        /////////////
        // Private methods
        /////////////

        var portSettings = function () {
            return {
                service_uuid: KESTREL_SERVICE_UUID,
                characteristic_uuid: WX1_UUID
            }
        };

        // Format can act on incoming data from the device, and then
        // forwards the data to the app through a 'data' event.
        var format = function (data) {
            if (!data.value || !data.uuid) {
                debug('No value or uuid received');
                return;
            }
            console.log(data);
            var dv = new DataView(data.value);
            if (data.uuid ==  WX1_UUID.replace(/-/gi,'')) {
                var windspeed = dv.getInt16(0, true);
                var temp = dv.getInt16(2, true);
                var rh = dv.getInt16(6, true);
                var pressure = dv.getInt16(8,true);
                var compass = dv.getInt16(10,true);

                var jsresp = {
                    temperature: temp/100,
                    rel_humidity: rh/100,
                    pressure: pressure/10,
                    compass_mag: compass,
                    wind: { dir: compass, speed: windspeed/1000},
                    unit: {
                        temperature: 'celsius',
                        rel_humidity: '%',
                        barometer: 'mb',
                        compass_mag: 'degree',
                        wind: { dir: 'degree', speed: 'm/s'}
                    }
                };

                // debug(jsresp);
                self.trigger('data', jsresp);
                return;
            }

            if (data.uuid ==  WX2_UUID.replace(/-/gi,'')) {
                var compass2 = dv.getInt16(0, true);
                // Todo: byte 6 is probably part of altitude
                var altitude = dv.getInt16(4, true);
                var barometer = dv.getInt16(7, true);
                var dens_altitude = dv.getInt16(14, true);
                var xwind = dv.getInt16(9, true);
                var hwind = dv.getInt16(11, true);

                var jsresp = {
                    compass_true: compass2,
                    altitude: altitude/10,
                    dens_altitude: dens_altitude/10,
                    barometer: barometer /10,
                    crosswind: xwind/1000,
                    headwind: hwind/1000,

                    unit: {
                        compass2: 'degree',
                        altitude: 'm',
                        dens_altitude: 'm',
                        barometer: 'mb',
                        crosswind: 'm/s',
                        headwind: 'm/s'

                    }
                };

                // debug(jsresp);
                self.trigger('data', jsresp);
                return;
            }

            if (data.uuid ==  WX3_UUID.replace(/-/gi,'')) {
                var dew_point = dv.getInt16(0, true);
                var heat_index = dv.getInt16(2, true);
                var wetbulb = dv.getInt16(16, true);
                var chill = dv.getInt16(18, true);

                var jsresp = {
                    dew_point: dew_point/100,
                    heat_index: heat_index/100,
                    wetbulb: wetbulb/100,
                    wind_chill: chill,
                    unit: {
                        dew_point: 'celsius',
                        heat_index: 'celsius',
                        wetbulb: 'celsius',
                        wind_chill: 'celsius'

                    }
                };
                self.trigger('data', jsresp);
                return;
            }
        };

        // Status returns an object that is concatenated with the
        // global server status
        var status = function (stat) {
            port_open_requested = false;
            console.log('Port status change', stat);
            if (stat.openerror) {
                // We could not open the port: warn through
                // a 'data' messages
                var resp = {
                    openerror: true
                };
                if (stat.reason != undefined)
                    resp.reason = stat.reason;
                if (stat.description != undefined)
                    resp.description = stat.description;
                self.trigger('data', resp);
                return;
            }
            if (stat.reconnecting != undefined) {
                // Forward the message to front-end
                self.trigger('data', {reconnecting:stat.reconnecting});
                return;
            }
            isopen = stat.portopen;
            if (isopen && stat.services) {
                // Should run any "onOpen" initialization routine here if
                // necessary.
                console.log('We found those services', stat.services);
                // ToDo: depending on the services we found, we can subscribe
                // to different service/characteristic UUIDs so that we can support
                // multiple versions of the Bluetooth module.
                port.subscribe({
                    service_uuid: KESTREL_SERVICE_UUID,
                    characteristic_uuid: [ WX1_UUID, WX2_UUID, WX3_UUID ]
                });
                // We remove the listener so that the serial port can be GC'ed
                if (port_close_requested) {
                    if (port.off)
                        port.off('status', status);
                    else
                        port.removeListener('status', status);

                    port_close_requested = false;
                }
            }
        };

        var openPort_app = function (insid) {
            port_open_requested = true;
            var ins = instrumentManager.getInstrument();
            port = new btleConnection(ins.get('port'), portSettings());
            port.open();
            port.on('data', format);
            port.on('status', status);
        };

        var openPort_server = function(insid) {
            dbs.instruments.get(insid, function(err,item) {
                port = new btleConnection(item.port, portSettings());
                port.on('data', format);
                port.on('status', status);
                port.open();
            });
        };

        /////////////
        // Public methods
        /////////////

        this.openPort = function (insid) {
            port_open_requested = true;
            if (vizapp.type == 'server') {
                openPort_server(insid);
            } else {
                openPort_app(insid);
            }
        };

        this.closePort = function (data) {
            // We need to remove all listeners otherwise the serial port
            // will never be GC'ed
            if (port.off)
                port.off('data', format);
            else
                port.removeListener('data', format);
            port_close_requested = true;
            port.close();
        }

        this.isOpen = function () {
            return isopen;
        }

        this.isOpenPending = function () {
            return port_open_requested;
        }

        this.getInstrumentId = function (arg) {};

        this.isStreaming = function () {
            return streaming;
        };

        // Called when the app needs a unique identifier.
        // this is a standardized call across all drivers.
        //
        // TODO: Returns the instrument GUID.
        this.sendUniqueID = function () {};

        // period in seconds
        this.startLiveStream = function (period) {};

        this.stopLiveStream = function (args) {};

        // output should return a string, and is used to format
        // the data that is sent on the serial port, coming from the
        // HTML interface.
        this.output = function (data) {
            //console.log('TX', data);
            port.write(data);
        };

        /**
         *This is called by the serial parser (see 'format' above)
         * For some mysterious reason, the bGeigie outputs an NMEA-like
         * sentence, which is very 90's like, but mostly a pain.
         *
         * The Safecast API wants this NMEA data, so we will keep it intact
         * in our own database for easy log export, but add a JSON copy for
         * ease of use for a couple of fields.
         */
        this.onDataReady = function (data) {
            // Remove any carriage return
            data = data.replace('\r\n', '');
            var fields = data.split(',');
            if (fields[0] != '$BNRDD') {
                console.log('Unknown bGeigie sentence');
                self.trigger('data', { error: "Err. Data" });
                return;
            }

            // Since we have a checksum, check it
            var chk = 0;
            for (var i = 1; i < data.indexOf('*'); i++) {
                chk = chk ^ data.charCodeAt(i);
            }
            var sum = parseInt(data.substr(data.indexOf('*')+1), 16);
            if ( chk != sum) {
                self.trigger('data', { error: "Err. Checksum" });
                return;
            }

            var cpm = parseInt(fields[3]);
            var lat = parseDecDeg(fields[7], fields[8]);
            var lng = parseDecDeg(fields[9], fields[10]);
            var sats = parseInt(fields[13]);

            var response = {
                cpm: {
                    value: cpm,
                    count: parseInt(fields[5]),
                    usv: cpm * conversionCoefficient,
                    valid: fields[6] == 'A'
                },
                nmea: data,
                batt_ok: false,
                loc: {
                    coords: {
                        latitude: lat,
                        longitude: lng
                    },
                    sats: sats
                },
                loc_status: (fields[12] == 'A') ? 'OK' : 'No GPS Lock'
            };

            self.trigger('data', response);
        };
    }

    // On server side, we use the Node eventing system, whereas on the
    // browser/app side, we use Bacbone's API:
    if (vizapp.type != 'server') {
        // Add event management to our parser, from the Backbone.Events class:
        _.extend(parser.prototype, Backbone.Events);
    } else {
        parser.prototype.__proto__ = events.EventEmitter.prototype;
        parser.prototype.trigger = parser.prototype.emit;
    }
    return parser;
});<commit_msg>Kestrel5: correct wind chill factor<commit_after>/**
 * This file is part of Wizkers.io
 *
 * The MIT License (MIT)
 *  Copyright (c) 2016 Edouard Lafargue, ed@wizkers.io
 *
 * 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.
 */

// This detects whether we are in a server situation and act accordingly:
if (typeof define !== 'function') {
    var define = require('amdefine')(module);
    var vizapp = { type: 'server'},
    DataView = require('buffer-dataview'), // Important for compatibility
    events = require('events'),
    dbs = require('pouch-config');
}

define(function (require) {
    "use strict";

    var Serialport = require('serialport'), // Used for parsing only
        abutils = require('app/lib/abutils'),
        btleConnection = require('connections/btle');

    var parser = function (socket) {

        var self = this,
            socket = socket,
            streaming = true,
            port = null,
            port_close_requested = false,
            port_open_requested = false,
            isopen = false;

        // We have to have those in lowercase
        var KESTREL_SERVICE_UUID  = '03290000-eab4-dea1-b24e-44ec023874db';
        var WX1_UUID     = '03290310-eab4-dea1-b24e-44ec023874db';
        var WX2_UUID     = '03290320-eab4-dea1-b24e-44ec023874db';
        var WX3_UUID     = '03290330-eab4-dea1-b24e-44ec023874db';

        // small utility to convert DDMM.MMM or DDDMM.MMM to decimal
        var parseDecDeg = function (c, hemi) {
            var i = c.indexOf('.');
            var deg = c.substring(0, i - 2);
            var decMin = c.substring(i - 2, c.length - 1);
            var decDeg = parseInt(deg, 10) + (decMin / 60);
            if (hemi === 'W' || hemi === 'S')
                decDeg *= -1;
            return decDeg;
        };

        /////////////
        // Private methods
        /////////////

        var portSettings = function () {
            return {
                service_uuid: KESTREL_SERVICE_UUID,
                characteristic_uuid: WX1_UUID
            }
        };

        // Format can act on incoming data from the device, and then
        // forwards the data to the app through a 'data' event.
        var format = function (data) {
            if (!data.value || !data.uuid) {
                debug('No value or uuid received');
                return;
            }
            console.log(data);
            var dv = new DataView(data.value);
            if (data.uuid ==  WX1_UUID.replace(/-/gi,'')) {
                var windspeed = dv.getInt16(0, true);
                var temp = dv.getInt16(2, true);
                var rh = dv.getInt16(6, true);
                var pressure = dv.getInt16(8,true);
                var compass = dv.getInt16(10,true);

                var jsresp = {
                    temperature: temp/100,
                    rel_humidity: rh/100,
                    pressure: pressure/10,
                    compass_mag: compass,
                    wind: { dir: compass, speed: windspeed/1000},
                    unit: {
                        temperature: 'celsius',
                        rel_humidity: '%',
                        barometer: 'mb',
                        compass_mag: 'degree',
                        wind: { dir: 'degree', speed: 'm/s'}
                    }
                };

                // debug(jsresp);
                self.trigger('data', jsresp);
                return;
            }

            if (data.uuid ==  WX2_UUID.replace(/-/gi,'')) {
                var compass2 = dv.getInt16(0, true);
                // Todo: byte 6 is probably part of altitude
                var altitude = dv.getInt16(4, true);
                var barometer = dv.getInt16(7, true);
                var dens_altitude = dv.getInt16(14, true);
                var xwind = dv.getInt16(9, true);
                var hwind = dv.getInt16(11, true);

                var jsresp = {
                    compass_true: compass2,
                    altitude: altitude/10,
                    dens_altitude: dens_altitude/10,
                    barometer: barometer /10,
                    crosswind: xwind/1000,
                    headwind: hwind/1000,

                    unit: {
                        compass2: 'degree',
                        altitude: 'm',
                        dens_altitude: 'm',
                        barometer: 'mb',
                        crosswind: 'm/s',
                        headwind: 'm/s'

                    }
                };

                // debug(jsresp);
                self.trigger('data', jsresp);
                return;
            }

            if (data.uuid ==  WX3_UUID.replace(/-/gi,'')) {
                var dew_point = dv.getInt16(0, true);
                var heat_index = dv.getInt16(2, true);
                var wetbulb = dv.getInt16(16, true);
                var chill = dv.getInt16(18, true);

                var jsresp = {
                    dew_point: dew_point/100,
                    heat_index: heat_index/100,
                    wetbulb: wetbulb/100,
                    wind_chill: chill/100,
                    unit: {
                        dew_point: 'celsius',
                        heat_index: 'celsius',
                        wetbulb: 'celsius',
                        wind_chill: 'celsius'

                    }
                };
                self.trigger('data', jsresp);
                return;
            }
        };

        // Status returns an object that is concatenated with the
        // global server status
        var status = function (stat) {
            port_open_requested = false;
            console.log('Port status change', stat);
            if (stat.openerror) {
                // We could not open the port: warn through
                // a 'data' messages
                var resp = {
                    openerror: true
                };
                if (stat.reason != undefined)
                    resp.reason = stat.reason;
                if (stat.description != undefined)
                    resp.description = stat.description;
                self.trigger('data', resp);
                return;
            }
            if (stat.reconnecting != undefined) {
                // Forward the message to front-end
                self.trigger('data', {reconnecting:stat.reconnecting});
                return;
            }
            isopen = stat.portopen;
            if (isopen && stat.services) {
                // Should run any "onOpen" initialization routine here if
                // necessary.
                console.log('We found those services', stat.services);
                // ToDo: depending on the services we found, we can subscribe
                // to different service/characteristic UUIDs so that we can support
                // multiple versions of the Bluetooth module.
                port.subscribe({
                    service_uuid: KESTREL_SERVICE_UUID,
                    characteristic_uuid: [ WX1_UUID, WX2_UUID, WX3_UUID ]
                });
                // We remove the listener so that the serial port can be GC'ed
                if (port_close_requested) {
                    if (port.off)
                        port.off('status', status);
                    else
                        port.removeListener('status', status);

                    port_close_requested = false;
                }
            }
        };

        var openPort_app = function (insid) {
            port_open_requested = true;
            var ins = instrumentManager.getInstrument();
            port = new btleConnection(ins.get('port'), portSettings());
            port.open();
            port.on('data', format);
            port.on('status', status);
        };

        var openPort_server = function(insid) {
            dbs.instruments.get(insid, function(err,item) {
                port = new btleConnection(item.port, portSettings());
                port.on('data', format);
                port.on('status', status);
                port.open();
            });
        };

        /////////////
        // Public methods
        /////////////

        this.openPort = function (insid) {
            port_open_requested = true;
            if (vizapp.type == 'server') {
                openPort_server(insid);
            } else {
                openPort_app(insid);
            }
        };

        this.closePort = function (data) {
            // We need to remove all listeners otherwise the serial port
            // will never be GC'ed
            if (port.off)
                port.off('data', format);
            else
                port.removeListener('data', format);
            port_close_requested = true;
            port.close();
        }

        this.isOpen = function () {
            return isopen;
        }

        this.isOpenPending = function () {
            return port_open_requested;
        }

        this.getInstrumentId = function (arg) {};

        this.isStreaming = function () {
            return streaming;
        };

        // Called when the app needs a unique identifier.
        // this is a standardized call across all drivers.
        //
        // TODO: Returns the instrument GUID.
        this.sendUniqueID = function () {};

        // period in seconds
        this.startLiveStream = function (period) {};

        this.stopLiveStream = function (args) {};

        // output should return a string, and is used to format
        // the data that is sent on the serial port, coming from the
        // HTML interface.
        this.output = function (data) {
            //console.log('TX', data);
            port.write(data);
        };

        /**
         *This is called by the serial parser (see 'format' above)
         * For some mysterious reason, the bGeigie outputs an NMEA-like
         * sentence, which is very 90's like, but mostly a pain.
         *
         * The Safecast API wants this NMEA data, so we will keep it intact
         * in our own database for easy log export, but add a JSON copy for
         * ease of use for a couple of fields.
         */
        this.onDataReady = function (data) {
            // Remove any carriage return
            data = data.replace('\r\n', '');
            var fields = data.split(',');
            if (fields[0] != '$BNRDD') {
                console.log('Unknown bGeigie sentence');
                self.trigger('data', { error: "Err. Data" });
                return;
            }

            // Since we have a checksum, check it
            var chk = 0;
            for (var i = 1; i < data.indexOf('*'); i++) {
                chk = chk ^ data.charCodeAt(i);
            }
            var sum = parseInt(data.substr(data.indexOf('*')+1), 16);
            if ( chk != sum) {
                self.trigger('data', { error: "Err. Checksum" });
                return;
            }

            var cpm = parseInt(fields[3]);
            var lat = parseDecDeg(fields[7], fields[8]);
            var lng = parseDecDeg(fields[9], fields[10]);
            var sats = parseInt(fields[13]);

            var response = {
                cpm: {
                    value: cpm,
                    count: parseInt(fields[5]),
                    usv: cpm * conversionCoefficient,
                    valid: fields[6] == 'A'
                },
                nmea: data,
                batt_ok: false,
                loc: {
                    coords: {
                        latitude: lat,
                        longitude: lng
                    },
                    sats: sats
                },
                loc_status: (fields[12] == 'A') ? 'OK' : 'No GPS Lock'
            };

            self.trigger('data', response);
        };
    }

    // On server side, we use the Node eventing system, whereas on the
    // browser/app side, we use Bacbone's API:
    if (vizapp.type != 'server') {
        // Add event management to our parser, from the Backbone.Events class:
        _.extend(parser.prototype, Backbone.Events);
    } else {
        parser.prototype.__proto__ = events.EventEmitter.prototype;
        parser.prototype.trigger = parser.prototype.emit;
    }
    return parser;
});<|endoftext|>


<commit_before><commit_msg>$loaded is unreliable so going with a recursive retry<commit_after><|endoftext|>


<commit_before>"use strict";
var $ = document.getElementById.bind(document), shownNode, bgLink;
function decodeHash() {
  var url, type;
  url = location.hash;
  if (url.lastIndexOf("#!image=", 0) === 0) {
    url = url.substring(8);
    type = "image";
  } else {
    return;
  }
  try {
    url = decodeURIComponent(url);
  } catch (e) {}

  switch (type) {
  case "image":
    shownNode = $("shownImage");
    shownNode.src = url;
    shownNode.onclick = function() {
      clickLink(this.src, {
        target: "_blank"
      });
    };
    bgLink = $('bgLink');
    bgLink.setAttribute('data-vim-url', url);
    bgLink.style.display = "none";
    shownNode.onload = function() {
      bgLink.style.height = this.height + "px";
      bgLink.style.width = this.width + "px";
      bgLink.style.display = "";
      bgLink.onclick = function() {
        shownNode.click();
      };
    };
    shownNode.onerror = function() {
      setTimeout(function(){
        shownNode.onload();
      }, 34);
    }
    break;
  }

  if (shownNode) {
    shownNode.style.display = "";
  }
}

window.addEventListener("hashchange", decodeHash);
decodeHash();

window.addEventListener("keydown", function(event) {
  var str;
  if (!(event.ctrlKey || event.metaKey) || event.altKey
    || event.shiftKey || !shownNode) { return; }
  str = String.fromCharCode(event.keyCode);
  if (str === 'S') {
    if (str = shownNode.src) {
      event.preventDefault();
      clickLink(str, {
        download: ""
      });
    }
  }
});

function clickLink(url, options) {
  var a = document.createElement('a'), i;
  for (i in options) {
    a.setAttribute(i, options[i]);
  }
  a.href = url;
  a.click();
}

(function() {
  var a = document.createElement('script');
  a.src = '/lib/math_parser.js';
  document.head.appendChild(a);console.log(window.MathParser);

})();<commit_msg>revert the last commit partly: some code is for tests only<commit_after>"use strict";
var $ = document.getElementById.bind(document), shownNode, bgLink;
function decodeHash() {
  var url, type;
  url = location.hash;
  if (url.lastIndexOf("#!image=", 0) === 0) {
    url = url.substring(8);
    type = "image";
  } else {
    return;
  }
  try {
    url = decodeURIComponent(url);
  } catch (e) {}

  switch (type) {
  case "image":
    shownNode = $("shownImage");
    shownNode.src = url;
    shownNode.onclick = function() {
      clickLink(this.src, {
        target: "_blank"
      });
    };
    bgLink = $('bgLink');
    bgLink.setAttribute('data-vim-url', url);
    bgLink.style.display = "none";
    shownNode.onload = function() {
      bgLink.style.height = this.height + "px";
      bgLink.style.width = this.width + "px";
      bgLink.style.display = "";
      bgLink.onclick = function() {
        shownNode.click();
      };
    };
    shownNode.onerror = function() {
      setTimeout(function(){
        shownNode.onload();
      }, 34);
    }
    break;
  }

  if (shownNode) {
    shownNode.style.display = "";
  }
}

window.addEventListener("hashchange", decodeHash);
decodeHash();

window.addEventListener("keydown", function(event) {
  var str;
  if (!(event.ctrlKey || event.metaKey) || event.altKey
    || event.shiftKey || !shownNode) { return; }
  str = String.fromCharCode(event.keyCode);
  if (str === 'S') {
    if (str = shownNode.src) {
      event.preventDefault();
      clickLink(str, {
        download: ""
      });
    }
  }
});

function clickLink(url, options) {
  var a = document.createElement('a'), i;
  for (i in options) {
    a.setAttribute(i, options[i]);
  }
  a.href = url;
  a.click();
}
<|endoftext|>


<commit_before>import * as constants from "../Constants";

function articles(state = {}, action) {
    switch (action.type) {
        case constants.ADD_ARTICLES:
            state = [...state, ...action.payloads];
			return state;

        default:
            return state;
    }
}

export default articles;
<commit_msg>update: intialState type in articles reducer<commit_after>import * as constants from "../Constants";

function articles(state = [], action) {
    switch (action.type) {
        case constants.ADD_ARTICLES:
            state = [...state, ...action.payloads];
			return state;

        default:
            return state;
    }
}

export default articles;
<|endoftext|>


<commit_before>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'ngCordova'])

.run(function($ionicPlatform, Commons, LocalStorage) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleLightContent();
    }
    // cek user info in localstorage
    var userInfo = LocalStorage.getObject('userInfo');
    try {
      if ((!userInfo || !userInfo.mobile) && window.plugins.phonenumber) {
        window.plugins.phonenumber.get(function(res) {
          if (!userInfo) {
            userInfo = {mobile: res};
          } else {
            userInfo.mobile = res;
          }
          LocalStorage.setObject('userInfo', userInfo);
        });
      }
    } catch (err) {
      console.error(err);
      LocalStorage.setObject('userInfo', {});
    }
  });
})

.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
  .state('tab', {
    url: '/tab',
    abstract: true,
    templateUrl: 'templates/tabs.html'
  })

  // Each tab has its own nav history stack:

  // .state('tab.dash', {
  //   url: '/dash',
  //   views: {
  //     'tab-dash': {
  //       templateUrl: 'templates/tab-dash.html',
  //       controller: 'DashCtrl'
  //     }
  //   }
  // })
  //
  // .state('tab.chats', {
  //     url: '/chats',
  //     views: {
  //       'tab-chats': {
  //         templateUrl: 'templates/tab-chats.html',
  //         controller: 'ChatsCtrl'
  //       }
  //     }
  //   })
  //   .state('tab.chat-detail', {
  //     url: '/chats/:chatId',
  //     views: {
  //       'tab-chats': {
  //         templateUrl: 'templates/chat-detail.html',
  //         controller: 'ChatDetailCtrl'
  //       }
  //     }
  //   })

  /* Cek harga! */

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  })

  .state('tab.cek-harga', {
    url: '/cek-harga',
    views: {
      'tab-cek-harga': {
        templateUrl: 'templates/cek-harga.html',
        controller: 'CekHargaCtrl'
      }
    }
  })

  .state('tab.pos-harga', {
    url: '/pos-harga',
    views: {
      'tab-pos-harga': {
        templateUrl: 'templates/pos-harga.html',
        controller: 'PosHargaCtrl'
      }
    }
  })

  .state('tab.jual', {
    url: '/jual',
    views: {
      'tab-jual': {
        templateUrl: 'templates/tab-jual.html',
        controller: 'JualCtrl'
      }
    }
  })
  ;

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/cek-harga');

});
<commit_msg>remove unused code<commit_after>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'ngCordova'])

.run(function($ionicPlatform, Commons, LocalStorage) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleLightContent();
    }
    // cek user info in localstorage
    var userInfo = LocalStorage.getObject('userInfo');
    try {
      if ((!userInfo || !userInfo.mobile) && window.plugins.phonenumber) {
        window.plugins.phonenumber.get(function(res) {
          if (!userInfo) {
            userInfo = {mobile: res};
          } else {
            userInfo.mobile = res;
          }
          LocalStorage.setObject('userInfo', userInfo);
        });
      }
    } catch (err) {
      console.error(err);
      LocalStorage.setObject('userInfo', {});
    }
  });
})

.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider) {

  // set tabs to bottom
  //$ionicConfigProvider.tabs.position('bottom');

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
  .state('tab', {
    url: '/tab',
    abstract: true,
    templateUrl: 'templates/tabs.html'
  })

  /* Cek harga! */

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  })

  .state('tab.cek-harga', {
    url: '/cek-harga',
    views: {
      'tab-cek-harga': {
        templateUrl: 'templates/cek-harga.html',
        controller: 'CekHargaCtrl'
      }
    }
  })

  .state('tab.pos-harga', {
    url: '/pos-harga',
    views: {
      'tab-pos-harga': {
        templateUrl: 'templates/pos-harga.html',
        controller: 'PosHargaCtrl'
      }
    }
  })

  .state('tab.jual', {
    url: '/jual',
    views: {
      'tab-jual': {
        templateUrl: 'templates/tab-jual.html',
        controller: 'JualCtrl'
      }
    }
  })
  ;

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/cek-harga');

});
<|endoftext|>


<commit_before>var GridStatesManager = {
  // do ajax save
  saveStates: function(gridName, type, value){
    var url = "/wulin_master/grid_states/save",
    data = decodeURIComponent($.param({ grid_name: encodeURIComponent(gridName),
                                        state_type: encodeURIComponent(type),
                                        state_value: value,
                                        authenticity_token: window._token }));
    $.post(url, data, function(response){});
  },

  // grid events
  onStateEvents: function(grid) {
    var self = this;

    // save columns width when columns resized
    grid.onColumnsResized.subscribe(function(){
      var widthJson = {};
      $.each(this.getColumns(), function(index, column){
        widthJson[column.id] = column.width;
      });
      self.saveStates(grid.name, "width", widthJson);
    });

    // save columns sorting info when columns sorted
    grid.onSort.subscribe(function(e, args){
      var loader = grid.loader, sortJson = {};
      sortJson["sortCol"] = loader.getSortColumn();
      sortJson["sortDir"] = loader.getSortDirection();
      self.saveStates(grid.name, "sort", sortJson);
    });

    // save columns order when columns re-ordered
    grid.onColumnsReordered.subscribe(function(e, args){
      var orderJson = {};
      $.each(this.getColumns(), function(index, column){
        orderJson[index] = column.id;
      });

      self.saveStates(grid.name, "order", orderJson);
    });

    // save filter states when input filter value
    grid.filterPanel.onFilterLoaded.subscribe(function(e, args){
      var filterJson = {};
      $.each(args.filterData, function(index,data){
        filterJson[data['id']] = encodeURIComponent(data['value']);
      });
      self.saveStates(grid.name, "filter", filterJson);
    });

    // save columns visibility when pick columns
    if(grid.picker){
      grid.picker.onColumnsPick.subscribe(function(e, args){
        var visibilityJson = {};
        $.each(grid.getColumns(), function(index, column){
          visibilityJson[index] = column.id;
        });

        self.saveStates(grid.name, "visibility", visibilityJson);
      })
    }
  },

  // Restore columns order states
  restoreOrderStates: function(columns, orderStates){
	  if(!orderStates) return columns;

	  var new_columns = [], i, j, k;
    // find id column
    for(i in columns){
      if (columns[i].id == "id"){
        new_columns.push(columns[i]);
        break;
      }
    }
		// push other columns according to states
		for(j in orderStates){
		  for(k in columns) {
		    if(columns[k].id == orderStates[j]){
		      new_columns.push(columns[k]);
		      break;
		    }
		  }
		}
		// push columns that are not in the state in abritrary order
		for(i in columns) {
	    var found = false;
	    for(j in new_columns) {
	      if (columns[i].id == new_columns[j].id) {
	        found = true;
	      }
	    }
	    if (found==false) {
	      new_columns.push(columns[i]);
	    }
	  }
		return new_columns;
	},

	// Restore columns visibility states
	restoreVisibilityStates: function(columns, visibilityStates) {
	  if(!visibilityStates) return false;

	  // push visible columns according to states
	  for(var i in columns){
	    var visible = false;
	    for(var j in visibilityStates){
	      if(columns[i].id == visibilityStates[j]){
	        visible = true;
	        break;
	      }
	    }
	    columns[i].visible = visible;
	  }
	},

	// Restore columns width states
	restoreWidthStates: function(columns, widthStates) {
	  if(!widthStates) return false;

    // restore width
    for(var i in widthStates){
      for(var j in columns){
        if(columns[j].id == i){
          columns[j].width = parseInt(widthStates[i]);
          break;
        }
      }
    }
	},

	// Restore columns sorting states
	restoreSortingStates: function(grid, loader, sortingStates) {
	  if(sortingStates){
      grid.setSortColumn(sortingStates["sortCol"], sortingStates["sortDir"] == 1);
	    loader.setSort(sortingStates["sortCol"], sortingStates["sortDir"]);
	  }
	},

	// Apply current filters
	applayFilters: function(path, filterStates) {
	  if (filterStates) {
	    path = path.replace(/filters.*?&/g,'').replace(/&filters.*/g,'');
  	  $.each(filterStates, function(k, v){
  	    path += "&filters[][column]=" + k + "&filters[][value]=" + v;
  	  })
    }
	  return path;
	}

}

<commit_msg>MISC - check if grid.filterPanel exist or not<commit_after>var GridStatesManager = {
  // do ajax save
  saveStates: function(gridName, type, value){
    var url = "/wulin_master/grid_states/save",
    data = decodeURIComponent($.param({ grid_name: encodeURIComponent(gridName),
                                        state_type: encodeURIComponent(type),
                                        state_value: value,
                                        authenticity_token: window._token }));
    $.post(url, data, function(response){});
  },

  // grid events
  onStateEvents: function(grid) {
    var self = this;

    // save columns width when columns resized
    grid.onColumnsResized.subscribe(function(){
      var widthJson = {};
      $.each(this.getColumns(), function(index, column){
        widthJson[column.id] = column.width;
      });
      self.saveStates(grid.name, "width", widthJson);
    });

    // save columns sorting info when columns sorted
    grid.onSort.subscribe(function(e, args){
      var loader = grid.loader, sortJson = {};
      sortJson["sortCol"] = loader.getSortColumn();
      sortJson["sortDir"] = loader.getSortDirection();
      self.saveStates(grid.name, "sort", sortJson);
    });

    // save columns order when columns re-ordered
    grid.onColumnsReordered.subscribe(function(e, args){
      var orderJson = {};
      $.each(this.getColumns(), function(index, column){
        orderJson[index] = column.id;
      });

      self.saveStates(grid.name, "order", orderJson);
    });

    // save filter states when input filter value
    if(grid.filterPanel) {
      grid.filterPanel.onFilterLoaded.subscribe(function(e, args){
        var filterJson = {};
        $.each(args.filterData, function(index,data){
          filterJson[data['id']] = encodeURIComponent(data['value']);
        });
        self.saveStates(grid.name, "filter", filterJson);
      });
    }

    // save columns visibility when pick columns
    if(grid.picker){
      grid.picker.onColumnsPick.subscribe(function(e, args){
        var visibilityJson = {};
        $.each(grid.getColumns(), function(index, column){
          visibilityJson[index] = column.id;
        });

        self.saveStates(grid.name, "visibility", visibilityJson);
      })
    }
  },

  // Restore columns order states
  restoreOrderStates: function(columns, orderStates){
	  if(!orderStates) return columns;

	  var new_columns = [], i, j, k;
    // find id column
    for(i in columns){
      if (columns[i].id == "id"){
        new_columns.push(columns[i]);
        break;
      }
    }
		// push other columns according to states
		for(j in orderStates){
		  for(k in columns) {
		    if(columns[k].id == orderStates[j]){
		      new_columns.push(columns[k]);
		      break;
		    }
		  }
		}
		// push columns that are not in the state in abritrary order
		for(i in columns) {
	    var found = false;
	    for(j in new_columns) {
	      if (columns[i].id == new_columns[j].id) {
	        found = true;
	      }
	    }
	    if (found==false) {
	      new_columns.push(columns[i]);
	    }
	  }
		return new_columns;
	},

	// Restore columns visibility states
	restoreVisibilityStates: function(columns, visibilityStates) {
	  if(!visibilityStates) return false;

	  // push visible columns according to states
	  for(var i in columns){
	    var visible = false;
	    for(var j in visibilityStates){
	      if(columns[i].id == visibilityStates[j]){
	        visible = true;
	        break;
	      }
	    }
	    columns[i].visible = visible;
	  }
	},

	// Restore columns width states
	restoreWidthStates: function(columns, widthStates) {
	  if(!widthStates) return false;

    // restore width
    for(var i in widthStates){
      for(var j in columns){
        if(columns[j].id == i){
          columns[j].width = parseInt(widthStates[i]);
          break;
        }
      }
    }
	},

	// Restore columns sorting states
	restoreSortingStates: function(grid, loader, sortingStates) {
	  if(sortingStates){
      grid.setSortColumn(sortingStates["sortCol"], sortingStates["sortDir"] == 1);
	    loader.setSort(sortingStates["sortCol"], sortingStates["sortDir"]);
	  }
	},

	// Apply current filters
	applayFilters: function(path, filterStates) {
	  if (filterStates) {
	    path = path.replace(/filters.*?&/g,'').replace(/&filters.*/g,'');
  	  $.each(filterStates, function(k, v){
  	    path += "&filters[][column]=" + k + "&filters[][value]=" + v;
  	  })
    }
	  return path;
	}

}

<|endoftext|>


<commit_before>
function Tower(data) {
	this.id = data['id'];
	this.name = data['name'];
	this.coordinate = {
		latitude: parseFloat(data['latitude']),
		longitude: parseFloat(data['longitude'])
	}
	this.size = parseFloat(data['size']);
	this.player = data['player'];
	this.troops = JSON.parse(data['troops']);
}

Tower.prototype.get = function(attribute) {
	return this[attribute];
}

Tower.prototype.set = function(attribute, value) {
	this[attribute] = value;
}

Tower.prototype.getLat = function(){
	return this.coordinate.latitude;
}

Tower.prototype.getLon = function(){
	return this.coordinate.longitude;
}

Tower.prototype.toString = function(){
	return this.id + ': (' + this.getLat().toFixed(3) + ', ' + this.getLon().toFixed(3) + ', ' + this.size + ')'
}

Tower.prototype.toPresetHTML = function(){
	var html = '';
	html += '
' + this.size + '
';
	return html;
}

Tower.prototype.getCircle = function(){
	var circle = new H.map.Circle({
		lat: this.getLat(),
		lng: this.getLon()
	}, this.size);
	console.log(this.getLat() + " " + this.getLon())
	return circle;
}

var nick = new Tower({
	id: "1234",
	name:"Tower",
	latitude: "32",
	longitude: "-23.0",
	size: "5",
	player: "Nick",
	troops: "[1, 2, 3, 4]"
});

console.log("Tower Loaded");<commit_msg>Supporting Tower Methods<commit_after>
function Tower(data) {
	this.id = data['id'];
	this.name = data['name'];
	this.coordinate = {
		latitude: parseFloat(data['latitude']),
		longitude: parseFloat(data['longitude'])
	}
	this.size = parseFloat(data['size']);
	this.player = data['player'];
	this.troops = JSON.parse(data['troops']);
}

Tower.prototype.get = function(attribute) {
	return this[attribute];
}

Tower.prototype.set = function(attribute, value) {
	this[attribute] = value;
}

Tower.prototype.getLat = function(){
	return this.coordinate.latitude;
}

Tower.prototype.getLon = function(){
	return this.coordinate.longitude;
}

Tower.prototype.toString = function(){
	return this.id + ': (' + this.getLat().toFixed(3) + ', ' + this.getLon().toFixed(3) + ', ' + this.size + ')'
}

Tower.prototype.toPresetHTML = function(){
	var html = '';
	html += '
' + this.size + '
';
	return html;
}

Tower.prototype.getCircle = function(){
	var circle = new H.map.Circle({
		lat: this.getLat(),
		lng: this.getLon()
	}, this.size);
	console.log(this.getLat() + " " + this.getLon())
	return circle;
}

Tower.prototype.addTroops = function(troops){
	for (var i = 0; i < troops.length; i++){
		this.troops.push(troops[i].id);
		troops[i].set('towerID', this.id);
	}
	// database.push(this);
}

Tower.prototype.getTroopsByPlayer(playerID) = function(id){
	var troops = this.troops
	var out = [];
	for (var i = 0; i < troops.length; i++){
		if(troops[i].playerID === players)
		out.push(troops[i].id);
	}
	return out
}

var nick = new Tower({
	id: "1234",
	name:"Tower",
	latitude: "32",
	longitude: "-23.0",
	size: "5",
	player: "Nick",
	troops: "[1, 2, 3, 4]"
});

console.log("Tower Loaded");
<|endoftext|>


<commit_before>import React from "react";
import FormatedDate from "../common/formated-date";
import _ from "lodash";
const cx = require('classnames')

export default class FailureDetails extends React.Component {
  getStacktrace(failure) {
    let i = 0
    return _.map(failure.throwable.stackTrace, (el)=> {
      i++
      return (

          at {el.className}.{el.methodName}({el.fileName}:{el.lineNumber})

      )
    })
  }

  render() {
    let {failure, onClose} = this.props;
    let content = "";
    if (!!failure) {
      content = (

          <button className="btn btn-danger pull-right" onClick={onClose} style={{marginRight: 10}}></button>

Job

{failure.payload.className}

Arguments

{failure.payload.args}

Queue

{failure.queue}

Worker

{failure.worker}

Time

<FormatedDate date={new Date(failure.failedAt)}/>

Exception

{failure.throwableString}

Message

{failure.error}

Stacktrace

{this.getStacktrace(failure)}

      )
    }

    return (

        {content}

    )
  }
}
<commit_msg>fix handling of failed jobs without throwable<commit_after>import React from "react";
import FormatedDate from "../common/formated-date";
import _ from "lodash";
const cx = require('classnames')

export default class FailureDetails extends React.Component {
  getStacktrace(failure) {
    if (failure.throwable == null) {
      return
    }
    let i = 0
    return _.map(failure.throwable.stackTrace, (el)=> {
      i++
      return (

          at {el.className}.{el.methodName}({el.fileName}:{el.lineNumber})

      )
    })
  }

  render() {
    let {failure, onClose} = this.props;
    let content = "";
    if (!!failure) {
      content = (

          <button className="btn btn-danger pull-right" onClick={onClose} style={{marginRight: 10}}></button>

Job

{failure.payload.className}

Arguments

{failure.payload.args}

Queue

{failure.queue}

Worker

{failure.worker}

Time

<FormatedDate date={new Date(failure.failedAt)}/>

Exception

{failure.throwableString}

Message

{failure.error}

Stacktrace

{this.getStacktrace(failure)}

      )
    }

    return (

        {content}

    )
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const renderers = require('./renderer/index.js');
const co = require('co');

/**
 * Artefact renderer
 *
 * @memberOf export
 * @extends Base
 */
class Renderer extends Base
{
    /**
     * @ignore
     */
    constructor(nodeRenderers, options)
    {
        super();
        this._options = options || {};
        this._nodeRenderers = [];

        //Default renderer
        this._nodeRenderers.push(new renderers.NodeListRenderer());

        // Custom renderer
        if (nodeRenderers && Array.isArray(nodeRenderers))
        {
            for (const nodeRenderer of nodeRenderers)
            {
                if (!(nodeRenderer instanceof renderers.NodeRenderer))
                {
                    throw new Error(this.className + ' expects a list of NodeRenderer instances');
                }
                this._nodeRenderers.push(nodeRenderer);
            }
        }
    }

    /**
     * @inheritDocs
     */
    static get className()
    {
        return 'export/Renderer';
    }

    /**
     * @inheritDocs
     */
    static get injections()
    {
        return { 'parameters': ['export/Renderer.nodeRenderers', 'export/Renderer.options'] };
    }

    /**
     * @type {Object}
     */
    get options()
    {
        return this._options;
    }

    /**
     * @type {Array}
     */
    get nodeRenderers()
    {
        return this._nodeRenderers;
    }

    /**
     * Renders any source code at the top of each rendering
     *
     * @protected
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderPreface(configuration)
    {
        return Promise.resolve('');
    }

    /**
     * Renders any source code at the bottom of each rendering
     *
     * @protected
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderPostface(configuration)
    {
        return Promise.resolve('');
    }

    /**
     * Renders the given node (and it's child nodes) to a string.
     *
     * It will ask all registered renderers if it "willRender" the
     * node. After a renderer wants to render that node it may allow other
     * renderes to process the current node by returning "false" when
     * asked for "shouldStopRendering".
     *
     * @param {export.ast.Node} node
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderNode(node, configuration)
    {
        if (!node)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            let result = '';
            let didRender = false;
            for (const renderer of scope.nodeRenderers)
            {
                const willRender = yield renderer.willRender(node, configuration);
                if (willRender)
                {
                    didRender = true;
                    result+= yield renderer.render(node, configuration);
                    const stopRendering = yield renderer.shouldStopRendering(node, configuration);
                    if (stopRendering)
                    {
                        return result;
                    }
                }
            }
            if (!didRender)
            {
                scope.logger.error('renderNode: No renderer found', node.serialize());
            }
            return result;
        });
        return promise;
    }

    /**
     * Renders a list of Nodes.
     *
     * @param {Array} list
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderList(list, configuration)
    {
        if (!list)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            let result = '';
            for (const item of list)
            {
                result+= yield scope.renderNode(item, configuration);
            }
            return result;
        });
        return promise;
    }

    /**
     * A central comment renderer
     *
     * @param {String} text
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderComment(text, configuration)
    {
        return Promise.resolve('<!-- ' + text + ' -->\n');
    }

    /**
     * Renders a node as source code
     *
     * @param {export.ast.Node} node
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    render(node, configuration)
    {
        if (!node)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            let source = '';
            source+= yield scope.renderPreface(configuration);
            source+= yield scope.renderNode(node, configuration);
            source+= yield scope.renderPostface(configuration);
            return source;
        });
        return promise;
    }

    /**
     * Reset's the internal state of all renderers.
     *
     * @param {export.Configuration} configuration
     * @returns {Promise}
     */
    reset(configuration)
    {
        const scope = this;
        const promise = co(function *()
        {
            for (const nodeRenderer of scope.nodeRenderers)
            {
                yield nodeRenderer.reset(configuration);
            }
        });
        return promise;
    }

    /**
     * Creates any additional files needed by node renderers.
     *
     * @param {export.Configuration} configuration
     * @param {String} stage
     * @returns {Promise<Array>}
     */
    createAdditionalFiles(configuration, stage)
    {
        const scope = this;
        const promise = co(function *()
        {
            const result = [];
            for (const nodeRenderer of scope.nodeRenderers)
            {
                const files = yield nodeRenderer.createAdditionalFiles(configuration, stage);
                result.push(...files);
            }
            return result;
        });
        return promise;
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.Renderer = Renderer;
<commit_msg>fix(export.Renderer): allow pre and post render methods to use data from node rendering<commit_after>'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const renderers = require('./renderer/index.js');
const co = require('co');

/**
 * Artefact renderer
 *
 * @memberOf export
 * @extends Base
 */
class Renderer extends Base
{
    /**
     * @ignore
     */
    constructor(nodeRenderers, options)
    {
        super();
        this._options = options || {};
        this._nodeRenderers = [];

        //Default renderer
        this._nodeRenderers.push(new renderers.NodeListRenderer());

        // Custom renderer
        if (nodeRenderers && Array.isArray(nodeRenderers))
        {
            for (const nodeRenderer of nodeRenderers)
            {
                if (!(nodeRenderer instanceof renderers.NodeRenderer))
                {
                    throw new Error(this.className + ' expects a list of NodeRenderer instances');
                }
                this._nodeRenderers.push(nodeRenderer);
            }
        }
    }

    /**
     * @inheritDocs
     */
    static get className()
    {
        return 'export/Renderer';
    }

    /**
     * @inheritDocs
     */
    static get injections()
    {
        return { 'parameters': ['export/Renderer.nodeRenderers', 'export/Renderer.options'] };
    }

    /**
     * @type {Object}
     */
    get options()
    {
        return this._options;
    }

    /**
     * @type {Array}
     */
    get nodeRenderers()
    {
        return this._nodeRenderers;
    }

    /**
     * Renders any source code at the top of each rendering
     *
     * @protected
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderPreface(configuration)
    {
        return Promise.resolve('');
    }

    /**
     * Renders any source code at the bottom of each rendering
     *
     * @protected
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderPostface(configuration)
    {
        return Promise.resolve('');
    }

    /**
     * Renders the given node (and it's child nodes) to a string.
     *
     * It will ask all registered renderers if it "willRender" the
     * node. After a renderer wants to render that node it may allow other
     * renderes to process the current node by returning "false" when
     * asked for "shouldStopRendering".
     *
     * @param {export.ast.Node} node
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderNode(node, configuration)
    {
        if (!node)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            let result = '';
            let didRender = false;
            for (const renderer of scope.nodeRenderers)
            {
                const willRender = yield renderer.willRender(node, configuration);
                if (willRender)
                {
                    didRender = true;
                    result+= yield renderer.render(node, configuration);
                    const stopRendering = yield renderer.shouldStopRendering(node, configuration);
                    if (stopRendering)
                    {
                        return result;
                    }
                }
            }
            if (!didRender)
            {
                scope.logger.error('renderNode: No renderer found', node.serialize());
            }
            return result;
        });
        return promise;
    }

    /**
     * Renders a list of Nodes.
     *
     * @param {Array} list
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderList(list, configuration)
    {
        if (!list)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            let result = '';
            for (const item of list)
            {
                result+= yield scope.renderNode(item, configuration);
            }
            return result;
        });
        return promise;
    }

    /**
     * A central comment renderer
     *
     * @param {String} text
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    renderComment(text, configuration)
    {
        return Promise.resolve('<!-- ' + text + ' -->\n');
    }

    /**
     * Renders a node as source code
     *
     * @param {export.ast.Node} node
     * @param {export.Configuration} configuration
     * @returns {Promise<String>}
     */
    render(node, configuration)
    {
        if (!node)
        {
            return Promise.resolve('');
        }
        const scope = this;
        const promise = co(function*()
        {
            const nodes = yield scope.renderNode(node, configuration);
            const preface = yield scope.renderPreface(configuration);
            const postface = yield scope.renderPostface(configuration);
            return preface + nodes + postface;
        });
        return promise;
    }

    /**
     * Reset's the internal state of all renderers.
     *
     * @param {export.Configuration} configuration
     * @returns {Promise}
     */
    reset(configuration)
    {
        const scope = this;
        const promise = co(function *()
        {
            for (const nodeRenderer of scope.nodeRenderers)
            {
                yield nodeRenderer.reset(configuration);
            }
        });
        return promise;
    }

    /**
     * Creates any additional files needed by node renderers.
     *
     * @param {export.Configuration} configuration
     * @param {String} stage
     * @returns {Promise<Array>}
     */
    createAdditionalFiles(configuration, stage)
    {
        const scope = this;
        const promise = co(function *()
        {
            const result = [];
            for (const nodeRenderer of scope.nodeRenderers)
            {
                const files = yield nodeRenderer.createAdditionalFiles(configuration, stage);
                result.push(...files);
            }
            return result;
        });
        return promise;
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.Renderer = Renderer;
<|endoftext|>


<commit_before>import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
import Folders from "../collection.js";

Meteor.publish('folders', function () {

    const currentUser = this.userId && Users.findOne(this.userId);

    if (Users.canDo(currentUser, "folders.view.approved.all")) {
        var userId = currentUser._id;

        var folders = Folders.find({userId: userId}, {fields: Folders.publishedFields.list});
        var publication = this;

        //folders.forEach(function (folder) {
        //  var childrenFolders = folder.getChildren();
        //  var folderIds = [folder._id].concat(_.pluck(childrenFolders, "_id"));
        //  var cursor = Posts.find({$and: [{folders: {$in: folderIds}}, {status: Posts.config.STATUS_APPROVED}]});
        //  // Counts.publish(publication, folder.getCounterName(), cursor, { noReady: true });
        //});

        return folders;
    }
    return [];
});

/**
 * @summary Publish a list of folders, along with the users corresponding to these folders
 * @param {Object} terms
 */
Meteor.publish('folders.list', function (terms) {

    // this.unblock(); // causes bug where publication returns 0 results

    this.autorun(function () {

        const currentUser = this.userId && Meteor.users.findOne(this.userId);

        terms.currentUserId = this.userId; // add currentUserId to terms
        const {selector, options} = Folders.parameters.get(terms);

        Counts.publish(this, terms.userId, Posts.find(selector, options), {noReady: true});

        options.fields = Folders.publishedFields.list;

        const posts = Folders.find(selector, options);

        // note: doesn't work yet :(
        // CursorCounts.set(terms, posts.count(), this.connection.id);

        return Users.canDo(currentUser, "folders.view.approved.all") ? [posts] : [];
    });

});

/**
 * @summary Publish a list of folders, along with the users corresponding to these folders
 * @param {Object} terms
 */
//Meteor.publish('folders.single', function (terms) {
//
//    // this.unblock(); // causes bug where publication returns 0 results
//
//    this.autorun(function () {
//
//        const currentUser = this.userId && Meteor.users.findOne(this.userId);
//
//        terms.currentUserId = this.userId; // add currentUserId to terms
//        const {selector, options} = Folders.parameters.get(terms);
//
//        Counts.publish(this, terms.userId, Posts.find(selector, options), {noReady: true});
//
//        options.fields = Folders.publishedFields.list;
//
//        const posts = Folders.find(selector, options);
//
//        // note: doesn't work yet :(
//        // CursorCounts.set(terms, posts.count(), this.connection.id);
//
//        return Users.canDo(currentUser, "folders.view.approved.all") ? [posts] : [];
//    });
//
//});

/**
 * @summary Publish a single post, along with all relevant users
 * @param {Object} terms
 */
Meteor.publish('folders.single', function (terms) {

    check(terms, Match.OneOf({_id: String}));

    const currentUser = this.userId && Meteor.users.findOne(this.userId);
    const options = {fields: Posts.publishedFields.single};
    const folders = Folders.find(terms._id, options);
    const folder = folders.fetch()[0];

    if (folder) {
        // query collected posts in this folder according to postId recording in the folder's posts.
        folder.posts.forEach(function (postId) {
            var childrenFolders = folder.getChildren();
            var folderIds = [folder._id].concat(_.pluck(childrenFolders, "_id"));
            var cursor = Posts.find({$and: [{folders: {$in: folderIds}}, {status: Posts.config.STATUS_APPROVED}]});
            Counts.publish(publication, folder.getCounterName(), cursor, {noReady: true});
        });

        return [folders];
    } else {
        console.log(`// folders.single: no collection found for _id “${terms._id}”`);
        return [];
    }

});<commit_msg>add "folders.list".<commit_after>import Posts from "meteor/nova:posts";
import Users from 'meteor/nova:users';
import Folders from "../collection.js";

Meteor.publish('folders', function () {

    const currentUser = this.userId && Users.findOne(this.userId);

    if (Users.canDo(currentUser, "folders.view.approved.all")) {
        var userId = currentUser._id;

        var folders = Folders.find({userId: userId}, {fields: Folders.publishedFields.list});
        var publication = this;

        //folders.forEach(function (folder) {
        //  var childrenFolders = folder.getChildren();
        //  var folderIds = [folder._id].concat(_.pluck(childrenFolders, "_id"));
        //  var cursor = Posts.find({$and: [{folders: {$in: folderIds}}, {status: Posts.config.STATUS_APPROVED}]});
        //  // Counts.publish(publication, folder.getCounterName(), cursor, { noReady: true });
        //});

        return folders;
    }
    return [];
});

/**
 * @summary Publish a list of folders, along with the users corresponding to these folders
 * @param {Object} terms
 */
Meteor.publish('folders.list', function (terms) {

    // this.unblock(); // causes bug where publication returns 0 results

    this.autorun(function () {

        const currentUser = this.userId && Meteor.users.findOne(this.userId);

        terms.currentUserId = this.userId; // add currentUserId to terms
        const {selector, options} = Folders.parameters.get(terms);

        Counts.publish(this, terms.userId, Posts.find(selector, options), {noReady: true});

        options.fields = Folders.publishedFields.list;

        const posts = Folders.find(selector, options);

        // note: doesn't work yet :(
        // CursorCounts.set(terms, posts.count(), this.connection.id);

        return Users.canDo(currentUser, "folders.view.approved.all") ? [posts] : [];
    });

});

/**
 * @summary Publish a list of folders, along with the users corresponding to these folders
 * @param {Object} terms
 */
//Meteor.publish('folders.single', function (terms) {
//
//    // this.unblock(); // causes bug where publication returns 0 results
//
//    this.autorun(function () {
//
//        const currentUser = this.userId && Meteor.users.findOne(this.userId);
//
//        terms.currentUserId = this.userId; // add currentUserId to terms
//        const {selector, options} = Folders.parameters.get(terms);
//
//        Counts.publish(this, terms.userId, Posts.find(selector, options), {noReady: true});
//
//        options.fields = Folders.publishedFields.list;
//
//        const posts = Folders.find(selector, options);
//
//        // note: doesn't work yet :(
//        // CursorCounts.set(terms, posts.count(), this.connection.id);
//
//        return Users.canDo(currentUser, "folders.view.approved.all") ? [posts] : [];
//    });
//
//});

/**
 * @summary Publish a single post, along with all relevant users
 * @param {Object} terms
 */
Meteor.publish('folders.single', function (terms) {

    check(terms, Match.OneOf({_id: String}));

    const currentUser = this.userId && Meteor.users.findOne(this.userId);
    const options = {fields: Posts.publishedFields.single};
    const folders = Folders.find(terms._id, options);
    const folder = folders.fetch()[0];

    if (folder) {
        // Query collected posts in this folder by postId recording in the folder's posts.
        var postsArray = [];
        folder.posts.forEach(function (postId) {
            var post = Posts.find({_id: postId}).fetch();
            if (post) {
                postsArray.push(post);
            }
        });
        folder.postsArray = postsArray;

        return [folders];
    } else {
        console.log(`// folders.single: no collection found for _id “${terms._id}”`);
        return [];
    }

});<|endoftext|>


<commit_before><commit_msg>Correct error message when adding a property with missing information<commit_after><|endoftext|>


<commit_before>(function ($) {
    "use strict";

    var pluginName = 'kbModalAjax';

    /**
     * Retrieves the script tags in document
     * @return {Array}
     */
    var getPageScriptTags = function () {
        var scripts = [];
        jQuery('script[src]').each(function () {
            scripts.push(jQuery(this).attr('src'));
        });
        return scripts;
    };

    /**
     * Retrieves the CSS links in document
     * @return {Array}
     */
    var getPageCssLinks = function () {
        var links = [];
        jQuery('link[rel="stylesheet"]').each(function () {
            links.push(jQuery(this).attr('href'));
        });
        return links;
    };

    function ModalAjax(element, options) {
        this.element = element;
        this.init(options);
    }

    ModalAjax.prototype.init = function (options) {
        this.selector = options.selector || null;
        this.initalRequestUrl = options.url;
        this.ajaxSubmit = options.ajaxSubmit || true;
        jQuery(this.element).on('show.bs.modal', this.shown.bind(this));
    };

    /**
     * Requests the content of the modal and injects it, called after the
     * modal is shown
     */
    ModalAjax.prototype.shown = function () {
        // Clear original html before loading
        jQuery(this.element).find('.modal-body').html('');

        jQuery.ajax({
            url: this.initalRequestUrl,
            context: this,
            beforeSend: function (xhr, settings) {
                jQuery(this.element).triggerHandler('kbModalBeforeShow', [xhr, settings]);
            },
            success: function (data, status, xhr) {
				var self = this;

                this.injectHtml(data, function()
				{
					if (self.ajaxSubmit) {
						jQuery(self.element).off('submit').on('submit', self.formSubmit.bind(self));
					}
					jQuery(self.element).triggerHandler('kbModalShow', [data, status, xhr, self.selector]);
				});
            }
        });
    };

    /**
     * Injects the form of given html into the modal and extecutes css and js
     * @param  {string} html the html to inject
     */
    ModalAjax.prototype.injectHtml = function (html, callback) {
        // Find form and inject it
        var form = jQuery(html).filter('form');

        // Remove existing forms
        if (jQuery(this.element).find('form').length > 0) {
            jQuery(this.element).find('form').off().yiiActiveForm('destroy').remove();
        }

        var knownScripts = getPageScriptTags();
        var knownCssLinks = getPageCssLinks();
        var newScripts = [];
        var inlineInjections = [];
        var loadedScriptsCount = 0;

        // Find some element to append to
        var headTag = jQuery('head');
        if (headTag.length < 1) {
            headTag = jQuery('body');
            if (headTag.length < 1) {
                headTag = jQuery(document);
            }
        }

        // CSS stylesheets that haven't been added need to be loaded
        jQuery(html).filter('link[rel="stylesheet"]').each(function () {
            var href = jQuery(this).attr('href');

            if (knownCssLinks.indexOf(href) < 0) {
                // Append the CSS link to the page
                headTag.append(jQuery(this).prop('outerHTML'));
                // Store the link so its not needed to be requested again
                knownCssLinks.push(href);
            }
        });

        // Scripts that haven't yet been loaded need to be added to the end of the body
        jQuery(html).filter('script').each(function () {
            var src = jQuery(this).attr("src");

            if (typeof src === 'undefined') {
                // If no src supplied, execute the raw JS (need to execute after the script tags have been loaded)
                inlineInjections.push(jQuery(this).text());
            } else if (knownScripts.indexOf(src) < 0) {
                // Prepare src so we can append GET parameter later
                src += (src.indexOf('?') < 0) ? '?' : '&';
                newScripts.push(src);
            }
        });

		var injectionElement = jQuery(this.element).find('.modal-body')[0];

		var doInjection = function()
		{
			injectionElement.innerHTML = html;

			// Execute inline scripts
			for (var i = 0; i < inlineInjections.length; i += 1) {
				window.eval(inlineInjections[i]);
			}

			if (callback != null)
			{
				callback();
			}
		};

		if (newScripts.length > 0)
		{
			/**
			 * Scripts loaded callback
			 */
			var scriptLoaded = function () {
				loadedScriptsCount += 1;
				if (loadedScriptsCount === newScripts.length) {
					doInjection();
				}
			};

			// Load each script tag
			for (var i = 0; i < newScripts.length; i += 1) {
				jQuery.getScript(newScripts[i] + (new Date().getTime()), scriptLoaded);
			}
		}
		else
		{
			doInjection();
		}
    };

    /**
     * Adds event handlers to the form to check for submit
     */
    ModalAjax.prototype.formSubmit = function () {
        var form = jQuery(this.element).find('form');

        // Convert form to ajax submit
        jQuery.ajax({
            method: form.attr('method'),
            url: form.attr('action'),
            data: form.serialize(),
            context: this,
            beforeSend: function (xhr, settings) {
                jQuery(this.element).triggerHandler('kbModalBeforeSubmit', [xhr, settings]);
            },
            success: function (data, status, xhr) {
                var contentType = xhr.getResponseHeader('content-type') || '';
                if (contentType.indexOf('html') > -1) {
                    // Assume form contains errors if html
                    this.injectHtml(data);
                    status = false;
                }
                jQuery(this.element).triggerHandler('kbModalSubmit', [data, status, xhr, this.selector]);
            }
        });

        return false;
    };

    $.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, pluginName)) {
                $.data(this, pluginName, new ModalAjax(this, options));
            } else {
                $.data(this, pluginName).initalRequestUrl = options.url;
                $.data(this, pluginName).selector = options.selector || null;
                //console.log($.data(this, pluginName).initalRequestUrl);
            }
        });
    };
})(jQuery);
<commit_msg>Update kb-modal-ajax.js<commit_after>(function ($) {
    "use strict";

    var pluginName = 'kbModalAjax';

    /**
     * Retrieves the script tags in document
     * @return {Array}
     */
    var getPageScriptTags = function () {
        var scripts = [];
        jQuery('script[src]').each(function () {
            scripts.push(jQuery(this).attr('src'));
        });
        return scripts;
    };

    /**
     * Retrieves the CSS links in document
     * @return {Array}
     */
    var getPageCssLinks = function () {
        var links = [];
        jQuery('link[rel="stylesheet"]').each(function () {
            links.push(jQuery(this).attr('href'));
        });
        return links;
    };

    function ModalAjax(element, options) {
        this.element = element;
        this.init(options);
    }

    ModalAjax.prototype.init = function (options) {
        this.selector = options.selector || null;
        this.initalRequestUrl = options.url;
        this.ajaxSubmit = options.ajaxSubmit || true;
        jQuery(this.element).on('show.bs.modal', this.shown.bind(this));
    };

    /**
     * Requests the content of the modal and injects it, called after the
     * modal is shown
     */
    ModalAjax.prototype.shown = function () {
        // Clear original html before loading
        jQuery(this.element).find('.modal-body').html('');

        jQuery.ajax({
            url: this.initalRequestUrl,
            context: this,
            beforeSend: function (xhr, settings) {
                jQuery(this.element).triggerHandler('kbModalBeforeShow', [xhr, settings]);
            },
            success: function (data, status, xhr) {
				var self = this;

                this.injectHtml(data, function()
				{
					if (self.ajaxSubmit) {
						jQuery(self.element).off('submit').on('submit', self.formSubmit.bind(self));
					}
					jQuery(self.element).triggerHandler('kbModalShow', [data, status, xhr, self.selector]);
				});
            }
        });
    };

    /**
     * Injects the form of given html into the modal and extecutes css and js
     * @param  {string} html the html to inject
     */
    ModalAjax.prototype.injectHtml = function (html, callback) {
        // Find form and inject it
        var form = jQuery(html).filter('form');

        // Remove existing forms
        if (jQuery(this.element).find('form').length > 0) {
            jQuery(this.element).find('form').off().yiiActiveForm('destroy').remove();
        }

        var knownScripts = getPageScriptTags();
        var knownCssLinks = getPageCssLinks();
        var newScripts = [];
        var inlineInjections = [];
        var loadedScriptsCount = 0;

        // Find some element to append to
        var headTag = jQuery('head');
        if (headTag.length < 1) {
            headTag = jQuery('body');
            if (headTag.length < 1) {
                headTag = jQuery(document);
            }
        }

        // CSS stylesheets that haven't been added need to be loaded
        jQuery(html).filter('link[rel="stylesheet"]').each(function () {
            var href = jQuery(this).attr('href');

            if (knownCssLinks.indexOf(href) < 0) {
                // Append the CSS link to the page
                headTag.append(jQuery(this).prop('outerHTML'));
                // Store the link so its not needed to be requested again
                knownCssLinks.push(href);
            }
        });

        // Scripts that haven't yet been loaded need to be added to the end of the body
        jQuery(html).filter('script').each(function () {
            var src = jQuery(this).attr("src");

            if (typeof src === 'undefined') {
                // If no src supplied, execute the raw JS (need to execute after the script tags have been loaded)
                inlineInjections.push(jQuery(this).text());
            } else if (knownScripts.indexOf(src) < 0) {
                // Prepare src so we can append GET parameter later
                src += (src.indexOf('?') < 0) ? '?' : '&';
                newScripts.push(src);
            }
        });

		var injectionElement = jQuery(this.element).find('.modal-body')[0];

		var doInjection = function()
		{
			injectionElement.innerHTML = html;

			// Execute inline scripts
			for (var i = 0; i < inlineInjections.length; i += 1) {
				window.eval(inlineInjections[i]);
			}

			if (callback != null)
			{
				callback();
			}
		};

		if (newScripts.length > 0)
		{
			/**
			 * Scripts loaded callback
			 */
			var scriptLoaded = function () {
				loadedScriptsCount += 1;
				if (loadedScriptsCount === newScripts.length) {
					doInjection();
				}
			};

			// Load each script tag
			for (var i = 0; i < newScripts.length; i += 1) {
				jQuery.getScript(newScripts[i] + (new Date().getTime()), scriptLoaded);
			}
		}
		else
		{
			doInjection();
		}
    };

    /**
     * Adds event handlers to the form to check for submit
     */
    ModalAjax.prototype.formSubmit = function () {
        var form = jQuery(this.element).find('form');

        // Convert form to ajax submit
        jQuery.ajax({
            method: form.attr('method'),
            url: form.attr('action'),
            data: form.serialize(),
            context: this,
            beforeSend: function (xhr, settings) {
                jQuery(this.element).triggerHandler('kbModalBeforeSubmit', [xhr, settings]);
            },
            success: function (data, status, xhr) {
                var contentType = xhr.getResponseHeader('content-type') || '';
                if (contentType.indexOf('html') > -1) {
                    // Assume form contains errors if html
                    this.injectHtml(data);
                    status = false;
                }
				else if (typeof data == "object" && data.msg != null && data.msg != '' && jQuery.notify != null)
				{
					jQuery.notify(data.msg, {
						className: "success",
						position: "top right"
					});
				}
                jQuery(this.element).triggerHandler('kbModalSubmit', [data, status, xhr, this.selector]);
            }
        });

        return false;
    };

    $.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, pluginName)) {
                $.data(this, pluginName, new ModalAjax(this, options));
            } else {
                $.data(this, pluginName).initalRequestUrl = options.url;
                $.data(this, pluginName).selector = options.selector || null;
                //console.log($.data(this, pluginName).initalRequestUrl);
            }
        });
    };
})(jQuery);
<|endoftext|>


<commit_before>/*
 * django-angular-websocket
 * https://github.com/jrief/django-angular
 *
 * Add three-way data-binding for AngularJS with Django using websockets.
 *
 * Copyright (c) 2014 Jacob Rief
 * Licensed under the MIT license.
 */

(function(angular, undefined) {
'use strict';

angular.module('ng.django.websocket', []).provider('djangoWebsocket', function() {
	var _prefix;
	var _console = { log: noop, warn: noop, error: noop };

	function noop() {}

	this.prefix = function(prefix) {
		_prefix = prefix;
		return this;
	};

	this.debug = function(debug) {
		if (debug) {
			_console = console;
		}
		return this;
	};

	this.$get = ['$window', '$q', '$timeout', function($window, $q, $timeout) {
		var ws, deferred, timer = null, interval = null, scope, channels, collection;

		function connect(uri) {
			try {
				_console.log("Connecting to "+uri);
				deferred = $q.defer();
				ws = new WebSocket(uri);
				ws.onopen = on_open;
				ws.onmessage = on_message;
				ws.onerror = on_error;
				ws.onclose = on_close;
				timer = null;
			} catch (err) {
				deferred.reject(new Error(err));
			}
		}

		function on_open(evt) {
			_console.log('Connected');
			interval = 3000;
			deferred.resolve();
		}

		function on_close(evt) {
			_console.log("Connection closed");
			if (!timer && interval) {
				timer = $timeout(function() {
					connect(ws.url);
				}, interval);
				interval = Math.min(interval + 1000, 90000);
			}
		}

		function on_error(evt) {
			_console.error("Websocket connection is broken!");
			deferred.reject(new Error(evt));
		}

		function on_message(evt) {
			try {
				var server_data = JSON.parse(evt.data);
				scope.$apply(function() {
					angular.extend(scope[collection], server_data);
				});
			} catch(e) {
				_console.warn('Data received by server is invalid JSON: ' + evt.data);
			}
		}

		function listener(newValue, oldValue) {
			if (newValue !== undefined) {
				ws.send(JSON.stringify(newValue));
			}
		}

		return {
			connect: function(scope_, channels_, collection_) {
				var parts = [], location = $window.location;
				scope = scope_;
				channels = channels_;
				collection = collection_;
				parts.push(location.protocol === 'https' ? 'wss:' : 'ws:');
				parts.push('//');
				parts.push(location.host);
				parts.push(_prefix);
				parts.push(location.pathname);
				parts.push('?');
				parts.push(channels.join('&'));
				connect(parts.join(''));
				scope[collection] = scope[collection] || {};
				deferred.promise.then(function() {
					scope.$watchCollection(collection, listener);
				});
				return deferred.promise;
			}
		};
	}];
});

})(window.angular);
<commit_msg>Added Angular directive which corrects behavior for bound forms<commit_after>/*
 * AngularJS modules to be used together with
 * https://github.com/jrief/django-angular
 *
 * Copyright (c) 2014 Jacob Rief
 * Licensed under the MIT license.
 */

(function(angular, undefined) {
'use strict';

// Correct Angular's form.FormController behavior after rendering bound forms.
angular.module('ng.django.forms', []).directive('form', function() {
	return {
		restrict: 'E',
		scope: 'isolate',
		priority: -1,
		link: function(scope, element, attrs) {
			var form = scope[attrs.name];
			var fields = angular.element(element).find('input');
			angular.forEach(fields, function(field) {
				if (form[field.name] !== undefined) {
					// restore the field's content from the rendered content of bound fields
					form[field.name].$setViewValue(field.defaultValue);
				}
			});
			// restore the form's pristine state
			form.$setPristine();
		}
	};
});

// Add three-way data-binding for AngularJS with Django using websockets.
angular.module('ng.django.websocket', []).provider('djangoWebsocket', function() {
	var _prefix;
	var _console = { log: noop, warn: noop, error: noop };

	function noop() {}

	this.prefix = function(prefix) {
		_prefix = prefix;
		return this;
	};

	this.debug = function(debug) {
		if (debug) {
			_console = console;
		}
		return this;
	};

	this.$get = ['$window', '$q', '$timeout', function($window, $q, $timeout) {
		var ws, deferred, timer = null, interval = null, scope, channels, collection;

		function connect(uri) {
			try {
				_console.log("Connecting to "+uri);
				deferred = $q.defer();
				ws = new WebSocket(uri);
				ws.onopen = on_open;
				ws.onmessage = on_message;
				ws.onerror = on_error;
				ws.onclose = on_close;
				timer = null;
			} catch (err) {
				deferred.reject(new Error(err));
			}
		}

		function on_open(evt) {
			_console.log('Connected');
			interval = 3000;
			deferred.resolve();
		}

		function on_close(evt) {
			_console.log("Connection closed");
			if (!timer && interval) {
				timer = $timeout(function() {
					connect(ws.url);
				}, interval);
				interval = Math.min(interval + 1000, 90000);
			}
		}

		function on_error(evt) {
			_console.error("Websocket connection is broken!");
			deferred.reject(new Error(evt));
		}

		function on_message(evt) {
			try {
				var server_data = JSON.parse(evt.data);
				scope.$apply(function() {
					angular.extend(scope[collection], server_data);
				});
			} catch(e) {
				_console.warn('Data received by server is invalid JSON: ' + evt.data);
			}
		}

		function listener(newValue, oldValue) {
			if (newValue !== undefined) {
				ws.send(JSON.stringify(newValue));
			}
		}

		return {
			connect: function(scope_, channels_, collection_) {
				var parts = [], location = $window.location;
				scope = scope_;
				channels = channels_;
				collection = collection_;
				parts.push(location.protocol === 'https' ? 'wss:' : 'ws:');
				parts.push('//');
				parts.push(location.host);
				parts.push(_prefix);
				parts.push(location.pathname);
				parts.push('?');
				parts.push(channels.join('&'));
				connect(parts.join(''));
				scope[collection] = scope[collection] || {};
				deferred.promise.then(function() {
					scope.$watchCollection(collection, listener);
				});
				return deferred.promise;
			}
		};
	}];
});

})(window.angular);
<|endoftext|>