<commit_before>/**
 * Interactive Map Widget
 * @copyright Copyright 2010
 * @author Edward Rudd <urkle at outoforder.cc>
 */
/*
 * This file is part of INQ Calculators.
 *
 * INQ Calculators is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * INQ Calculators is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with INQ Calculators.  If not, see <http://www.gnu.org/licenses/>.
 */
(function($) { //hide namespace

function parseScale(val) {
    var p = val.split(':');
    return {
        num: parseInt(p[0]),
        den: parseInt(p[1])
    };
}

function dirname (path) {
    // Modified from http://phpjs.org/functions/dirname
    return path.replace(/\/[^\/]*\/?$/, '');
}

function OverlayContainer(elem) {
    this.element = elem;
    // The starting scale
    this._scale = { num: 1, den: 1 };
    // List of jsGraphics wrappers
    this._elems = [];
    this._toDraw = [];
}
$.extend(OverlayContainer.prototype, {
    setScale: function(scale) {
        if (this._scale.num != scale.num || this._scale.den != scale.den) {
            this._scale.num = scale.num;
            this._scale.den = scale.den;
        }
        return this;
    },
    draw: function(force) {
        if (force) {
            this._toDraw = [];
            for (var i=0,l=this._elems.length; i<l; ++i) {
                var o = this._elems[i];
                var f = this['_draw_'+o.type];
                if ($.isFunction(f)) {
                    f.call(this,o);
                }
            }
        } else {
            while (this._toDraw.length) {
                var o = this._elems[this._toDraw.shift()];
                var f = this['_draw_'+o.type];
                if ($.isFunction(f)) {
                    f.call(this,o);
                }
            }
        }
        return this;
    },
    _draw_polygon: function(o) {
        if (!o.wrapper) {
            o.wrapper = $('
').appendTo(this.element);
        }
        o.wrapper.empty();
        o.data.draw(o.wrapper, this._scale, this.nextColor());
    },
    colors: [
        '#ffffff',
        '#ff00ff',
        '#00ffff',
        '#ffff00',
        '#ff0000',
        '#00ff00',
        '#0000ff',
        '#000000',
    ],
    nextColor: function() {
        this.color = ((this.color || 0) + 1) % this.colors.length;
        return this.colors[this.color];
    },
    addPolygon: function(polygon, offset) {
        var id = this._addObject('polygon', polygon, offset, true);
        return id;
    },
    _addObject: function(type, data, offset, toDraw) {
        var o = {
            type: type,
            data: data,
            offset: offset
        };
        this._elems.push(o);
        var id = this._elems.length-1;
        if (toDraw) {
            this._toDraw.push(id);
        }
        return id;
    }
});

$.widget('ui.interactiveMap', $.ui.mouse, {
    options: {
        map:'',
        blankImage:'images/blank.gif'
    },

    _create: function() {
        this._mouseInit();
        this._elems = {};
        var self = this;
        this.element
            .addClass('interactiveMap')
            .disableSelection()
            .mousewheel(function(event,delta) {self._mouseWheel(event,delta);});
        this._elems.view = $('
')
            .appendTo(this.element);
        this._elems.container = $('
')
            .appendTo(this._elems.view);
        this._elems.tileCache = $('
')
            .appendTo(this._elems.container);
        this._elems.overlay = $('
')
            .appendTo(this._elems.container);
        this.loadMap();
    },
    render: function() {
        if (this.element.is(':hidden') || !this._map) {
            // nothing to see here move along
            return;
        }
        // Called when the display needs to be recalculated (resize or show when previously hidden)
        var _viewwidth = this.element.innerWidth()
            || this.options.width || 400;
        var _viewheight = this.element.innerHeight()
            || this.options.height || 400;
        var tiles_x = Math.ceil(_viewwidth / this._map.tilesize) + 1;
        var tiles_y = Math.ceil(_viewheight / this._map.tilesize) + 1;
        this._view = {
            w: (tiles_x + 1) * this._map.tilesize,
            h: (tiles_y + 1) * this._map.tilesize
        };
        if (this._activeLayerNum !== undefined) {
            var left = this._elems.container[0].offsetLeft;
            var top = this._elems.container[0].offsetTop;
            this.checkTiles(left, top);
            this.overlay().draw();
        }
    },
    destroy: function() {
        this._mouseDestroy();
        this.element.empty();
        this.element
            .removeClass('interactiveMap')
            .enableSelection();

        $.Widget.prototype.destroy.apply(this, arguments);
    },
    loadMap: function(map) {
        if (map) {
            this._setOption('map',map);
        }
        var self = this;
        $.get(this.options.map,undefined,function(xml) {
            self._loadXML(xml);
        },'xml');
    },
    _loadXML: function(xml) {
        var layers = $(xml).find("layer");
        var map = $(xml).find('map');
        this._map = {};
        this._map.tilesize = parseInt(map.attr('tilesize'));
        this._map.width = parseInt(map.attr('width'));
        this._map.height = parseInt(map.attr('height'));
        this._map.layers = [];
        for (var layer_itr=0,layer_len=layers.length; layer_itr<layer_len;
                ++layer_itr) {
            var _l = layers.eq(layer_itr);
            var _ll = {
                width: parseInt(_l.attr('width')),
                height: parseInt(_l.attr('height')),
                scale: parseScale(_l.attr('scale')),
                path: dirname(this.options.map)+'/'+_l.attr('path')+'/',
                pieces: {}
            }
            // Parse Pieces
            var pieces = _l.find('piece');
            for (var piece_itr=0,piece_len=pieces.length; piece_itr<piece_len;
                    ++piece_itr) {
                var _p = pieces.eq(piece_itr);
                var left = _p.attr('left'), top = _p.attr('top');
                if (!_ll.pieces[left]) {
                    _ll.pieces[left] = {};
                }
                _ll.pieces[left][top] = _p.attr('file');
            }
            this._map.layers.push(_ll);
        }
        this._map.layers.sort(this._sortLayers);
        this._setupTiles();
    },
    /** Need to toggle a Loading/notile graphic when changing zoom levels */
    loadLayer: function(layer, center) {
        var cur_scale;
        if (layer === this._activeLayerNum) return;
        // Grab current layer scale
        if (this._activeLayer && center) {
            cur_scale = this._activeLayer.scale;
        }
        this._activeLayer = this._map.layers[layer];
        this._activeLayerNum = layer;
        var left = this._elems.container[0].offsetLeft;
        var top = this._elems.container[0].offsetTop;
        if (cur_scale) {
            var new_scale = this._activeLayer.scale;
            var mult = (cur_scale.den * new_scale.num) / (cur_scale.num * new_scale.den);
            left = (left - center.x) * mult + center.x;
            top = (top - center.y) * mult + center.y;
            this._elems.container.css({left:left,top:top});
        }
        this.checkTiles(left, top);
        this._elems.overlay.css({width:this._activeLayer.width,height:this._activeLayer.height});
        this.overlay()
            .setScale(this._activeLayer.scale)
            .draw(true);
    },
    /** Overlays */
    overlay: function(cmd) {
        if (!this._overlay) {
            this._overlay = new OverlayContainer(this._elems.overlay);
            if (this._activeLayer) {
                this._overlay.setScale(this._activeLayer.scale);
            }
        }
        if (cmd) {
            if ($.isFunction(this._overlay[cmd])) {
                return this._overlay[cmd].apply(this._overlay, Array.prototype.slice.call(arguments, 1));
            }
        }
        return this._overlay;
    },
    _sortLayers: function(a, b) {
        // Sort Ascending
        return (a.scale.num / a.scale.den) - (b.scale.num / b.scale.den);
    },
    _setupTiles: function() {
        this._elems.tileCache.empty();
        this._tileCache = {};
        this._tiles = [];
        this._elems.container.css({left:0,top:0});
        this.loadLayer(0);
    },
    _createTile: function(x, y) {
        var tile = $('
')
            .css({left:x,top:y,
                width:this._map.tilesize,height:this._map.tilesize})
            .appendTo(this._elems.tileCache)
        $('')
            .attr('src',this._getImageForTile(x,y))
            .css({
                width:this._map.tilesize,
                height: this._map.tilesize
            })
            .appendTo(tile);
        if (!this._tileCache[x]) {
            this._tileCache[x] = {};
        }
        this._tileCache[x][y] = tile;
        this._tiles.push(tile);
    },
    _moveTile: function(tile, x, y) {
        // Remove from Cache
        this._tileCache[tile[0].offsetLeft][tile[0].offsetTop] = undefined;
        var img = tile.children();
        // Set blank image
        img.attr('src',this.options.blankImage);
        // Move Tile
        tile.css({left:x,top:y});
        // Update Image
        img.attr('src',this._getImageForTile(x,y));
        // update layer for tile
        tile.data('layer',this._activeLayerNum);
        // Add back into cache
        if (!this._tileCache[x]) {
            this._tileCache[x] = {};
        }
        this._tileCache[x][y] = tile;
    },
    _getTileForPoint: function(x,y) {
        if (this._tileCache[x] && this._tileCache[x][y]) {
            return this._tileCache[x][y];
        }
        return false;
    },
    _getImageForTile: function(x,y) {
        if (this._activeLayer.pieces[x] && this._activeLayer.pieces[x][y]) {
            return this._activeLayer.path + this._activeLayer.pieces[x][y];
        }
        return this.options.blankImage;
    },
    checkTiles: function(aX, aY) {
        if (this.element.is(':hidden')) {
            return;
        } else if (this._view === undefined) {
            this.render();
            return;
        }
        var l = (Math.floor(-aX / this._map.tilesize) * this._map.tilesize)
                - this._map.tilesize,
            t = (Math.floor(-aY / this._map.tilesize) * this._map.tilesize)
                - this._map.tilesize,
            r = l + this._view.w,
            b = t + this._view.h;

        //figure out where we have no tiles in our map rectangle
        var needed = [];
        var good = [];
        for (var y=t; y < b; y+=this._map.tilesize) {
            for (var x=l; x < r; x+=this._map.tilesize) {
                var tile = this._getTileForPoint(x, y);
                if (tile === false
                        || tile.data('layer')!=this._activeLayerNum) {
                    needed.push([x,y]);
                } else {
                    good.push(tile);
                }
            }
        }
        var free = [];
        for (var idx=0, idx_l=this._tiles.length; idx<idx_l; ++idx) {
            if (good.indexOf(this._tiles[idx]) == -1) {
                free.push(this._tiles[idx]);
            }
        }
        for (idx=0,idx_l=needed.length; idx<idx_l; ++idx) {
            if (free[idx]) {
                this._moveTile(free[idx], needed[idx][0], needed[idx][1]);
            } else {
                // Create new Tile
                this._createTile(needed[idx][0],needed[idx][1]);
            }
        }
    },
    _mouseStart: function(aEvt) {
        this.offset = this.element.offset();
        $.extend(this.offset, {
            click: { //Where click happened, relative to the element
                x:aEvt.pageX - this.offset.left,
                y:aEvt.pageY - this.offset.top
            },
            view: {
                x:this._elems.container[0].offsetLeft,
                y:this._elems.container[0].offsetTop
            }
        });
    },
    _mouseDrag: function(aEvt) {
        if ((this._ctr++ % 20)> 0 ) return;
        var o = {
            x:aEvt.pageX - this.offset.left,
            y:aEvt.pageY - this.offset.top
        };
        var p = {
            x:o.x - this.offset.click.x + this.offset.view.x,
            y:o.y - this.offset.click.y + this.offset.view.y
        };
        this._elems.container.css({left:p.x, top: p.y});
        this.checkTiles(p.x, p.y);
    },
    _mouseWheel: function(event, delta) {
        var layer = this._activeLayerNum + (delta < 0 ? -1 : 1);
        event.preventDefault();
        if (layer < 0 || layer >= this._map.layers.length) {
            return; // max zoom
        }
        var offset = this.element.offset();
        this.loadLayer(layer, {x:event.pageX - offset.left, y:event.pageY - offset.top});
    },
    _mouseStop: function(aEvt) {

    }
});

$.extend($.ui.interactiveMap, {
    version: "0.2"
});

})(jQuery);<commit_msg>Fix interactiveMap in IE 8<commit_after>/**
 * Interactive Map Widget
 * @copyright Copyright 2010
 * @author Edward Rudd <urkle at outoforder.cc>
 */
/*
 * This file is part of INQ Calculators.
 *
 * INQ Calculators is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * INQ Calculators is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with INQ Calculators.  If not, see <http://www.gnu.org/licenses/>.
 */
(function($) { //hide namespace

function parseScale(val) {
    var p = val.split(':');
    return {
        num: parseInt(p[0]),
        den: parseInt(p[1])
    };
}

function dirname (path) {
    // Modified from http://phpjs.org/functions/dirname
    return path.replace(/\/[^\/]*\/?$/, '');
}

function OverlayContainer(elem) {
    this.element = elem;
    // The starting scale
    this._scale = { num: 1, den: 1 };
    // List of jsGraphics wrappers
    this._elems = [];
    this._toDraw = [];
}
$.extend(OverlayContainer.prototype, {
    setScale: function(scale) {
        if (this._scale.num != scale.num || this._scale.den != scale.den) {
            this._scale.num = scale.num;
            this._scale.den = scale.den;
        }
        return this;
    },
    draw: function(force) {
        if (force) {
            this._toDraw = [];
            for (var i=0,l=this._elems.length; i<l; ++i) {
                var o = this._elems[i];
                var f = this['_draw_'+o.type];
                if ($.isFunction(f)) {
                    f.call(this,o);
                }
            }
        } else {
            while (this._toDraw.length) {
                var o = this._elems[this._toDraw.shift()];
                var f = this['_draw_'+o.type];
                if ($.isFunction(f)) {
                    f.call(this,o);
                }
            }
        }
        return this;
    },
    _draw_polygon: function(o) {
        if (!o.wrapper) {
            o.wrapper = $('
').appendTo(this.element);
        }
        o.wrapper.empty();
        o.data.draw(o.wrapper, this._scale, this.nextColor());
    },
    colors: [
        '#ffffff',
        '#ff00ff',
        '#00ffff',
        '#ffff00',
        '#ff0000',
        '#00ff00',
        '#0000ff',
        '#000000',
    ],
    nextColor: function() {
        this.color = ((this.color || 0) + 1) % this.colors.length;
        return this.colors[this.color];
    },
    addPolygon: function(polygon, offset) {
        var id = this._addObject('polygon', polygon, offset, true);
        return id;
    },
    _addObject: function(type, data, offset, toDraw) {
        var o = {
            type: type,
            data: data,
            offset: offset
        };
        this._elems.push(o);
        var id = this._elems.length-1;
        if (toDraw) {
            this._toDraw.push(id);
        }
        return id;
    }
});

$.widget('ui.interactiveMap', $.ui.mouse, {
    options: {
        map:'',
        blankImage:'images/blank.gif'
    },

    _create: function() {
        this._mouseInit();
        this._elems = {};
        var self = this;
        this.element
            .addClass('interactiveMap')
            .disableSelection()
            .mousewheel(function(event,delta) {self._mouseWheel(event,delta);});
        this._elems.view = $('
')
            .appendTo(this.element);
        this._elems.container = $('
')
            .appendTo(this._elems.view);
        this._elems.tileCache = $('
')
            .appendTo(this._elems.container);
        this._elems.overlay = $('
')
            .appendTo(this._elems.container);
        this.loadMap();
    },
    render: function() {
        if (this.element.is(':hidden') || !this._map) {
            // nothing to see here move along
            return;
        }
        // Called when the display needs to be recalculated (resize or show when previously hidden)
        var _viewwidth = this.element.innerWidth()
            || this.options.width || 400;
        var _viewheight = this.element.innerHeight()
            || this.options.height || 400;
        var tiles_x = Math.ceil(_viewwidth / this._map.tilesize) + 1;
        var tiles_y = Math.ceil(_viewheight / this._map.tilesize) + 1;
        this._view = {
            w: (tiles_x + 1) * this._map.tilesize,
            h: (tiles_y + 1) * this._map.tilesize
        };
        if (this._activeLayerNum !== undefined) {
            var p = this._elems.container.position();
            this.checkTiles(p.left, p.top);
            this.overlay().draw();
        }
    },
    destroy: function() {
        this._mouseDestroy();
        this.element.empty();
        this.element
            .removeClass('interactiveMap')
            .enableSelection();

        $.Widget.prototype.destroy.apply(this, arguments);
    },
    loadMap: function(map) {
        if (map) {
            this._setOption('map',map);
        }
        var self = this;
        $.get(this.options.map,undefined,function(xml) {
            self._loadXML(xml);
        },'xml');
    },
    _loadXML: function(xml) {
        var layers = $(xml).find("layer");
        var map = $(xml).find('map');
        this._map = {};
        this._map.tilesize = parseInt(map.attr('tilesize'));
        this._map.width = parseInt(map.attr('width'));
        this._map.height = parseInt(map.attr('height'));
        this._map.layers = [];
        for (var layer_itr=0,layer_len=layers.length; layer_itr<layer_len;
                ++layer_itr) {
            var _l = layers.eq(layer_itr);
            var _ll = {
                width: parseInt(_l.attr('width')),
                height: parseInt(_l.attr('height')),
                scale: parseScale(_l.attr('scale')),
                path: dirname(this.options.map)+'/'+_l.attr('path')+'/',
                pieces: {}
            }
            // Parse Pieces
            var pieces = _l.find('piece');
            for (var piece_itr=0,piece_len=pieces.length; piece_itr<piece_len;
                    ++piece_itr) {
                var _p = pieces.eq(piece_itr);
                var left = _p.attr('left'), top = _p.attr('top');
                if (!_ll.pieces[left]) {
                    _ll.pieces[left] = {};
                }
                _ll.pieces[left][top] = _p.attr('file');
            }
            this._map.layers.push(_ll);
        }
        this._map.layers.sort(this._sortLayers);
        this._setupTiles();
    },
    /** Need to toggle a Loading/notile graphic when changing zoom levels */
    loadLayer: function(layer, center) {
        var cur_scale;
        if (layer === this._activeLayerNum) return;
        // Grab current layer scale
        if (this._activeLayer && center) {
            cur_scale = this._activeLayer.scale;
        }
        this._activeLayer = this._map.layers[layer];
        this._activeLayerNum = layer;
        var p = this._elems.container.position();
        if (cur_scale) {
            var new_scale = this._activeLayer.scale;
            var mult = (cur_scale.den * new_scale.num) / (cur_scale.num * new_scale.den);
            p.left = (p.left - center.x) * mult + center.x;
            p.top = (p.top - center.y) * mult + center.y;
            this._elems.container.css({left:p.left,top:p.top});
        }
        this.checkTiles(p.left, p.top);
        this._elems.overlay.css({width:this._activeLayer.width,height:this._activeLayer.height});
        this.overlay()
            .setScale(this._activeLayer.scale)
            .draw(true);
    },
    /** Overlays */
    overlay: function(cmd) {
        if (!this._overlay) {
            this._overlay = new OverlayContainer(this._elems.overlay);
            if (this._activeLayer) {
                this._overlay.setScale(this._activeLayer.scale);
            }
        }
        if (cmd) {
            if ($.isFunction(this._overlay[cmd])) {
                return this._overlay[cmd].apply(this._overlay, Array.prototype.slice.call(arguments, 1));
            }
        }
        return this._overlay;
    },
    _sortLayers: function(a, b) {
        // Sort Ascending
        return (a.scale.num / a.scale.den) - (b.scale.num / b.scale.den);
    },
    _setupTiles: function() {
        this._elems.tileCache.empty();
        this._tileCache = {};
        this._tiles = [];
        this._elems.container.css({left:0,top:0});
        this.loadLayer(0);
    },
    _createTile: function(x, y) {
        var tile = $('
')
            .css({left:x,top:y,
                width:this._map.tilesize,height:this._map.tilesize})
            .appendTo(this._elems.tileCache);
        $('')
            .attr('src',this._getImageForTile(x,y))
            .css({
                width:this._map.tilesize,
                height: this._map.tilesize
            })
            .appendTo(tile);
        tile.data('position',{left:x, top:y});
        if (!this._tileCache[x]) {
            this._tileCache[x] = {};
        }
        this._tileCache[x][y] = tile;
        this._tiles.push(tile);
    },
    _moveTile: function(tile, x, y) {
        // Remove from Cache
        var p = tile.data('position');
        this._tileCache[p.left][p.top] = undefined;
        var img = tile.children();
        // Set blank image
        img.attr('src',this.options.blankImage);
        // Move Tile
        p = {left:x,top:y};
        tile.css(p);
        tile.data('position',p);
        // Update Image
        img.attr('src',this._getImageForTile(x,y));
        // update layer for tile
        tile.data('layer',this._activeLayerNum);
        // Add back into cache
        if (!this._tileCache[x]) {
            this._tileCache[x] = {};
        }
        this._tileCache[x][y] = tile;
    },
    _getTileForPoint: function(x,y) {
        if (this._tileCache[x] && this._tileCache[x][y]) {
            return this._tileCache[x][y];
        }
        return false;
    },
    _getImageForTile: function(x,y) {
        if (this._activeLayer.pieces[x] && this._activeLayer.pieces[x][y]) {
            return this._activeLayer.path + this._activeLayer.pieces[x][y];
        }
        return this.options.blankImage;
    },
    checkTiles: function(aX, aY) {
        if (this.element.is(':hidden')) {
            return;
        } else if (this._view === undefined) {
            this.render();
            return;
        }
        var l = (Math.floor(-aX / this._map.tilesize) * this._map.tilesize)
                - this._map.tilesize,
            t = (Math.floor(-aY / this._map.tilesize) * this._map.tilesize)
                - this._map.tilesize,
            r = l + this._view.w,
            b = t + this._view.h;

        //figure out where we have no tiles in our map rectangle
        var needed = [];
        var good = [];
        for (var y=t; y < b; y+=this._map.tilesize) {
            for (var x=l; x < r; x+=this._map.tilesize) {
                var tile = this._getTileForPoint(x, y);
                if (tile === false
                        || tile.data('layer')!=this._activeLayerNum) {
                    needed.push([x,y]);
                } else {
                    good.push(tile);
                }
            }
        }
        var free = [];
        for (var idx=0, idx_l=this._tiles.length; idx<idx_l; ++idx) {
            if (good.indexOf(this._tiles[idx]) == -1) {
                free.push(this._tiles[idx]);
            }
        }
        for (idx=0,idx_l=needed.length; idx<idx_l; ++idx) {
            if (free[idx]) {
                this._moveTile(free[idx], needed[idx][0], needed[idx][1]);
            } else {
                // Create new Tile
                this._createTile(needed[idx][0],needed[idx][1]);
            }
        }
    },
    _mouseStart: function(aEvt) {
        this.offset = this.element.offset();
        var p = this._elems.container.position();
        $.extend(this.offset, {
            click: { //Where click happened, relative to the element
                x:aEvt.pageX - this.offset.left,
                y:aEvt.pageY - this.offset.top
            },
            view: {
                x:p.left,
                y:p.top
            }
        });
    },
    _mouseDrag: function(aEvt) {
        if ((this._ctr++ % 20)> 0 ) return;
        var o = {
            x:aEvt.pageX - this.offset.left,
            y:aEvt.pageY - this.offset.top
        };
        var p = {
            x:o.x - this.offset.click.x + this.offset.view.x,
            y:o.y - this.offset.click.y + this.offset.view.y
        };
        this._elems.container.css({left:p.x, top: p.y});
        this.checkTiles(p.x, p.y);
    },
    _mouseWheel: function(event, delta) {
        var layer = this._activeLayerNum + (delta < 0 ? -1 : 1);
        event.preventDefault();
        if (layer < 0 || layer >= this._map.layers.length) {
            return; // max zoom
        }
        var offset = this.element.offset();
        this.loadLayer(layer, {x:event.pageX - offset.left, y:event.pageY - offset.top});
    },
    _mouseStop: function(aEvt) {

    }
});

$.extend($.ui.interactiveMap, {
    version: "0.2"
});

})(jQuery);<|endoftext|>


<commit_before>hqDefine("reports/js/filters/case_list_explorer", ['jquery', 'underscore', 'knockout'], function($, _, ko) {
    'use strict';

    var applySuggestions = function(allSuggestions){
        // Adds the required properties to filter the case type autocomplete dropdowns
        var self = this;
        self.currentCaseType = ko.observable('');
        $('#report_filter_case_type').on('change', function(e){
            self.currentCaseType(e.val);
        });

        self.suggestedProperties = ko.computed(function(){
            if (self.currentCaseType() === ''){
                return allSuggestions;
            }
            return _.filter(allSuggestions, function(prop){
                return prop['case_type'] === self.currentCaseType() || prop['case_type'] === null;
            });
        });
    };

    var Property = function ($parent, name, label, editable, hidden) {
        var self = {};
        self.name = ko.observable(name).trimmed();

        self.label = ko.observable(label || name).trimmed();

        self.name.subscribe(function(newValue){
            // Set the label value to the value of the name if it isn't otherwise set
            if (!self.label() && newValue !== 'undefined'){ // atwho sometimes sets the value to the string 'undefined'
                var val = newValue.replace('@', '').replace(/_/g, ' ').replace(/\w\S*/g, function(txt){
                    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
                });
                self.label(val);
            }
        });

        self.meta_type = ko.computed(function(){
            var value = _.find($parent.allSuggestions, function(prop){
                return prop.name === self.name();
            });
            if (value){
                return value.meta_type;
            }
            return null;
        });
        self.editable = ko.observable(editable === undefined ? true : editable);
        self.hidden = ko.observable(hidden || false);

        return self;
    };

    var casePropertyColumnsViewModel = function(initialColumns, allCaseProperties) {
        var self = {
            allSuggestions: allCaseProperties,
        };
        applySuggestions.call(self, allCaseProperties);

        self.properties = ko.observableArray();
        for (var i = 0; i < initialColumns.length; i++){
            var initialColumn = initialColumns[i];
            self.properties.push(Property(self, initialColumn.name, initialColumn.label, initialColumn.editable, initialColumn.hidden));
        }

        self.addProperty = function () {
            self.properties.push(Property(self, '', ''));
        };

        self.removeProperty = function (property) {
            self.properties.remove(property);
            $('#fieldset_explorer_columns').trigger('change');
        };

        self.allProperties = ko.computed(function(){
            return JSON.stringify(ko.toJS(self.properties()));
        });

        return self;
    };

    var caseSearchXpathViewModel = function(allSuggestions){
        var self = {};
        applySuggestions.call(self, allSuggestions);
        return self;
    };

    return {
        casePropertyColumns: casePropertyColumnsViewModel,
        caseSearchXpath: caseSearchXpathViewModel,
    };
});
<commit_msg>Shorten URLs a bit<commit_after>hqDefine("reports/js/filters/case_list_explorer", ['jquery', 'underscore', 'knockout'], function($, _, ko) {
    'use strict';

    var applySuggestions = function(allSuggestions){
        // Adds the required properties to filter the case type autocomplete dropdowns
        var self = this;
        self.currentCaseType = ko.observable('');
        $('#report_filter_case_type').on('change', function(e){
            self.currentCaseType(e.val);
        });

        self.suggestedProperties = ko.computed(function(){
            if (self.currentCaseType() === ''){
                return allSuggestions;
            }
            return _.filter(allSuggestions, function(prop){
                return prop['case_type'] === self.currentCaseType() || prop['case_type'] === null;
            });
        });
    };

    var Property = function ($parent, name, label, editable, hidden) {
        var self = {};
        self.name = ko.observable(name).trimmed();

        self.label = ko.observable(label || name).trimmed();

        self.name.subscribe(function(newValue){
            // Set the label value to the value of the name if it isn't otherwise set
            if (!self.label() && newValue !== 'undefined'){ // atwho sometimes sets the value to the string 'undefined'
                var val = newValue.replace('@', '').replace(/_/g, ' ').replace(/\w\S*/g, function(txt){
                    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
                });
                self.label(val);
            }
        });

        self.meta_type = ko.computed(function(){
            var value = _.find($parent.allSuggestions, function(prop){
                return prop.name === self.name();
            });
            if (value){
                return value.meta_type;
            }
            return null;
        });
        self.editable = ko.observable(editable === undefined ? true : editable);
        self.hidden = ko.observable(hidden || false);

        return self;
    };

    var casePropertyColumnsViewModel = function(initialColumns, allCaseProperties) {
        var self = {
            allSuggestions: allCaseProperties,
        };
        applySuggestions.call(self, allCaseProperties);

        self.properties = ko.observableArray();
        for (var i = 0; i < initialColumns.length; i++){
            var initialColumn = initialColumns[i];
            self.properties.push(Property(self, initialColumn.name, initialColumn.label, initialColumn.editable, initialColumn.hidden));
        }

        self.addProperty = function () {
            self.properties.push(Property(self, '', ''));
        };

        self.removeProperty = function (property) {
            self.properties.remove(property);
            $('#fieldset_explorer_columns').trigger('change');
        };

        self.allProperties = ko.computed(function(){

            return JSON.stringify(
                _.map(self.properties(), function(property){
                    var pertinent_props = {name: property.name(), label: property.label()};
                    if (property.hidden()){
                        pertinent_props.hidden = property.hidden();
                    }
                    if (property.meta_type()){
                        pertinent_props.meta_type = property.meta_type();
                    }
                    return pertinent_props;
                })
            );
        });

        return self;
    };

    var caseSearchXpathViewModel = function(allSuggestions){
        var self = {};
        applySuggestions.call(self, allSuggestions);
        return self;
    };

    return {
        casePropertyColumns: casePropertyColumnsViewModel,
        caseSearchXpath: caseSearchXpathViewModel,
    };
});
<|endoftext|>


<commit_before>var pluginifierBuilder = require("../lib/build/export");

module.exports = function(grunt){

	var task =  function(){
		var done = this.async();
		var options = this.data;
		// make sure things look right
		["system","outputs"].forEach(function(name){
			if(!options[name]) {
				grunt.fail.warn("steal-export needs a "+name+" property.");
			}
		});

		pluginifierBuilder(options,
			grunt.config('meta.steal.export-helpers'),
			grunt.config('meta.steal.modules') ).then(function(){
			done();
		}, done);
	};

	grunt.registerMultiTask("stealExport", "Create a 'plugin' version of your project which is not dependent on Steal.", task);
	grunt.registerMultiTask("steal-export", "Create a 'plugin' version of your project which is not dependent on Steal.", task);
};
<commit_msg>removing stealExport<commit_after>var pluginifierBuilder = require("../lib/build/export");

module.exports = function(grunt){

	var task =  function(){
		var done = this.async();
		var options = this.data;
		// make sure things look right
		["system","outputs"].forEach(function(name){
			if(!options[name]) {
				grunt.fail.warn("steal-export needs a "+name+" property.");
			}
		});

		pluginifierBuilder(options,
			grunt.config('meta.steal.export-helpers'),
			grunt.config('meta.steal.modules') ).then(function(){
			done();
		}, done);
	};

	grunt.registerMultiTask("steal-export", "Create a 'plugin' version of your project which is not dependent on Steal.", task);
};
<|endoftext|>


<commit_before>import * as Filters from './Filters';

export const SOMERVILLE = 'somerville';
export const NEW_BEDFORD = 'new_bedford';
export const DEMO = 'demo';

export function hasStudentPhotos(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === NEW_BEDFORD) return false;
  return false;
}

const ORDERED_DISABILITY_VALUES_MAP = {
  [NEW_BEDFORD]: [
    "Does Not Apply",
    "Low-Less Than 2hrs/week",
    "Low-2+ hrs/week",
    "Moderate",
    "High"
  ],
  [SOMERVILLE]: [
    // also include null
    'Low < 2',
    'Low >= 2',
    'Moderate',
    'High'
  ]
};

export function orderedDisabilityValues(districtKey) {
  return ORDERED_DISABILITY_VALUES_MAP[districtKey] || [];
}

// Includes if they "exited" the 504
export function hasInfoAbout504Plan(maybeStudent504Field) {
  if (maybeStudent504Field === undefined) return false;
  if (maybeStudent504Field === null) return false;
  if (maybeStudent504Field === '') return false;
  if (maybeStudent504Field === '504') return true; // Somerville
  if (maybeStudent504Field === 'Not 504') return false; // Somerville
  if (maybeStudent504Field === 'NotIn504') return false; // Somerville & New Bedford
  if (maybeStudent504Field === 'Exited') return true; // New Bedford
  if (maybeStudent504Field === 'Active') return true; // New Bedford

  return true;
}

// Renders a table for `SlicePanels` that works differently for different
// districts.
export function renderSlicePanelsDisabilityTable(districtKey, options = {}) {
  const {createItemFn, renderTableFn} = options;

  const key = 'sped_level_of_need';
  const itemsFromValues = orderedDisabilityValues(districtKey).map(value => {
    return createItemFn(value, Filters.Equal(key, value));
  });

  // Somerville uses a null value for no disability, while New Bedford
  // uses a separate value to describe that explicitly.
  const items = (districtKey === SOMERVILLE)
    ? [createItemFn('None', Filters.Null(key))].concat(itemsFromValues)
    : itemsFromValues;
  return renderTableFn({items, title: 'Disability'});
}

// Check educator labels to see if the educator belongs to
// the NGE and 10GE experience teams.  This label only applies to
// Somerville.
export function inExperienceTeam(educatorLabels) {
  return (educatorLabels.indexOf('shs_experience_team') !== -1);
}

const ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE = {
  'pic': 10,
  'cap': 100,
  'brn': 200,
  'hea': 300,
  'kdy': 300,
  'afas': 300,
  'escs': 300,
  'wsns': 300,
  'whcs': 300,
  'nw': 400,
  'shs': 500,
  'fc': 500,
  'sped': 600
};

export function sortSchoolSlugsByGrade(districtKey, slugA, slugB) {
  if (districtKey === SOMERVILLE) {
    return ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE[slugA] - ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE[slugB];
  }

  return slugA.localeCompare(slugB);
}

export function supportsHouse(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This only applies to Somerville HS.
export function shouldDisplayHouse(school) {
  return (school && school.local_id === 'SHS');
}

export function somervilleHouses() {
  return [
    'Beacon',
    'Broadway',
    'Elm',
    'Highland'
  ];
}

export function supportsCounselor(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This only applies to high schools.
export function shouldDisplayCounselor(school) {
  return (school && school.school_type === 'HS');
}

export function supportsSpedLiaison(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

export function supportsExcusedAbsences(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This returns user-facing text to describe their program and placement
// in one label.
export function prettyProgramText(programAssigned, spedPlacement) {
  return (programAssigned && programAssigned !== 'Reg Ed')
    ? programAssigned === 'Sp Ed' ? spedPlacement : programAssigned
    : null;
}

// What is the eventNoteTypeId to use in user-facing text about how to support
// students with high absences?
export function eventNoteTypeIdForAbsenceSupportMeeting(districtKey) {
  if (districtKey === NEW_BEDFORD) return 400; // bbst
  if (districtKey === SOMERVILLE) return 300; // sst

  return 300;
}

// What choices do educators have for taking notes in the product?
export function takeNotesChoices(districtKey) {
  if (districtKey === SOMERVILLE || districtKey === DEMO) {
    return {
      leftEventNoteTypeIds: [300, 301, 302],
      rightEventNoteTypeIds: [305, 306, 304]
    };
  }

  if (districtKey === NEW_BEDFORD) {
    return {
      leftEventNoteTypeIds: [400, 302, 304],
      rightEventNoteTypeIds: []
    };
  }

  throw new Error(`unsupported districtKey: ${districtKey}`);
}

// In tables of students, what eventNoteTypeIds should be shown as columns with notes
// about those students?
export function studentTableEventNoteTypeIds(districtKey, schoolType) {
  if (districtKey === NEW_BEDFORD) return [400];
  const isSomervilleOrDemo = (districtKey === SOMERVILLE || districtKey === DEMO);
  if (!isSomervilleOrDemo) throw new Error(`unsupported districtKey: ${districtKey}`);

  if (isSomervilleOrDemo && schoolType === 'HS') return [300, 305, 306];
  if (isSomervilleOrDemo) return [300, 301];  // Includes elementary/middle, Capuano early childhood,
                                              // and SPED.
}<commit_msg>Add const to PerDistrict.js<commit_after>import * as Filters from './Filters';

export const SOMERVILLE = 'somerville';
export const NEW_BEDFORD = 'new_bedford';
export const BEDFORD = 'bedford';
export const DEMO = 'demo';

export function hasStudentPhotos(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === NEW_BEDFORD) return false;
  return false;
}

const ORDERED_DISABILITY_VALUES_MAP = {
  [NEW_BEDFORD]: [
    "Does Not Apply",
    "Low-Less Than 2hrs/week",
    "Low-2+ hrs/week",
    "Moderate",
    "High"
  ],
  [SOMERVILLE]: [
    // also include null
    'Low < 2',
    'Low >= 2',
    'Moderate',
    'High'
  ]
};

export function orderedDisabilityValues(districtKey) {
  return ORDERED_DISABILITY_VALUES_MAP[districtKey] || [];
}

// Includes if they "exited" the 504
export function hasInfoAbout504Plan(maybeStudent504Field) {
  if (maybeStudent504Field === undefined) return false;
  if (maybeStudent504Field === null) return false;
  if (maybeStudent504Field === '') return false;
  if (maybeStudent504Field === '504') return true; // Somerville
  if (maybeStudent504Field === 'Not 504') return false; // Somerville
  if (maybeStudent504Field === 'NotIn504') return false; // Somerville & New Bedford
  if (maybeStudent504Field === 'Exited') return true; // New Bedford
  if (maybeStudent504Field === 'Active') return true; // New Bedford

  return true;
}

// Renders a table for `SlicePanels` that works differently for different
// districts.
export function renderSlicePanelsDisabilityTable(districtKey, options = {}) {
  const {createItemFn, renderTableFn} = options;

  const key = 'sped_level_of_need';
  const itemsFromValues = orderedDisabilityValues(districtKey).map(value => {
    return createItemFn(value, Filters.Equal(key, value));
  });

  // Somerville uses a null value for no disability, while New Bedford
  // uses a separate value to describe that explicitly.
  const items = (districtKey === SOMERVILLE)
    ? [createItemFn('None', Filters.Null(key))].concat(itemsFromValues)
    : itemsFromValues;
  return renderTableFn({items, title: 'Disability'});
}

// Check educator labels to see if the educator belongs to
// the NGE and 10GE experience teams.  This label only applies to
// Somerville.
export function inExperienceTeam(educatorLabels) {
  return (educatorLabels.indexOf('shs_experience_team') !== -1);
}

const ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE = {
  'pic': 10,
  'cap': 100,
  'brn': 200,
  'hea': 300,
  'kdy': 300,
  'afas': 300,
  'escs': 300,
  'wsns': 300,
  'whcs': 300,
  'nw': 400,
  'shs': 500,
  'fc': 500,
  'sped': 600
};

export function sortSchoolSlugsByGrade(districtKey, slugA, slugB) {
  if (districtKey === SOMERVILLE) {
    return ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE[slugA] - ORDERED_SOMERVILLE_SCHOOL_SLUGS_BY_GRADE[slugB];
  }

  return slugA.localeCompare(slugB);
}

export function supportsHouse(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This only applies to Somerville HS.
export function shouldDisplayHouse(school) {
  return (school && school.local_id === 'SHS');
}

export function somervilleHouses() {
  return [
    'Beacon',
    'Broadway',
    'Elm',
    'Highland'
  ];
}

export function supportsCounselor(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This only applies to high schools.
export function shouldDisplayCounselor(school) {
  return (school && school.school_type === 'HS');
}

export function supportsSpedLiaison(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

export function supportsExcusedAbsences(districtKey) {
  if (districtKey === SOMERVILLE) return true;
  if (districtKey === DEMO) return true;
  return false;
}

// This returns user-facing text to describe their program and placement
// in one label.
export function prettyProgramText(programAssigned, spedPlacement) {
  return (programAssigned && programAssigned !== 'Reg Ed')
    ? programAssigned === 'Sp Ed' ? spedPlacement : programAssigned
    : null;
}

// What is the eventNoteTypeId to use in user-facing text about how to support
// students with high absences?
export function eventNoteTypeIdForAbsenceSupportMeeting(districtKey) {
  if (districtKey === NEW_BEDFORD) return 400; // bbst
  if (districtKey === SOMERVILLE) return 300; // sst

  return 300;
}

// What choices do educators have for taking notes in the product?
export function takeNotesChoices(districtKey) {
  if (districtKey === SOMERVILLE || districtKey === DEMO) {
    return {
      leftEventNoteTypeIds: [300, 301, 302],
      rightEventNoteTypeIds: [305, 306, 304]
    };
  }

  if (districtKey === NEW_BEDFORD) {
    return {
      leftEventNoteTypeIds: [400, 302, 304],
      rightEventNoteTypeIds: []
    };
  }

  throw new Error(`unsupported districtKey: ${districtKey}`);
}

// In tables of students, what eventNoteTypeIds should be shown as columns with notes
// about those students?
export function studentTableEventNoteTypeIds(districtKey, schoolType) {
  if (districtKey === NEW_BEDFORD) return [400];
  const isSomervilleOrDemo = (districtKey === SOMERVILLE || districtKey === DEMO);
  if (!isSomervilleOrDemo) throw new Error(`unsupported districtKey: ${districtKey}`);

  if (isSomervilleOrDemo && schoolType === 'HS') return [300, 305, 306];
  if (isSomervilleOrDemo) return [300, 301];  // Includes elementary/middle, Capuano early childhood,
                                              // and SPED.
}<|endoftext|>


<commit_before>var is = require('is');
var clone = require('clone');
var InputTypes = require('./InputTypes');

var FormMixin = {
	getInitialState: function(){
		return {
			initial_values_source_version: this.____getInitialValuesSourceVersion(this.props),
			data: this.____getInitialValues(this.props),
			errors: {},
			submit_attempts: 0
		};
	},
	componentWillReceiveProps: function(new_props){
		var initial_values_source_version = this.____getInitialValuesSourceVersion(new_props);
		if(this.state.initial_values_source_version !== initial_values_source_version){
			this.setState({
				initial_values_source_version: initial_values_source_version,
				data: this.____getInitialValues(new_props),
				errors: {},
				submit_attempts: 0
			});
		}
	},
	Form_validate: function(){
		var fields = this.____buildSchema();
		var data = this.state.data;
		return validateFields(fields, data);
	},
	Form_onSubmit: function(e){
		if(e && e.preventDefault){
			e.preventDefault();
		}
		var self = this;
		this.setState({
			submit_attempts: this.state.submit_attempts + 1,
			errors: this.Form_validate()
		}, function(){
			if(is.empty(self.state.errors)){
				self.____onSubmit(self.state.data);
			}else{
				self.____onSubmitFail(self.state.errors);
			}
		});
	},
	Form_onChange: function(field_name, new_value){
		var self = this;
		var fields = this.____buildSchema();
		var should_validate = this.state.submit_attempts > 0;
		var data = this.state.data;

		data[field_name] = new_value;

		this.setState({
			data: data,
			errors: should_validate ? validateFields(fields, data) : null
		}, function(){
			self.____onFormChanged(field_name, new_value);
		});
	},
	Form_buildInput: function(field, field_name){
		var input = InputTypes.getInputByType(field.type);
		return input.component({
			field: field,
			value: this.state.data[field_name],
			onChange: this.Form_onChange,
			field_name: field_name
		});
	},
	Form_reset: function(){
		this.setState({data: this.____getInitialValues(this.props), errors: {}, submit_attempts: 0});
	},
	Form_areChangesMade: function(props){
		return !is.equal(this.state.data, this.____getInitialValues(props || this.props));
	},

	//Below are functions that the child can implement
	____buildSchema: function(){
		if(is.fn(this.buildSchema)){
			return this.buildSchema();
		}else{
			console.warn("react-loose-forms FormMixin expects there to be a funciton on the compoent called buildSchema that returns the schema for the form.");
			return {};
		}
	},
	____getInitialValuesSourceVersion: function(props){
		if(is.fn(this.getInitialValuesSourceVersion)){
			return this.getInitialValuesSourceVersion(props);
		}
		return null;
	},
	____getInitialValues: function(props){
		if(is.fn(this.getInitialValues)){
			return clone(this.getInitialValues(props) || {});
		}
		return {};
	},
	____onFormChanged: function(field_name, new_value){
		if(is.fn(this.onFormChanged)){
			this.onFormChanged(field_name, new_value);
		}
	},
	____onSubmit: function(data){
		if(is.fn(this.props.onSubmit)){
			this.props.onSubmit(data);
		}
	},
	____onSubmitFail: function(errors){
		if(is.fn(this.props.onSubmitFail)){
			this.props.onSubmitFail(errors);
		}
	}
};

var defaultValidationFn = function(value, field){
	var valid = false;
	if(is.boolean(value)){
		valid = value === true;
	}else if(is.number(value)){
		valid = value !== 0;
	}else if(is.date(value)){
		valid = true;
	}else{
		valid = !is.empty(value);
	}
	return valid || field.label + ' is required';
};

var validateFields = function(fields, data){
	var errors = {};
	Object.keys(fields).forEach(function(field_name){
		var field = fields[field_name];
		var validation_fn = defaultValidationFn;
		if(is.fn(field.validate)){
			validation_fn = field.validate;
		}else{
			var input = InputTypes.getInputByType(field.type);
			if(is.fn(input && input.validate)){
				validation_fn = input.validate;
			}
		}
		var resp = validation_fn(data[field_name], field);
		if(resp !== true){
			errors[field_name] = is.string(resp) ? resp : 'Please check your input.';
		}
	});
	return errors;
};

module.exports = FormMixin;
<commit_msg>Form_buildInput no longer needs the field_name<commit_after>var is = require('is');
var clone = require('clone');
var InputTypes = require('./InputTypes');

var FormMixin = {
	getInitialState: function(){
		return {
			initial_values_source_version: this.____getInitialValuesSourceVersion(this.props),
			data: this.____getInitialValues(this.props),
			errors: {},
			submit_attempts: 0
		};
	},
	componentWillReceiveProps: function(new_props){
		var initial_values_source_version = this.____getInitialValuesSourceVersion(new_props);
		if(this.state.initial_values_source_version !== initial_values_source_version){
			this.setState({
				initial_values_source_version: initial_values_source_version,
				data: this.____getInitialValues(new_props),
				errors: {},
				submit_attempts: 0
			});
		}
	},
	Form_validate: function(){
		var fields = this.Form_buildSchema();
		var data = this.state.data;
		return validateFields(fields, data);
	},
	Form_onSubmit: function(e){
		if(e && e.preventDefault){
			e.preventDefault();
		}
		var self = this;
		this.setState({
			submit_attempts: this.state.submit_attempts + 1,
			errors: this.Form_validate()
		}, function(){
			if(is.empty(self.state.errors)){
				self.____onSubmit(self.state.data);
			}else{
				self.____onSubmitFail(self.state.errors);
			}
		});
	},
	Form_onChange: function(field_name, new_value){
		var self = this;
		var fields = this.Form_buildSchema();
		var should_validate = this.state.submit_attempts > 0;
		var data = this.state.data;

		data[field_name] = new_value;

		this.setState({
			data: data,
			errors: should_validate ? validateFields(fields, data) : null
		}, function(){
			self.____onFormChanged(field_name, new_value);
		});
	},
	Form_buildInput: function(field){
		var input = InputTypes.getInputByType(field.type);
		return input.component({
			field: field,
			value: this.state.data[field.name],
			onChange: this.Form_onChange
		});
	},
	Form_reset: function(){
		this.setState({data: this.____getInitialValues(this.props), errors: {}, submit_attempts: 0});
	},
	Form_areChangesMade: function(props){
		return !is.equal(this.state.data, this.____getInitialValues(props || this.props));
	},
	Form_buildSchema: function(){
		var schema = this.____buildSchema();
		Object.keys(schema).forEach(function(name){
			schema[name].name = name;
		});
	},

	//Below are functions that the child can implement
	____buildSchema: function(){
		if(is.fn(this.buildSchema)){
			return this.buildSchema();
		}else{
			console.warn("react-loose-forms FormMixin expects there to be a funciton on the compoent called buildSchema that returns the schema for the form.");
			return {};
		}
	},
	____getInitialValuesSourceVersion: function(props){
		if(is.fn(this.getInitialValuesSourceVersion)){
			return this.getInitialValuesSourceVersion(props);
		}
		return null;
	},
	____getInitialValues: function(props){
		if(is.fn(this.getInitialValues)){
			return clone(this.getInitialValues(props) || {});
		}
		return {};
	},
	____onFormChanged: function(field_name, new_value){
		if(is.fn(this.onFormChanged)){
			this.onFormChanged(field_name, new_value);
		}
	},
	____onSubmit: function(data){
		if(is.fn(this.props.onSubmit)){
			this.props.onSubmit(data);
		}
	},
	____onSubmitFail: function(errors){
		if(is.fn(this.props.onSubmitFail)){
			this.props.onSubmitFail(errors);
		}
	}
};

var defaultValidationFn = function(value, field){
	var valid = false;
	if(is.boolean(value)){
		valid = value === true;
	}else if(is.number(value)){
		valid = value !== 0;
	}else if(is.date(value)){
		valid = true;
	}else{
		valid = !is.empty(value);
	}
	return valid || field.label + ' is required';
};

var validateFields = function(fields, data){
	var errors = {};
	Object.keys(fields).forEach(function(field_name){
		var field = fields[field_name];
		var validation_fn = defaultValidationFn;
		if(is.fn(field.validate)){
			validation_fn = field.validate;
		}else{
			var input = InputTypes.getInputByType(field.type);
			if(is.fn(input && input.validate)){
				validation_fn = input.validate;
			}
		}
		var resp = validation_fn(data[field_name], field);
		if(resp !== true){
			errors[field_name] = is.string(resp) ? resp : 'Please check your input.';
		}
	});
	return errors;
};

module.exports = FormMixin;
<|endoftext|>


<commit_before>if (enyo && enyo.version) {
	enyo.version["enyo-ilib"] = "2.5.0";
}
<commit_msg>Update version string to 2.5.1-pre.1<commit_after>if (enyo && enyo.version) {
	enyo.version["enyo-ilib"] = "2.5.1-pre.1";
}
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require_self
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require leather
//= require jquery-ui/core
//= require jquery-ui/datepicker
//= require jquery-ui/position
//= require jquery-ui/widget
//= require jquery-ui/resizable
//= require jquery.ui.timepicker
//= require jquery.iframe-transport.js
//= require jquery.fileupload.js
//= require codemirror
//= require codemirror/modes/xml
//= require codemirror/modes/htmlmixed
//= require codemirror/modes/overlay
//= require codemirror/addons/fold/xml-fold
//= require codemirror/addons/edit/closetag
//= require codemirror/addons/edit/closebrackets
//= require chosen.jquery
//= require medium-editor.min
//= require fitvids.js
//= require jquery.instagram
//= require_tree .

window.Storytime || (window.Storytime = {})
window.Storytime.Dashboard = {}

document.addEventListener("DOMContentLoaded", function(event) {

  // $("#responsive-videos").fitVids();

  $("#responsive-videos").fitVids({ customSelector: "iframe[src^='http://sharevideo.redbull.com'],iframe[src^='https://sharevideo.redbull.com'], iframe[src^='http://www.thrashermagazine.com'], iframe[src^='https://embed.theguardian.com'], iframe[src^='http://embed.theguardian.com'], iframe[src^='http://theberrics.com']"});

  $('ul.dropdown-menu.dropdown-menu-right li:last-child').remove();

	$(function() {
	  $('.menu_burger').click(function() {
	  $('.menu').slideToggle();
	  return false;
	  });
})

// solution for hover on mobile
$('body').bind('touchstart', function() {});
//

$('.moving-banner').insertAfter('.list_item:nth-child(6)');

});

<commit_msg>all combinations for berric iframe<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require_self
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require leather
//= require jquery-ui/core
//= require jquery-ui/datepicker
//= require jquery-ui/position
//= require jquery-ui/widget
//= require jquery-ui/resizable
//= require jquery.ui.timepicker
//= require jquery.iframe-transport.js
//= require jquery.fileupload.js
//= require codemirror
//= require codemirror/modes/xml
//= require codemirror/modes/htmlmixed
//= require codemirror/modes/overlay
//= require codemirror/addons/fold/xml-fold
//= require codemirror/addons/edit/closetag
//= require codemirror/addons/edit/closebrackets
//= require chosen.jquery
//= require medium-editor.min
//= require fitvids.js
//= require jquery.instagram
//= require_tree .

window.Storytime || (window.Storytime = {})
window.Storytime.Dashboard = {}

document.addEventListener("DOMContentLoaded", function(event) {

  // $("#responsive-videos").fitVids();

  $("#responsive-videos").fitVids({ customSelector: "iframe[src^='http://sharevideo.redbull.com'],iframe[src^='https://sharevideo.redbull.com'], iframe[src^='http://www.thrashermagazine.com'], iframe[src^='https://embed.theguardian.com'], iframe[src^='http://embed.theguardian.com'], iframe[src^='http://theberrics.com'], iframe[src^='https://theberrics.com'], iframe[src^='http://www.theberrics.com'], , iframe[src^='https://www.theberrics.com']"});

  $('ul.dropdown-menu.dropdown-menu-right li:last-child').remove();

	$(function() {
	  $('.menu_burger').click(function() {
	  $('.menu').slideToggle();
	  return false;
	  });
})

// solution for hover on mobile
$('body').bind('touchstart', function() {});
//

$('.moving-banner').insertAfter('.list_item:nth-child(6)');

});

<|endoftext|>


<commit_before>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
'use strict';

module.exports = function(agent , database) {
  console.log(agent.getAgent())
	//
  var ObjectId = require('mongodb').ObjectId;
	var Spooky = require('spooky');
  var EventEmitter = require('events').EventEmitter;
  var domain = require('domain');

	var bucket;
  var ipQueue = [];
  var ipQueueIndex = 0;
  var child_processes = 0;

    //
    var Buckets = database.model('Buckets');

    //
    var setBucket =  function(bucketObj){
    	 bucket = bucketObj;
         if(bucket.urls.length>0){
            for(let i=0; i < bucket.urls.length; i++){
                bucket.urls[i].visited = 0;
                bucket.urls[i].statusText = 'No status yet';
            };
         }

    	 console.log(bucket);
    	 console.log('bucket set in visitor');
         startUpdateDaemon();
    };

    //
    var getBucket = function(){
    	return bucket;
    };

    //
    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            //
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //
    var notifyDelete = function(_id){
         console.log('Bucket with'+ _id +'deleted');
         if(bucket){
             if(bucket._id == _id){
                console.log('This bucket was deleted');
                setTimeout(function(){
                    process.exit(0);
                } , 10000);
             }
             else{
                 console.log('Not this one 1..');
             }

         }
         else{
            console.log('Not this one..');
         }
    }

    //
    var visitWith = function(ip){
        console.log('Adding %s to queue' , ip);
        if(ipQueue.indexOf(ip)<0){
            ipQueue.push(ip);
        }
        else{
            console.log('ip alredy used or currently in use');
        }

        if(ipQueue.length == 1){
            startVisitingDaemon();
        }
    }

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    var V_WORKER = function(){
        var workerEvents = new EventEmitter;

        var visit = function(ip , urlObj , index , userAgent){
            console.log('visit starting with '+ip+' and '+urlObj.urlName);

            let spooky = Spooky.create({
                child: {
                    transport: 'http',
                    proxy: ip
                },

                casper: {
                    logLevel: 'debug',
                    verbose: true,
                    options: {
                        clientScripts: ['public/js/vendors/jquery.min.js'],
                        pageSettings: {
                            webSecurityEnabled: false
                        }
                    }
                }
            },

            function(err){
               if (err) {
                    e = new Error('Failed to initialize SpookyJS');
                    e.details = err;
                    throw e;
                }

                //
                (function(url , selector , index){
                    //
                    console.log(userAgent);
                    spooky.start();
                    spooky.then(function () {
                        this.userAgent(userAgent);
                        this.page.customHeaders = {
                            "Referer": 'http://www.minicards.xyz'
                        };
                    });
                    spooky.thenOpen(url);
                    spooky.then([{url:url , selector:selector , index:index} , function(){
                        //
                        this.done = function(err , status){
                            if(err){
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                            else{
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                        }

                       if(selector=='none'){
                            this.then(function(){
                                this.wait(10000 , function(){
                                    this.done(null , true);
                                });
                            });
                        }

                        else{
                            this.then(function(){
                                this.waitForSelector(selector , function(){
                                    this.thenClick(selector , function() {
                                        this.done(null , true);
                                    });

                                } , function(){
                                    this.done(true , null);
                                } , 10000);
                            });
                        }
                    }]);
                })(urlObj.urlName , urlObj.selector , index);

                //
                spooky.run();
            });

            //
            spooky.on('console', function (line) {
                console.log(line);
            });

            //
            spooky.on('error', function (e, stack) {
                console.error(stack||e);
                workerEvents.emit('done' , {status:stack?stack:e , index:0});
            });

            //
            spooky.on('done', function (status) {
                workerEvents.emit('done' , status);
            });

            //self destruct this instance in 8 minutes
            setTimeout(function(){
                console.log('Instance destroyed');
                spooky.destroy();
                child_processes--;
            } , 8*60000);
        };

        return {
            visit:visit,
            status:workerEvents
        }
    }
    //++++++++++++++++++++++++++++++++END++++++++++++++++++++++++++++++++++++++++++

    //updateBucket after every 120 secs of activity
    function startUpdateDaemon(){
        let timer = 0;
        console.log('Starting cron daemon');
        setInterval(function(){
            bucket.lastActive = Date.now()+'';
            Buckets.update(
                {_id : ObjectId(bucket._id)},
                bucket,
                function(err , result){
                    if(err){
                        console.log(err);
                        res.status(500).send('Database error during cron update in visitor');
                    }
                    else {
                        timer+=2;
                        if(timer >= 120){
                            console.log('Maximum uptime of three hours exceeded exiting....');
                            process.exit(0);
                        }
                        console.log('bucket updated in cron job');
                    }
                }
          );
        } , 120000);
    }

    //
    function startVisitingDaemon(){
       let v_worker = V_WORKER();

       (function fillVisiting(){
            console.log('fill visiting called');
            if(ipQueueIndex < ipQueue.length && child_processes<=20){
               child_processes+=bucket.urls.length;
               console.log(child_processes+' child_processes currently running');

               //spin all new workers for each urls
               for(let i=0; i < bucket.urls.length; i++){
                   v_worker.visit(ipQueue[ipQueueIndex] , bucket.urls[i] , i , agent.getAgent());
               }

               ipQueueIndex++;
            }
            else{
                console.log('Good ip shortage');
            }

            //
            setTimeout(function(){
                return fillVisiting();
            } , 20000);
       })();

      //
      v_worker.status.on('done' , function(status){
            console.log(status);
            bucket.urls[status.index].statusText = status.status;
            bucket.urls[status.index].visited++;
        });
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
      notifyDelete:notifyDelete
	}
};
<commit_msg>Signed-off-by: codemuhammed <codemuhammed@gmail.com><commit_after>/* This module uses a give ip to visit the whole urls in the bucket assigned to it
*/
'use strict';

module.exports = function(agent , database) {
  console.log(agent.getAgent())
	//
  var ObjectId = require('mongodb').ObjectId;
	var Spooky = require('spooky');
  var EventEmitter = require('events').EventEmitter;
  var domain = require('domain');

	var bucket;
  var ipQueue = [];
  var ipQueueIndex = 0;
  var child_processes = 0;

    //
    var Buckets = database.model('Buckets');

    //
    var setBucket =  function(bucketObj){
    	 bucket = bucketObj;
         if(bucket.urls.length>0){
            for(let i=0; i < bucket.urls.length; i++){
                bucket.urls[i].visited = 0;
                bucket.urls[i].statusText = 'No status yet';
            };
         }

    	 console.log(bucket);
    	 console.log('bucket set in visitor');
         startUpdateDaemon();
    };

    //
    var getBucket = function(){
    	return bucket;
    };

    //
    var updateBucket = function(bucketObj , meta){
    	console.log(meta);
    	if(bucket){
            //
            if(bucketObj._id+'' == bucket._id){
	           if(meta.action == 0){
	           	   console.log('Deleting url in this bucket');
                   bucket.urls.splice(meta.index , 1);
	           }
	           else if(meta.action == 1) {
                   console.log('Updating url in this bucket');
                   bucket = bucketObj;
	           }
	    	}
	    	else{
	    	   console.log('Just passing by');
	    	}
    	}
    	else{
    		 console.log('Bucket empty here');
    	}
    }

    //
    var notifyDelete = function(_id){
         console.log('Bucket with'+ _id +'deleted');
         if(bucket){
             if(bucket._id == _id){
                console.log('This bucket was deleted');
                setTimeout(function(){
                    process.exit(0);
                } , 10000);
             }
             else{
                 console.log('Not this one 1..');
             }

         }
         else{
            console.log('Not this one..');
         }
    }

    //
    var visitWith = function(ip){
        console.log('Adding %s to queue' , ip);
        if(ipQueue.indexOf(ip)<0){
            ipQueue.push(ip);
        }
        else{
            console.log('ip alredy used or currently in use');
        }

        if(ipQueue.length == 1){
            startVisitingDaemon();
        }
    }

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    var V_WORKER = function(){
        var workerEvents = new EventEmitter;

        var visit = function(ip , urlObj , index , userAgent){
            console.log('visit starting with '+ip+' and '+urlObj.urlName);

            let spooky = Spooky.create({
                child: {
                    transport: 'http',
                    proxy: ip
                },

                casper: {
                    logLevel: 'debug',
                    verbose: true,
                    options: {
                        clientScripts: ['public/js/vendors/jquery.min.js'],
                        pageSettings: {
                            webSecurityEnabled: false,
                            userAgent:userAgent
                        }
                    }
                }
            },

            function(err){
               if (err) {
                    e = new Error('Failed to initialize SpookyJS');
                    e.details = err;
                    throw e;
                }

                //
                (function(url , selector , index){
                    //
                    console.log(userAgent);
                    spooky.start();
                    spooky.then(function () {
                        this.page.customHeaders = {
                            "Referer": 'http://www.minicards.xyz'
                        };
                    });
                    spooky.thenOpen(url);
                    spooky.then([{url:url , selector:selector , index:index} , function(){
                        //
                        this.done = function(err , status){
                            if(err){
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                            else{
                                this.emit('done', {status:this.getCurrentUrl() , index:index});
                                return phantom.clearCookies();
                            }
                        }

                       if(selector=='none'){
                            this.then(function(){
                                this.wait(10000 , function(){
                                    this.done(null , true);
                                });
                            });
                        }

                        else{
                            this.then(function(){
                                this.waitForSelector(selector , function(){
                                    this.thenClick(selector , function() {
                                        this.done(null , true);
                                    });

                                } , function(){
                                    this.done(true , null);
                                } , 10000);
                            });
                        }
                    }]);
                })(urlObj.urlName , urlObj.selector , index);

                //
                spooky.run();
            });

            //
            spooky.on('console', function (line) {
                console.log(line);
            });

            //
            spooky.on('error', function (e, stack) {
                console.error(stack||e);
                workerEvents.emit('done' , {status:stack?stack:e , index:0});
            });

            //
            spooky.on('done', function (status) {
                workerEvents.emit('done' , status);
            });

            //self destruct this instance in 8 minutes
            setTimeout(function(){
                console.log('Instance destroyed');
                spooky.destroy();
                child_processes--;
            } , 8*60000);
        };

        return {
            visit:visit,
            status:workerEvents
        }
    }
    //++++++++++++++++++++++++++++++++END++++++++++++++++++++++++++++++++++++++++++

    //updateBucket after every 120 secs of activity
    function startUpdateDaemon(){
        let timer = 0;
        console.log('Starting cron daemon');
        setInterval(function(){
            bucket.lastActive = Date.now()+'';
            Buckets.update(
                {_id : ObjectId(bucket._id)},
                bucket,
                function(err , result){
                    if(err){
                        console.log(err);
                        res.status(500).send('Database error during cron update in visitor');
                    }
                    else {
                        timer+=2;
                        if(timer >= 120){
                            console.log('Maximum uptime of three hours exceeded exiting....');
                            process.exit(0);
                        }
                        console.log('bucket updated in cron job');
                    }
                }
          );
        } , 120000);
    }

    //
    function startVisitingDaemon(){
       let v_worker = V_WORKER();

       (function fillVisiting(){
            console.log('fill visiting called');
            if(ipQueueIndex < ipQueue.length && child_processes<=20){
               child_processes+=bucket.urls.length;
               console.log(child_processes+' child_processes currently running');

               //spin all new workers for each urls
               for(let i=0; i < bucket.urls.length; i++){
                   v_worker.visit(ipQueue[ipQueueIndex] , bucket.urls[i] , i , agent.getAgent());
               }

               ipQueueIndex++;
            }
            else{
                console.log('Good ip shortage');
            }

            //
            setTimeout(function(){
                return fillVisiting();
            } , 20000);
       })();

      //
      v_worker.status.on('done' , function(status){
            console.log(status);
            bucket.urls[status.index].statusText = status.status;
            bucket.urls[status.index].visited++;
        });
    }

	return {
	    visitWith:visitWith,
	    getBucket:getBucket,
	    setBucket:setBucket,
	    updateBucket:updateBucket,
      notifyDelete:notifyDelete
	}
};
<|endoftext|>


<commit_before>var evals = [ 'undefined', 'null', 'false', 'true' ];

var _filters = {
	regex: function(value) {
		return new RegExp(value, 'i');
	},

	exists: function(value) {
		if(value === true)
			return { $ne: null };
		else
			return { $eq: null };
	}
};

module.exports = function(properties, filters) {
	filters = _.mapValues(filters, function(value, key) {
		return _.isString(value) ? _filters[value] : value;
	});

	return function(req, res, next) {
		req.query = _.mapValues(_.pick(req.query, properties), function(value, key) {
			value = decodeURIComponent(value);

			if(evals.indexOf(value) > -1) value = eval(value);

			return filters[key] ? filters[key](value) : value;
		});

		next();
	};
};
<commit_msg>Use keys from filter object in allowed properties.<commit_after>var evals = [ 'undefined', 'null', 'false', 'true' ];

var _filters = {
	regex: function(value) {
		return new RegExp(value, 'i');
	},

	exists: function(value) {
		if(value === true)
			return { $ne: null };
		else
			return { $eq: null };
	}
};

module.exports = function(properties, filters) {
	properties = _.union(properties, _.keys(filters));

	filters = _.mapValues(filters, function(value, key) {
		return _.isString(value) ? _filters[value] : value;
	});

	return function(req, res, next) {
		req.query = _.mapValues(_.pick(req.query, properties), function(value, key) {
			value = decodeURIComponent(value);

			if(evals.indexOf(value) > -1) value = eval(value);

			return filters[key] ? filters[key](value) : value;
		});

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


<commit_before>const { Box } = require('../examples/lib')

const res =

  // wrap the function into the Box
  Box( x => x + 1 )

  // apply our wrapped function to the Box'ed value 2
  .ap(Box(2))

// This uses switched order comparing
// to the Fantasy Land applicative spec
// ap :: f a ~> f (a -> b) -> f b

console.log(res) //=> Box(3)

// apply Box'ed curried function
// to 1st and then 2nd argument
const res1 = Box( x => y => x + y )
  .ap(Box(2)).ap(Box(3))

console.log(res1)

// lift f to function on Box'es
// 2nd argument 'fx' is a lifted object (e.g. Box'ed), which has 'map' method
// 'fx.map(f)' is 'f' lifted and partially applied to 'fx'
// which result is lifted and applied to 'fx' with 'ap' method
const liftA2 = (f, fx, fy) =>
  fx.map(f).ap(fy)

const add = x => y => x + y

console.log(liftA2(add, Box(2), Box(4)))
// -> Box(6)
<commit_msg>Add static syntax examples<commit_after>const { Box } = require('../examples/lib')

const res =

  // wrap the function into the Box
  Box( x => x + 1 )

  // apply our wrapped function to the Box'ed value 2
  .ap(Box(2))

// This uses switched order comparing
// to the Fantasy Land applicative spec
// ap :: f a ~> f (a -> b) -> f b

console.log(res) //=> Box(3)

// apply Box'ed curried function
// to 1st and then 2nd argument
const res1 = Box( x => y => x + y )
  .ap(Box(2)).ap(Box(3))

console.log(res1)

// lift f to function on Box'es
// 2nd argument 'fx' is a lifted object (e.g. Box'ed), which has 'map' method
// 'fx.map(f)' is 'f' lifted and partially applied to 'fx'
// which result is lifted and applied to 'fx' with 'ap' method
const liftA2 = (f, fx, fy) =>
  fx.map(f).ap(fy)

const add = x => y => x + y

console.log(liftA2(add, Box(2), Box(4)))
// -> Box(6)

console.log(liftA2(x => y => x - y, Box(2), Box(4)))
// -> Box(-2)

// static syntax
// ap(Fg)(Fx, Fy)
const ap = Fg => (Fx, Fy) => Fg.ap(Fx).ap(Fy)

// liftA2cur(g)(Fx, Fy)
const liftA2cur = g => (Fx, Fy) => liftA2(g, Fx, Fy)
<|endoftext|>


<commit_before>'use strict';

angular.module('dragonfly.treecontroller', [])

.controller("treeController",['$scope', '$window', 'dataService', function ($scope, $window, dataService) {

  $scope.$watch(function(){
      return dataService.data();
    }, function(v){
    if(v === undefined) return;
    if(Object.keys(v).length <= 1) return;
    var sensorNodes = {
      "name": "Sensors",
      "children": []
    }
    for(var i in v){
      sensorNodes.children.push({
        "name": v[i].name
      })
    }
    buildTree(sensorNodes);
  });

  function buildTree(treeData){
  // Set the dimensions and margins of the diagram
    var margin = {top: 20, right: 20, bottom: 30, left: 20},
        width = $('#sensor-tree')[0].clientWidth - margin.right - margin.left,
        height = 100 - margin.top - margin.bottom;

    // append the svg object to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("#sensor-tree").append("svg")
        .attr("width", width + margin.right + margin.left)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate("
              + margin.left + "," + margin.top + ")");

    var i = 0,
        duration = 750,
        root;

    // declares a tree layout and assigns the size
    var treemap = d3.tree().size([width, height]);

    // Assigns parent, children, height, depth
    root = d3.hierarchy(treeData, function(d) { return d.children; });
    root.x0 = width/2;
    root.y0 = 0;

    // Collapse after the second level
    root.children.forEach(collapse);

    update(root);

    // Collapse the node and all it's children
    function collapse(d) {
      if(d.children) {
        d._children = d.children
        d._children.forEach(collapse)
        d.children = null
      }
    }

    function update(source) {

      // Assigns the x and y position for the nodes
      var treeData = treemap(root);

      // Compute the new tree layout.
      var nodes = treeData.descendants(),
          links = treeData.descendants().slice(1);

      // Normalize for fixed-depth.
      nodes.forEach(function(d){ d.y = d.depth * 50});

      // ****************** Nodes section ***************************

      // Update the nodes...
      var node = svg.selectAll('g.node')
          .data(nodes, function(d) {return d.id || (d.id = ++i); });

      // Enter any new modes at the parent's previous position.
      var nodeEnter = node.enter().append('g')
          .attr('class', 'node')
          .attr("transform", function(d) {
            return "translate(" + source.x0 + "," + source.y0 + ")";
        })
        .on('click', click);

      // Add Circle for the nodes
      nodeEnter.append('circle')
          .attr('class', 'node')
          .attr('r', 1e-6)
          .style("fill", function(d) {
              return d._children ? "lightsteelblue" : "#fff";
          });

      // Add labels for the nodes
      nodeEnter.append('text')
          .attr("y", function(d) { return d.children || d._children ? -8 : 20; })
          .attr("text-anchor", 'middle')
          .text(function(d) { return d.data.name; });

      // UPDATE
      var nodeUpdate = nodeEnter.merge(node);

      // Transition to the proper position for the node
      nodeUpdate.transition()
        .duration(duration)
        .attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
         });

      // Update the node attributes and style
      nodeUpdate.select('circle.node')
        .attr('r', 10)
        .style("fill", function(d) {
            return d._children ? "lightsteelblue" : "#fff";
        })
        .attr('cursor', 'pointer');

      // Remove any exiting nodes
      var nodeExit = node.exit().transition()
          .duration(duration)
          .attr("transform", function(d) {
              return "translate(" + source.x + "," + source.y + ")";
          })
          .remove();

      // On exit reduce the node circles size to 0
      nodeExit.select('circle')
        .attr('r', 1e-6);

      // On exit reduce the opacity of text labels
      nodeExit.select('text')
        .style('fill-opacity', 1e-6);

      // ****************** links section ***************************

      // Update the links...
      var link = svg.selectAll('path.link')
          .data(links, function(d) { return d.id; });

      // Enter any new links at the parent's previous position.
      var linkEnter = link.enter().insert('path', "g")
          .attr("class", "link")
          .attr('d', function(d){
            var o = {x: source.x0, y: source.y0}
            return diagonal(o, o)
          });

      // UPDATE
      var linkUpdate = linkEnter.merge(link);

      // Transition back to the parent element position
      linkUpdate.transition()
          .duration(duration)
          .attr('d', function(d){ return diagonal(d, d.parent) });

      // Remove any exiting links
      var linkExit = link.exit().transition()
          .duration(duration)
          .attr('d', function(d) {
            var o = {x: source.x, y: source.y}
            return diagonal(o, o)
          })
          .remove();

      // Store the old positions for transition.
      nodes.forEach(function(d){
        d.x0 = d.x;
        d.y0 = d.y;
      });

      // Creates a curved (diagonal) path from parent to the child nodes
      function diagonal(source, target) {
        var d = {
          'source': source,
          'target':target
        }
        return "M" + d.source.x + "," + d.source.y
          + "C" + d.source.x +  "," + (d.source.y + d.target.y) / 2
          + " " + d.target.x + "," + (d.source.y + d.target.y) / 2
          + " " + d.target.x + "," + d.target.y;
      }

      // Toggle children on click.
      function click(d) {
        if (d.children) {
            d._children = d.children;
            d.children = null;
          } else {
            d.children = d._children;
            d._children = null;
          }
        update(d);
        dataService.select(d.data.name)
        $scope.$apply();
      }
    }
  }
  dataService.select('waterTemp')
}]);

<commit_msg>adjusting margins<commit_after>'use strict';

angular.module('dragonfly.treecontroller', [])

.controller("treeController",['$scope', '$window', 'dataService', function ($scope, $window, dataService) {

  $scope.$watch(function(){
      return dataService.data();
    }, function(v){
    if(v === undefined) return;
    if(Object.keys(v).length <= 1) return;
    var sensorNodes = {
      "name": "Sensors",
      "children": []
    }
    for(var i in v){
      sensorNodes.children.push({
        "name": v[i].name
      })
    }
    buildTree(sensorNodes);
  });

  function buildTree(treeData){
  // Set the dimensions and margins of the diagram
    var margin = {top: 30, right: 20, bottom: 20, left: 20},
        width = $('#sensor-tree')[0].clientWidth - margin.right - margin.left,
        height = 110 - margin.top - margin.bottom;

    // append the svg object to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("#sensor-tree").append("svg")
        .attr("width", width + margin.right + margin.left)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate("
              + margin.left + "," + margin.top + ")");

    var i = 0,
        duration = 750,
        root;

    // declares a tree layout and assigns the size
    var treemap = d3.tree().size([width, height]);

    // Assigns parent, children, height, depth
    root = d3.hierarchy(treeData, function(d) { return d.children; });
    root.x0 = width/2;
    root.y0 = 0;

    // Collapse after the second level
    root.children.forEach(collapse);

    update(root);

    // Collapse the node and all it's children
    function collapse(d) {
      if(d.children) {
        d._children = d.children
        d._children.forEach(collapse)
        d.children = null
      }
    }

    function update(source) {

      // Assigns the x and y position for the nodes
      var treeData = treemap(root);

      // Compute the new tree layout.
      var nodes = treeData.descendants(),
          links = treeData.descendants().slice(1);

      // Normalize for fixed-depth.
      nodes.forEach(function(d){ d.y = d.depth * 50});

      // ****************** Nodes section ***************************

      // Update the nodes...
      var node = svg.selectAll('g.node')
          .data(nodes, function(d) {return d.id || (d.id = ++i); });

      // Enter any new modes at the parent's previous position.
      var nodeEnter = node.enter().append('g')
          .attr('class', 'node')
          .attr("transform", function(d) {
            return "translate(" + source.x0 + "," + source.y0 + ")";
        })
        .on('click', click);

      // Add Circle for the nodes
      nodeEnter.append('circle')
          .attr('class', 'node')
          .attr('r', 1e-6)
          .style("fill", function(d) {
              return d._children ? "lightsteelblue" : "#fff";
          });

      // Add labels for the nodes
      nodeEnter.append('text')
          .attr("y", function(d) { return d.children || d._children ? -14 : 20; })
          .attr("text-anchor", 'middle')
          .text(function(d) { return d.data.name; });

      // UPDATE
      var nodeUpdate = nodeEnter.merge(node);

      // Transition to the proper position for the node
      nodeUpdate.transition()
        .duration(duration)
        .attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
         });

      // Update the node attributes and style
      nodeUpdate.select('circle.node')
        .attr('r', 10)
        .style("fill", function(d) {
            return d._children ? "lightsteelblue" : "#fff";
        })
        .attr('cursor', 'pointer');

      // Remove any exiting nodes
      var nodeExit = node.exit().transition()
          .duration(duration)
          .attr("transform", function(d) {
              return "translate(" + source.x + "," + source.y + ")";
          })
          .remove();

      // On exit reduce the node circles size to 0
      nodeExit.select('circle')
        .attr('r', 1e-6);

      // On exit reduce the opacity of text labels
      nodeExit.select('text')
        .style('fill-opacity', 1e-6);

      // ****************** links section ***************************

      // Update the links...
      var link = svg.selectAll('path.link')
          .data(links, function(d) { return d.id; });

      // Enter any new links at the parent's previous position.
      var linkEnter = link.enter().insert('path', "g")
          .attr("class", "link")
          .attr('d', function(d){
            var o = {x: source.x0, y: source.y0}
            return diagonal(o, o)
          });

      // UPDATE
      var linkUpdate = linkEnter.merge(link);

      // Transition back to the parent element position
      linkUpdate.transition()
          .duration(duration)
          .attr('d', function(d){ return diagonal(d, d.parent) });

      // Remove any exiting links
      var linkExit = link.exit().transition()
          .duration(duration)
          .attr('d', function(d) {
            var o = {x: source.x, y: source.y}
            return diagonal(o, o)
          })
          .remove();

      // Store the old positions for transition.
      nodes.forEach(function(d){
        d.x0 = d.x;
        d.y0 = d.y;
      });

      // Creates a curved (diagonal) path from parent to the child nodes
      function diagonal(source, target) {
        var d = {
          'source': source,
          'target':target
        }
        return "M" + d.source.x + "," + d.source.y
          + "C" + d.source.x +  "," + (d.source.y + d.target.y) / 2
          + " " + d.target.x + "," + (d.source.y + d.target.y) / 2
          + " " + d.target.x + "," + d.target.y;
      }

      // Toggle children on click.
      function click(d) {
        if (d.children) {
            d._children = d.children;
            d.children = null;
          } else {
            d.children = d._children;
            d._children = null;
          }
        update(d);
        dataService.select(d.data.name)
        $scope.$apply();
      }
    }
  }
  dataService.select('waterTemp')
}]);

<|endoftext|>


<commit_before>// @flow
import Action from '../lib/Action';
import type { walletExportTypeChoices } from '../../types/walletExportTypes';

export type WalletImportFromFileParams = {
  filePath: string,
  walletName: ?string,
  walletPassword: ?string,
};

// ======= WALLET ACTIONS =======

export default class WalletsActions {
  createWallet: Action<{ name: string, password: ?string }> = new Action();
  // eslint-disable-next-line max-len
  restoreWallet: Action<{recoveryPhrase: string, walletName: string, walletPassword: ?string, type?: string }> = new Action();
  importWalletFromFile: Action<WalletImportFromFileParams> = new Action();
  deleteWallet: Action<{ walletId: string }> = new Action();
  sendMoney: Action<{ receiver: string, amount: string, password: ?string }> = new Action();
  chooseWalletExportType: Action<{ walletExportType: walletExportTypeChoices }> = new Action();
  generateCertificate: Action<{ filePath: string }> = new Action();
  updateCertificateStep: Action<any> = new Action();
  closeCertificateGeneration: Action<any> = new Action();
  setCertificateTemplate: Action<{ selectedTemplate: string }> = new Action();
  finishCertificate: Action<any> = new Action();
}
<commit_msg>[DDW-355] Renames 'password' param to 'spendingPassword'<commit_after>// @flow
import Action from '../lib/Action';
import type { walletExportTypeChoices } from '../../types/walletExportTypes';

export type WalletImportFromFileParams = {
  filePath: string,
  walletName: ?string,
  walletPassword: ?string,
};

// ======= WALLET ACTIONS =======

export default class WalletsActions {
  createWallet: Action<{ name: string, spendingPassword: ?string }> = new Action();
  // eslint-disable-next-line max-len
  restoreWallet: Action<{recoveryPhrase: string, walletName: string, walletPassword: ?string, type?: string }> = new Action();
  importWalletFromFile: Action<WalletImportFromFileParams> = new Action();
  deleteWallet: Action<{ walletId: string }> = new Action();
  sendMoney: Action<{ receiver: string, amount: string, password: ?string }> = new Action();
  chooseWalletExportType: Action<{ walletExportType: walletExportTypeChoices }> = new Action();
  generateCertificate: Action<{ filePath: string }> = new Action();
  updateCertificateStep: Action<any> = new Action();
  closeCertificateGeneration: Action<any> = new Action();
  setCertificateTemplate: Action<{ selectedTemplate: string }> = new Action();
  finishCertificate: Action<any> = new Action();
}
<|endoftext|>