<commit_before>/**
 * Default settings
 */
window.settings = window.settings || {
    SERVER: "localhost:8000",
    TILES: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
};

/** Until the 42 issues and pull requests are fixed in Leaflet core */
L.extend(L.GeoJSON, {
    latLngsToCoords: function (layer) {
        var coords = function coords (latlng) {
            return [latlng.lng, latlng.lat];
        };
        if (layer.getLatLng) {
            return coords(layer.getLatLng());
        }
        else if (layer instanceof L.Polygon) {
            // A polygon can theorically have holes, thus list of rings.
            return [_.map(layer.getLatLngs(), function (latlng) {
                return coords(latlng);
            })];
        }
        else if (layer instanceof L.Polyline) {
            return _.map(layer.getLatLngs(), function (latlng) {return coords(latlng);});
        }
        else throw "Could not export layer coordinates";
    },
});

var Item = Backbone.Model.extend({
    popup: function () {
        var tpl = this.definition.templatePopup();
        return tpl(this.toJSON());
    },

    getLayer: function () {
        if (!this.layer) {
            var geomfield = this.definition.geomField();
            if (!geomfield) return;

            var factories = {
                'point': function (coords) {return L.circleMarker([coords[1], coords[0]]);},
                'line': function (coords) {return L.polyline(L.GeoJSON.coordsToLatLngs(coords));},
                'polygon': function (coords) {return L.polygon(L.GeoJSON.coordsToLatLngs(coords[0]));},
            };

            var coords = this.get(geomfield.name);
            if (typeof coords === 'string') {
                coords = JSON.parse(coords);
            }
            this.layer = factories[geomfield.type](coords);
        }
        return this.layer;
    },

    setLayer: function (layer) {
        var geomfield = this.definition.geomField();
        if (!geomfield) return;

        var coords = L.GeoJSON.latLngsToCoords(layer)
          , attrs = {};
        attrs[geomfield.name] = JSON.stringify(coords);
        this.set(attrs);
    },
});

var ItemList = Backbone.Collection.extend({
    model: Item,

    initialize: function (definition) {
        this.definition = definition;
    },

    url: function () {
        return URI.build({hostname:settings.SERVER, path: '/data/' + this.definition.id});
    },

    parse: function(response) {
        return response.data;
    },

    /**
     * Override instanciation to link with Definition instance.
     */
    _prepareModel: function() {
        var m = Backbone.Collection.prototype._prepareModel.apply(this, arguments);
        m.definition = this.definition;
        return m;
    },
});

var Definition = Backbone.Model.extend({
    url: function () {
        return URI.build({hostname:settings.SERVER, path: 'definitions/' + this.id});
    },

    schema: {
        id:  { type: 'Hidden', title: '' },
        title: 'Text',
        description: 'Text',
        fields: { type: 'List', itemType: 'Object', subSchema: {
            name: { validators: ['required'] },
            description: { validators: ['required'] },
            type: { type: 'Select', options: ['int', 'string', 'decimal', 'boolean',
                                              'email', 'url', 'point', 'line', 'polygon'] }
        }}
    },

    isReady: function () {
        return this.attributes.fields && this.attributes.fields.length > 0;
    },

    whenReady: function (cb) {
        if (this.isReady())
            cb();
        else {
            this.once('change', function () {
                this.whenReady(cb);
            }, this);
        }
    },

    itemSchema: function () {
        if (!this.isReady())
            throw "Definition is not ready. Fetch it first.";
        var typeMapping = {
            'int': 'Number',
            'string': 'Text',
            'boolean': 'Checkbox'
        }
        var geom = function (f) {
            return {type: 'TextArea',
                    editorAttrs: {style: 'display: none'},
                    help: f.description + ' (on map)'};
        };
        var fieldMapping = {
            'default': function (f) {
                var d = {help: f.description}
                  , t = typeMapping[f.type];
                if (t) d.type = t;
                return d;
            },
            'decimal': function (f) {
                var d = fieldMapping['default'](field);
                d.editorAttrs = {pattern: '[-+]?[0-9]*\.?[0-9]+'};
                return d;
            },
            'email': function (f) {
                var d = fieldMapping['default'](field);
                d.validators = ['required', 'email'];
                return d;
            },
            'url': function (f) {
                var d = fieldMapping['default'](field);
                d.validators = ['required', 'url'];
                return d;
            },
            'point': geom,
            'line': geom,
            'polygon': geom,
        };
        var schema = {};
        // Add Backbone.Forms fields from Daybed definition
        $(this.attributes.fields).each(function (i, field) {
            var defaultschema = fieldMapping['default']
              , build = fieldMapping[field.type] || defaultschema;
            schema[field.name] = build(field);
        });
        return schema;
    },

    mainFields: function () {
        var geomField = this.geomField();
        if (!geomField)
            return this.attributes.fields;
        return this.attributes.fields.filter(function (f) {
            return f.name != geomField.name;
        });
    },

    /**
     * Returns the first field whose type is Geometry.
     */
    geomField: function () {
        for (i in this.attributes.fields) {
            var f = this.attributes.fields[i];
            if (f.type == 'point' || f.type == 'line' || f.type == 'polygon')
                return f;
        }
        return null;
    },

    templatePopup: function () {
        var c = '
';
        $(this.mainFields()).each(function (i, f) {
            c += '
{{ ' + f.name + ' }}
'
        });
        c += '
';
        return Mustache.compile(c);
    },

    tableContent: function () {
        var tpl = '

' +
                  '{{#fields}}{{name}}	{{/fields}}'+
                  '

';
        return Mustache.compile(tpl)({fields: this.mainFields()});
    },

    templateRow: function () {
        var c = '
';
        $(this.mainFields()).each(function (i, f) {
            c += '{{ ' + f.name + ' }}	'
        });
        c += '
';
        return Mustache.compile(c);
    },
});

var FormView = Backbone.View.extend({
    model: null,
    tagName: "div",
    className: "well",

    template: Mustache.compile('
{{ title }}
' +
                               '

' +
                               'Cancel ' +
                               'Save'),
    templateError: Mustache.compile('{{ msg }}'),

    events: {
        "click #submit": "submit",
        "click #cancel": "cancel",
    },

    initialize: function () {
        this.instance = new this.model({});
        if (!this.instance.schema && this.options.definition) {
            this.instance.definition = this.options.definition;
            this.instance.schema = this.options.definition.itemSchema();
        }
        this.instance.on('change', this.refresh.bind(this));
        this.instance.on('sync', this.success.bind(this));
        this.instance.on('error', this.showErrors.bind(this));
        this.form = new Backbone.Form({
            model: this.instance
        });
    },

    render: function () {
        this.$el.html(this.template(this));
        this.$('#form').html(this.form.render().el);
        this.delegateEvents();
        return this;
    },

    cancel: function (e) {
        e.preventDefault();
        return false;
    },

    submit: function(e) {
        e.preventDefault();
        this.$el.find('.field-error').remove();
        this.form.commit();
        return false;
    },

    success: function (model, response, options) {
        return false;
    },

    showErrors: function (model, xhr, options) {
        try {
            var descriptions = JSON.parse(xhr.responseText);
            $(descriptions.errors).each(L.Util.bind(function (i, e) {
                var name = e.name.split('.')[0];
                this.$el.find("[name='" + name + "']")
                    .after(this.templateError({msg: e.description}));
            }, this));
        }
        catch (e) {
            this.$el.html(this.templateError({msg: xhr.responseText}));
        }
    },

    /**
     * Refresh field values from instance attributes.
     */
    refresh: function () {
        for (f in this.instance.changed) {
            if (f == 'id') continue;
            var formfield = this.$('[name='+ f + ']');
            if (formfield.length == 0)
                console.warn("Could not find form field '" + f + "'");
            formfield.val(this.instance.get(f));
        }
    }
});
<commit_msg>Rewrote form refresh<commit_after>/**
 * Default settings
 */
window.settings = window.settings || {
    SERVER: "localhost:8000",
    TILES: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
};

/** Until the 42 issues and pull requests are fixed in Leaflet core */
L.extend(L.GeoJSON, {
    latLngsToCoords: function (layer) {
        var coords = function coords (latlng) {
            return [latlng.lng, latlng.lat];
        };
        if (layer.getLatLng) {
            return coords(layer.getLatLng());
        }
        else if (layer instanceof L.Polygon) {
            // A polygon can theorically have holes, thus list of rings.
            return [_.map(layer.getLatLngs(), function (latlng) {
                return coords(latlng);
            })];
        }
        else if (layer instanceof L.Polyline) {
            return _.map(layer.getLatLngs(), function (latlng) {return coords(latlng);});
        }
        else throw "Could not export layer coordinates";
    },
});

var Item = Backbone.Model.extend({
    popup: function () {
        var tpl = this.definition.templatePopup();
        return tpl(this.toJSON());
    },

    getLayer: function () {
        if (!this.layer) {
            var geomfield = this.definition.geomField();
            if (!geomfield) return;

            var factories = {
                'point': function (coords) {return L.circleMarker([coords[1], coords[0]]);},
                'line': function (coords) {return L.polyline(L.GeoJSON.coordsToLatLngs(coords));},
                'polygon': function (coords) {return L.polygon(L.GeoJSON.coordsToLatLngs(coords[0]));},
            };

            var coords = this.get(geomfield.name);
            if (typeof coords === 'string') {
                coords = JSON.parse(coords);
            }
            this.layer = factories[geomfield.type](coords);
        }
        return this.layer;
    },

    setLayer: function (layer) {
        var geomfield = this.definition.geomField();
        if (!geomfield) return;

        var coords = L.GeoJSON.latLngsToCoords(layer)
          , attrs = {};
        attrs[geomfield.name] = JSON.stringify(coords);
        this.set(attrs);
    },
});

var ItemList = Backbone.Collection.extend({
    model: Item,

    initialize: function (definition) {
        this.definition = definition;
    },

    url: function () {
        return URI.build({hostname:settings.SERVER, path: '/data/' + this.definition.id});
    },

    parse: function(response) {
        return response.data;
    },

    /**
     * Override instanciation to link with Definition instance.
     */
    _prepareModel: function() {
        var m = Backbone.Collection.prototype._prepareModel.apply(this, arguments);
        m.definition = this.definition;
        return m;
    },
});

var Definition = Backbone.Model.extend({
    url: function () {
        return URI.build({hostname:settings.SERVER, path: 'definitions/' + this.id});
    },

    schema: {
        id:  { type: 'Hidden', title: '' },
        title: 'Text',
        description: 'Text',
        fields: { type: 'List', itemType: 'Object', subSchema: {
            name: { validators: ['required'] },
            description: { validators: ['required'] },
            type: { type: 'Select', options: ['int', 'string', 'decimal', 'boolean',
                                              'email', 'url', 'point', 'line', 'polygon'] }
        }}
    },

    isReady: function () {
        return this.attributes.fields && this.attributes.fields.length > 0;
    },

    whenReady: function (cb) {
        if (this.isReady())
            cb();
        else {
            this.once('change', function () {
                this.whenReady(cb);
            }, this);
        }
    },

    itemSchema: function () {
        if (!this.isReady())
            throw "Definition is not ready. Fetch it first.";
        var typeMapping = {
            'int': 'Number',
            'string': 'Text',
            'boolean': 'Checkbox'
        }
        var geom = function (f) {
            return {type: 'TextArea',
                    editorAttrs: {style: 'display: none'},
                    help: f.description + ' (on map)'};
        };
        var fieldMapping = {
            'default': function (f) {
                var d = {help: f.description}
                  , t = typeMapping[f.type];
                if (t) d.type = t;
                return d;
            },
            'decimal': function (f) {
                var d = fieldMapping['default'](field);
                d.editorAttrs = {pattern: '[-+]?[0-9]*\.?[0-9]+'};
                return d;
            },
            'email': function (f) {
                var d = fieldMapping['default'](field);
                d.validators = ['required', 'email'];
                return d;
            },
            'url': function (f) {
                var d = fieldMapping['default'](field);
                d.validators = ['required', 'url'];
                return d;
            },
            'point': geom,
            'line': geom,
            'polygon': geom,
        };
        var schema = {};
        // Add Backbone.Forms fields from Daybed definition
        $(this.attributes.fields).each(function (i, field) {
            var defaultschema = fieldMapping['default']
              , build = fieldMapping[field.type] || defaultschema;
            schema[field.name] = build(field);
        });
        return schema;
    },

    mainFields: function () {
        var geomField = this.geomField();
        if (!geomField)
            return this.attributes.fields;
        return this.attributes.fields.filter(function (f) {
            return f.name != geomField.name;
        });
    },

    /**
     * Returns the first field whose type is Geometry.
     */
    geomField: function () {
        for (i in this.attributes.fields) {
            var f = this.attributes.fields[i];
            if (f.type == 'point' || f.type == 'line' || f.type == 'polygon')
                return f;
        }
        return null;
    },

    templatePopup: function () {
        var c = '
';
        $(this.mainFields()).each(function (i, f) {
            c += '
{{ ' + f.name + ' }}
'
        });
        c += '
';
        return Mustache.compile(c);
    },

    tableContent: function () {
        var tpl = '

' +
                  '{{#fields}}{{name}}	{{/fields}}'+
                  '

';
        return Mustache.compile(tpl)({fields: this.mainFields()});
    },

    templateRow: function () {
        var c = '
';
        $(this.mainFields()).each(function (i, f) {
            c += '{{ ' + f.name + ' }}	'
        });
        c += '
';
        return Mustache.compile(c);
    },
});

var FormView = Backbone.View.extend({
    model: null,
    tagName: "div",
    className: "well",

    template: Mustache.compile('
{{ title }}
' +
                               '

' +
                               'Cancel ' +
                               'Save'),
    templateError: Mustache.compile('{{ msg }}'),

    events: {
        "click #submit": "submit",
        "click #cancel": "cancel",
    },

    initialize: function () {
        this.instance = new this.model({});
        if (!this.instance.schema && this.options.definition) {
            this.instance.definition = this.options.definition;
            this.instance.schema = this.options.definition.itemSchema();
        }
        this.instance.on('change', this.refresh.bind(this));
        this.instance.on('sync', this.success.bind(this));
        this.instance.on('error', this.showErrors.bind(this));
        this.form = new Backbone.Form({
            model: this.instance
        });
    },

    render: function () {
        this.$el.html(this.template(this));
        this.$('#form').html(this.form.render().el);
        this.delegateEvents();
        return this;
    },

    cancel: function (e) {
        e.preventDefault();
        return false;
    },

    submit: function(e) {
        e.preventDefault();
        this.$el.find('.field-error').remove();
        this.form.commit();
        return false;
    },

    success: function (model, response, options) {
        return false;
    },

    showErrors: function (model, xhr, options) {
        try {
            var descriptions = JSON.parse(xhr.responseText);
            $(descriptions.errors).each(L.Util.bind(function (i, e) {
                var name = e.name.split('.')[0];
                this.$el.find("[name='" + name + "']")
                    .after(this.templateError({msg: e.description}));
            }, this));
        }
        catch (e) {
            this.$el.html(this.templateError({msg: xhr.responseText}));
        }
    },

    /**
     * Refresh field values from instance attributes.
     */
    refresh: function () {
        for (f in this.instance.changed) {
            if (f == 'id') continue;
            var attr = {};
            attr[f] = this.instance.get(f);
            this.form.setValue(attr);
        }
    }
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Waze Map Editor - Utils
// @namespace    http://tampermonkey.net/
// @version      1.0.7
// @description  set of utils to speed development
// @author       Delfim Machado - dbcm@profundos.org
// @match        https://beta.waze.com/*editor/*
// @match        https://www.waze.com/*editor/*
// @exclude      https://www.waze.com/*user/*editor/*
// @grant        none
// ==/UserScript==

/*

reusable code for all WME tools i'm building

*/

(function(root) {
    "use strict";

    var face = {
        meh: "¯_(ツ)_/¯",
        angry: "(⋟﹏⋞)",
        happy: "⎦˚◡˚⎣"
    };

    var WMEutils = function(options) {
        this.init(options);
    };

    WMEutils.prototype.init = function(opt) {
        this._VERSION = 0.1;

        opt = opt || {};

        this.debug = opt.debug;

        this.app = opt.app || "DUH";
        this.uid = opt.uid || "___";
        this.version = opt.version || "0.0.666";
        this.doLog = opt.hasOwnProperty("doLog") ? opt.doLog : true;
    };

    /*
      	o
      	{
      		id: "blame",
      		name: "bl",
      		title: 'blame plugin : ¯\\_(ツ)_/¯  [last 10 days]',
      		desc: 'i blame you all',
      		content: menu
      	}
      */
    WMEutils.prototype.addTab = function(o) {
        var self = this;

        // while testing and developing...
        var mdk = function(id) {
            try {
                document.getElementById(id).remove();
            } catch (e) {
                console.log("X");
            }
        };

        if (document.getElementById("t" + o.id)) {
            return;
        }

        var addon = document.createElement("div");
        addon.innerHTML +=
            '

' + o.title + "

";
        addon.innerHTML += o.content;
        addon.innerHTML += "

";

        var navTabs = document.getElementsByClassName("nav nav-tabs")[0];
        var tabContent = document.getElementsByClassName("tab-content")[0];

        var newtab = document.createElement("li");
        newtab.id = "t" + o.id;
        newtab.innerHTML =
            '' +
            o.name +
            "";
        //mdk("t" + o.id);
        navTabs.appendChild(newtab);

        addon.id = "sidepanel-" + o.id;
        addon.className = "tab-pane";
        //mdk("sidepanel-" + o.id);
        tabContent.appendChild(addon);

        return true;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopSegments = function(f) {
        var ret = {};

        for (var segId in W.model.segments.objects) {
            var seg = W.model.segments.getObjectById(segId);

            if (!this.isOnScreen(seg)) {
                continue;
            }

            if (!this.canEdit(seg)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](seg);
                    if (
                        r &&
                        (Array.isArray(r) ?
                            r.every(function(r) {
                                return r.id;
                            }) :
                            r.id)
                    ) {
                        if (!Array.isArray(r)) re.push(r);
                        else re = [...re, ...r];
                    }
                }
            }
            if (re.length > 0) ret[seg.attributes.id] = re;
        }

        return ret;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopVenues = function(f) {
        var ret = {};

        for (var venId in W.model.venues.objects) {
            var ven = W.model.venues.getObjectById(venId);

            if (!this.isOnScreen(ven)) {
                continue;
            }

            if (!this.canEdit(ven)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](ven);
                    if (r && r.id) re.push(r);
                }
            }
            if (re.length > 0) ret[ven.attributes.id] = re;
        }

        return ret;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopNodes = function(f) {
        var ret = {};

        for (var nodId in W.model.nodes.objects) {
            var nod = W.model.nodes.getObjectById(nodId);

            if (!this.isOnScreen(nod)) {
                continue;
            }

            if (!this.canEdit(nod)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](nod);
                    if (r && r.id) re.push(r);
                }
            }
            if (re.length > 0) ret[nod.attributes.id] = re;
        }

        return ret;
    };

    /*
      	if the object visible
      */
    WMEutils.prototype.isOnScreen = function(obj) {
        if (!obj) return false;
        if (obj.geometry) {
            return W.map.getExtent().intersectsBounds(obj.geometry.getBounds());
        }
        return false;
    };

    /*
      	can i edit this object
      */
    WMEutils.prototype.canEdit = function(obj) {
        if (obj.isDeleted()) return false;

        if (obj.type === "segment")
            return (
                obj.isAllowed(obj.PERMISSIONS.EDIT_GEOMETRY) &&
                !obj.hasClosures() &&
                obj.isAllowed(obj.PERMISSIONS.EDIT_PROPERTIES)
            );
        // || obj.isUpdated();
        //  &&
        // !obj.isInBigJunction()
        if (obj.type === "venue")
            return (
                obj.isAllowed(obj.PERMISSIONS.EDIT_GEOMETRY) &&
                obj.areExternalProvidersEditable()
            ); // || obj.isUpdated();
        if (obj.type === "node")
            return (!obj.isConnectedToBigJunction() &&
                obj.isAllowedToMoveNode() &&
                obj.isAllowed(obj.PERMISSIONS.DELETE)
            );
        // obj.isUpdated();
        // obj.areConnectionsEditable() &&
    };

    /*
      	is this object in Portugal
      */
    WMEutils.prototype.isPortugal = function(obj) {
        var att = obj.attributes;
        var street = W.model.streets.getObjectById(att.primaryStreetID);
        var city = segment.model.cities.getObjectById(street.cityID);
        var countryId = city.countryID;

        return countryId === 181;
    };

    /*
      	return a random color
      */
    WMEutils.prototype.rColor = function() {
        var letters = "0123456789ABCDEF";
        var color = "#";
        for (var i = 0; i < 6; i++) {
            color += letters[Math.floor(Math.random() * 16)];
        }
        return color;
    };

    /*
          obj = must be a segment OBJ
      */
    WMEutils.prototype.isDrivable = function(obj) {
        if (obj.type === "segment") {
            var drivable = [1, 2, 3, 4, 6, 7, 8, 17, 15, 20];

            if (drivable.includes(obj.attributes.roadType)) {
                return true;
            }
        }
        return false;
    };

    /*
          obj = object to highlight, can be and segment or a place (landmark/venue)
          color = highlight color
          bgColor = background color, if null, defaults to color
      */
    WMEutils.prototype.highlightObject = function(obj, color, bgColor, label) {
        return new OpenLayers.Feature.Vector(
            obj.geometry.clone(), {}, {
                strokeColor: color,
                strokeDashstyle: "none",
                strokeLinecap: "round",
                strokeWidth: 15,
                strokeOpacity: 0.5,
                fill: true,
                fillColor: bgColor || color,
                fillOpacity: 0.2,
                pointRadius: 6,
                fontColor: color,
                labelOutlineColor: bgColor || "black",
                labelOutlineWidth: 4,
                labelAlign: "cm",
                label: label || null,
                rotation: 0.785398164,
                textAlign: "center",
                textBaseline: "middle"
            }
        );
    };

    /*
      	options stuff
      */
    WMEutils.prototype.loadOptions = function(section = "options") {
        var self = this;

        return JSON.parse(localStorage.getItem(self.uid + "_" + section)) || {};
    };
    WMEutils.prototype.saveOptions = function(options, section = "options") {
        var self = this;

        return localStorage.setItem(self.uid + "_" + section, JSON.stringify(options));
    };

    /*
      	log stuff
      */
    WMEutils.prototype.log = function(msg) {
        var self = this;

        if (!this.doLog) return;

        var now = Date.now();
        console.log("[" + this.app + "] " + now + " : " + msg);
    };

    /*
      	set attributes to objects
      */
    WMEutils.prototype.setAttributes = function(obj, attr) {
        var WazeActionUpdateObject = window.require("Waze/Action/UpdateObject");
        var WazeActionMultiAction = window.require("Waze/Action/MultiAction");

        var action = [];
        action.push(new WazeActionUpdateObject(obj, attr));
        W.model.actionManager.add(new WazeActionMultiAction(action));
    };

    /*
      	get normalized lock rank
      */
    WMEutils.prototype.getLockRank = function(obj) {
        var rank = obj.attributes.lockRank;

        // support for the automatic lock
        if (obj.attributes.rank > rank) rank = obj.attributes.rank;

        if (!rank) {
            rank = 1;
        } else {
            rank++;
        }
        return rank;
    };

    /*
      	get road name
      */
    WMEutils.prototype.getRoadName = function(obj) {
        var attr = obj.attributes;
        var segStreetID = attr.primaryStreetID;
        if (segStreetID !== null && segStreetID !== -100) {
            var street = W.model.streets.getObjectById(segStreetID);

            if (!street) return "";

            return street.name || "";
        }
    };

    /*
          returns 1, 2 or 3 based on segment direction
      */
    WMEutils.prototype.getDirection = function(obj) {
        var attr = obj.attributes;

        var val = 0;
        if (attr.fwdDirection) val += 1;

        if (attr.revDirection) val += 2;

        return val;
    };

    /*
      	returns true if the segment if from a roundabout
      */
    WMEutils.prototype.isRoundabout = function(seg) {
        if (
            seg.attributes.junctionID !== null &&
            seg.attributes.junctionID !== undefined
        )
            return true;
        return false;
    };

    /*
      	returns top city name
      */
    WMEutils.prototype.getTopCityName = function() {
        var topCityId = W.model.segments.topCityID;
        if (topCityId) {
            var topCity = W.model.cities.getObjectById(topCityId);
            if (topCity) {
                return topCity.attributes.name;
            }
        }
        return null;
    };

    /*
      	returns true if you are using beta editor
      */
    WMEutils.prototype.onBeta = function() {
        return -1 !== window.location.href.indexOf("beta");
    };

    /*
      	add menu layer

          section = [issues, places, road, display]
          name = layer name
          uid = internal id
          callback = function() {...}
          layer = OL Layer
      */
    WMEutils.prototype.addMenuLayer = function(o) {
        // from WME Street View Availability
        var roadGroupSelector = document.getElementById(
            "layer-switcher-group_" + o.section
        );
        let magicItem = document.getElementById("layer-switcher-item_" + o.uid);
        if (roadGroupSelector !== null && magicItem == null) {
            var roadGroup = roadGroupSelector.parentNode.parentNode.querySelector(
                ".children"
            );
            var toggler = document.createElement("li");
            var togglerContainer = document.createElement("div");
            togglerContainer.className = "controls-container toggler";
            var checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.id = "layer-switcher-item_" + o.uid;
            checkbox.className = "toggle";
            checkbox.checked = true;
            checkbox.addEventListener("click", function(e) {
                o.layer.setVisibility(e.target.checked);
            });
            togglerContainer.appendChild(checkbox);
            var label = document.createElement("label");
            label.htmlFor = checkbox.id;
            var labelText = document.createElement("span");
            labelText.className = "label-text";
            labelText.appendChild(document.createTextNode(o.name));
            label.appendChild(labelText);
            togglerContainer.appendChild(label);
            toggler.appendChild(togglerContainer);
            roadGroup.appendChild(toggler);
        }
    };

    root.WMEutils = WMEutils;
})(window);
<commit_msg>donald link<commit_after>// ==UserScript==
// @name         Waze Map Editor - Utils
// @namespace    http://tampermonkey.net/
// @version      1.0.7
// @description  set of utils to speed development
// @author       Delfim Machado - dbcm@profundos.org
// @match        https://beta.waze.com/*editor/*
// @match        https://www.waze.com/*editor/*
// @exclude      https://www.waze.com/*user/*editor/*
// @grant        none
// @downloadURL  https://raw.githubusercontent.com/dbcm/waze/master/utils/utils.user.js
// ==/UserScript==

/*

reusable code for all WME tools i'm building

*/

(function(root) {
    "use strict";

    var face = {
        meh: "¯_(ツ)_/¯",
        angry: "(⋟﹏⋞)",
        happy: "⎦˚◡˚⎣"
    };

    var WMEutils = function(options) {
        this.init(options);
    };

    WMEutils.prototype.init = function(opt) {
        this._VERSION = 0.1;

        opt = opt || {};

        this.debug = opt.debug;

        this.app = opt.app || "DUH";
        this.uid = opt.uid || "___";
        this.version = opt.version || "0.0.666";
        this.doLog = opt.hasOwnProperty("doLog") ? opt.doLog : true;
    };

    /*
      	o
      	{
      		id: "blame",
      		name: "bl",
      		title: 'blame plugin : ¯\\_(ツ)_/¯  [last 10 days]',
      		desc: 'i blame you all',
      		content: menu
      	}
      */
    WMEutils.prototype.addTab = function(o) {
        var self = this;

        // while testing and developing...
        var mdk = function(id) {
            try {
                document.getElementById(id).remove();
            } catch (e) {
                console.log("X");
            }
        };

        if (document.getElementById("t" + o.id)) {
            return;
        }

        var addon = document.createElement("div");
        addon.innerHTML +=
            '

' + o.title + "

";
        addon.innerHTML += o.content;
        addon.innerHTML += "

";

        var navTabs = document.getElementsByClassName("nav nav-tabs")[0];
        var tabContent = document.getElementsByClassName("tab-content")[0];

        var newtab = document.createElement("li");
        newtab.id = "t" + o.id;
        newtab.innerHTML =
            '' +
            o.name +
            "";
        //mdk("t" + o.id);
        navTabs.appendChild(newtab);

        addon.id = "sidepanel-" + o.id;
        addon.className = "tab-pane";
        //mdk("sidepanel-" + o.id);
        tabContent.appendChild(addon);

        return true;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopSegments = function(f) {
        var ret = {};

        for (var segId in W.model.segments.objects) {
            var seg = W.model.segments.getObjectById(segId);

            if (!this.isOnScreen(seg)) {
                continue;
            }

            if (!this.canEdit(seg)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](seg);
                    if (
                        r &&
                        (Array.isArray(r) ?
                            r.every(function(r) {
                                return r.id;
                            }) :
                            r.id)
                    ) {
                        if (!Array.isArray(r)) re.push(r);
                        else re = [...re, ...r];
                    }
                }
            }
            if (re.length > 0) ret[seg.attributes.id] = re;
        }

        return ret;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopVenues = function(f) {
        var ret = {};

        for (var venId in W.model.venues.objects) {
            var ven = W.model.venues.getObjectById(venId);

            if (!this.isOnScreen(ven)) {
                continue;
            }

            if (!this.canEdit(ven)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](ven);
                    if (r && r.id) re.push(r);
                }
            }
            if (re.length > 0) ret[ven.attributes.id] = re;
        }

        return ret;
    };

    /*
      	f = ARRAY of functions
      */
    WMEutils.prototype.loopNodes = function(f) {
        var ret = {};

        for (var nodId in W.model.nodes.objects) {
            var nod = W.model.nodes.getObjectById(nodId);

            if (!this.isOnScreen(nod)) {
                continue;
            }

            if (!this.canEdit(nod)) {
                continue;
            }

            var re = [];
            for (var i = 0; i < f.length; i++) {
                if (f[i]) {
                    var r = f[i](nod);
                    if (r && r.id) re.push(r);
                }
            }
            if (re.length > 0) ret[nod.attributes.id] = re;
        }

        return ret;
    };

    /*
      	if the object visible
      */
    WMEutils.prototype.isOnScreen = function(obj) {
        if (!obj) return false;
        if (obj.geometry) {
            return W.map.getExtent().intersectsBounds(obj.geometry.getBounds());
        }
        return false;
    };

    /*
      	can i edit this object
      */
    WMEutils.prototype.canEdit = function(obj) {
        if (obj.isDeleted()) return false;

        if (obj.type === "segment")
            return (
                obj.isAllowed(obj.PERMISSIONS.EDIT_GEOMETRY) &&
                !obj.hasClosures() &&
                obj.isAllowed(obj.PERMISSIONS.EDIT_PROPERTIES)
            );
        // || obj.isUpdated();
        //  &&
        // !obj.isInBigJunction()
        if (obj.type === "venue")
            return (
                obj.isAllowed(obj.PERMISSIONS.EDIT_GEOMETRY) &&
                obj.areExternalProvidersEditable()
            ); // || obj.isUpdated();
        if (obj.type === "node")
            return (!obj.isConnectedToBigJunction() &&
                obj.isAllowedToMoveNode() &&
                obj.isAllowed(obj.PERMISSIONS.DELETE)
            );
        // obj.isUpdated();
        // obj.areConnectionsEditable() &&
    };

    /*
      	is this object in Portugal
      */
    WMEutils.prototype.isPortugal = function(obj) {
        var att = obj.attributes;
        var street = W.model.streets.getObjectById(att.primaryStreetID);
        var city = segment.model.cities.getObjectById(street.cityID);
        var countryId = city.countryID;

        return countryId === 181;
    };

    /*
      	return a random color
      */
    WMEutils.prototype.rColor = function() {
        var letters = "0123456789ABCDEF";
        var color = "#";
        for (var i = 0; i < 6; i++) {
            color += letters[Math.floor(Math.random() * 16)];
        }
        return color;
    };

    /*
          obj = must be a segment OBJ
      */
    WMEutils.prototype.isDrivable = function(obj) {
        if (obj.type === "segment") {
            var drivable = [1, 2, 3, 4, 6, 7, 8, 17, 15, 20];

            if (drivable.includes(obj.attributes.roadType)) {
                return true;
            }
        }
        return false;
    };

    /*
          obj = object to highlight, can be and segment or a place (landmark/venue)
          color = highlight color
          bgColor = background color, if null, defaults to color
      */
    WMEutils.prototype.highlightObject = function(obj, color, bgColor, label) {
        return new OpenLayers.Feature.Vector(
            obj.geometry.clone(), {}, {
                strokeColor: color,
                strokeDashstyle: "none",
                strokeLinecap: "round",
                strokeWidth: 15,
                strokeOpacity: 0.5,
                fill: true,
                fillColor: bgColor || color,
                fillOpacity: 0.2,
                pointRadius: 6,
                fontColor: color,
                labelOutlineColor: bgColor || "black",
                labelOutlineWidth: 4,
                labelAlign: "cm",
                label: label || null,
                rotation: 0.785398164,
                textAlign: "center",
                textBaseline: "middle"
            }
        );
    };

    /*
      	options stuff
      */
    WMEutils.prototype.loadOptions = function(section = "options") {
        var self = this;

        return JSON.parse(localStorage.getItem(self.uid + "_" + section)) || {};
    };
    WMEutils.prototype.saveOptions = function(options, section = "options") {
        var self = this;

        return localStorage.setItem(self.uid + "_" + section, JSON.stringify(options));
    };

    /*
      	log stuff
      */
    WMEutils.prototype.log = function(msg) {
        var self = this;

        if (!this.doLog) return;

        var now = Date.now();
        console.log("[" + this.app + "] " + now + " : " + msg);
    };

    /*
      	set attributes to objects
      */
    WMEutils.prototype.setAttributes = function(obj, attr) {
        var WazeActionUpdateObject = window.require("Waze/Action/UpdateObject");
        var WazeActionMultiAction = window.require("Waze/Action/MultiAction");

        var action = [];
        action.push(new WazeActionUpdateObject(obj, attr));
        W.model.actionManager.add(new WazeActionMultiAction(action));
    };

    /*
      	get normalized lock rank
      */
    WMEutils.prototype.getLockRank = function(obj) {
        var rank = obj.attributes.lockRank;

        // support for the automatic lock
        if (obj.attributes.rank > rank) rank = obj.attributes.rank;

        if (!rank) {
            rank = 1;
        } else {
            rank++;
        }
        return rank;
    };

    /*
      	get road name
      */
    WMEutils.prototype.getRoadName = function(obj) {
        var attr = obj.attributes;
        var segStreetID = attr.primaryStreetID;
        if (segStreetID !== null && segStreetID !== -100) {
            var street = W.model.streets.getObjectById(segStreetID);

            if (!street) return "";

            return street.name || "";
        }
    };

    /*
          returns 1, 2 or 3 based on segment direction
      */
    WMEutils.prototype.getDirection = function(obj) {
        var attr = obj.attributes;

        var val = 0;
        if (attr.fwdDirection) val += 1;

        if (attr.revDirection) val += 2;

        return val;
    };

    /*
      	returns true if the segment if from a roundabout
      */
    WMEutils.prototype.isRoundabout = function(seg) {
        if (
            seg.attributes.junctionID !== null &&
            seg.attributes.junctionID !== undefined
        )
            return true;
        return false;
    };

    /*
      	returns top city name
      */
    WMEutils.prototype.getTopCityName = function() {
        var topCityId = W.model.segments.topCityID;
        if (topCityId) {
            var topCity = W.model.cities.getObjectById(topCityId);
            if (topCity) {
                return topCity.attributes.name;
            }
        }
        return null;
    };

    /*
      	returns true if you are using beta editor
      */
    WMEutils.prototype.onBeta = function() {
        return -1 !== window.location.href.indexOf("beta");
    };

    /*
      	add menu layer

          section = [issues, places, road, display]
          name = layer name
          uid = internal id
          callback = function() {...}
          layer = OL Layer
      */
    WMEutils.prototype.addMenuLayer = function(o) {
        // from WME Street View Availability
        var roadGroupSelector = document.getElementById(
            "layer-switcher-group_" + o.section
        );
        let magicItem = document.getElementById("layer-switcher-item_" + o.uid);
        if (roadGroupSelector !== null && magicItem == null) {
            var roadGroup = roadGroupSelector.parentNode.parentNode.querySelector(
                ".children"
            );
            var toggler = document.createElement("li");
            var togglerContainer = document.createElement("div");
            togglerContainer.className = "controls-container toggler";
            var checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.id = "layer-switcher-item_" + o.uid;
            checkbox.className = "toggle";
            checkbox.checked = true;
            checkbox.addEventListener("click", function(e) {
                o.layer.setVisibility(e.target.checked);
            });
            togglerContainer.appendChild(checkbox);
            var label = document.createElement("label");
            label.htmlFor = checkbox.id;
            var labelText = document.createElement("span");
            labelText.className = "label-text";
            labelText.appendChild(document.createTextNode(o.name));
            label.appendChild(labelText);
            togglerContainer.appendChild(label);
            toggler.appendChild(togglerContainer);
            roadGroup.appendChild(toggler);
        }
    };

    root.WMEutils = WMEutils;
})(window);
<|endoftext|>


<commit_before>//
//
//

const game_schema = require('core/game_schema');

function load(game_path, game_name, cb) {

  cb = cb || function() {};

  let game = require(game_path);

  if (!game || !game.db_init || !game.init || !game.turn || !game.config) {
    console.log(`not valid game => ${game_name}`);
    return;
  }

  let schema = game.db_init;
  schema.path = game_path;

  game_schema.add(schema, function(err, result) {

    if (err) {
      return cb({
        status: 500,
        err: err
      });
    }

    console.log(`game loaded => ${game.db_init.game_name}`);

    return cb(null, result);
  });
}

module.exports = load;
<commit_msg>better error handling<commit_after>//
//
//

const game_schema = require('core/game_schema');

function load(game_path, game_name, cb) {

  cb = cb || function() {};

  let game = require(game_path);

  if (!game || !game.db_init || !game.init || !game.turn || !game.config) {
    console.log(`not valid game => ${game.db_init.game_name}`);
    return cb({
      status: 400,
      err: new Error('no valid game.')
    })
  }

  let schema = game.db_init;
  schema.path = game_path;

  game_schema.add(schema, function(err, result) {

    if (err) {
      return cb({
        status: 500,
        err: err
      });
    }

    console.log(`game loaded => ${game.db_init.game_name}`);

    return cb(null, result);
  });
}

module.exports = load;
<|endoftext|>


<commit_before>define(['jquery', 'bootstrap-notify', './bridge', './translate'], function ($, _, Bridge, Translate) {
    return function (aceEditor, settings) {

        var editor = this,
            currentFilepath = null,
            currentFiletype = null,
            statusCurrentFileUnsaved = false,
            statusCurrentFileExternallyChanged = false,
            modes = {
                '.rb':   'ace/mode/ruby_sketchup',
                '.css' : 'ace/mode/css',
                '.html': 'ace/mode/html',
                '.htm':  'ace/mode/html',
                '.js':   'ace/mode/javascript',
                '.json': 'ace/mode/json'
            };
        this.aceEditor = aceEditor;

        function initialize () {
            configureAce(aceEditor);
            // Listen for changes in the document to keep the (un)saved status variable up-to-date.
            aceEditor.on('change', function(){
                statusCurrentFileUnsaved = true;
            });
        }

        // Implementation of Observer/Observable

        this.addListener = function (eventName, fn) {
            $(editor).on(eventName, function (event, args) {
                fn.apply(undefined, args);
            });
        };

        function trigger (eventName, data) {
            var args = Array.prototype.slice.call(arguments).slice(1);
            $(editor).trigger(eventName, [args]);
        }

        this.focus = function () {
            aceEditor.focus();
        };

        this.setContent = function (content) {
            aceEditor.session.setValue(content);
        };

        this.getContent = function () {
            return aceEditor.session.getValue();
        };

        this.getCurrentFilepath = function () {
            return currentFilepath;
        };

        this.newDocument = function () {
            // Ask whether to save changes if there are unsaved changes.
            if ((statusCurrentFileUnsaved && confirmSaveChanges()) || (statusCurrentFileExternallyChanged && confirmSaveAndIgnoreExternalChanges())) {
                return editor.save().then(function() {
                    return editor.newDocument();
                });
            } else {
                if (currentFilepath) closeCurrentFile();
                editor.setContent('');
                currentFilepath = null;
                // Set the mode to plain text or ruby or leave the current mode.
                // aceEditor.session.setMode('ace/mode/text');
                // Since the file is new, it has not been saved yet.
                statusCurrentFileUnsaved = true;
                statusCurrentFileExternallyChanged = false;
                // Trigger an event.
                trigger('opened', '');
                return new Bridge.Promise.resolve(true); // Return a resolved promise
            }
        };

        this.open = function (filepath, lineNumber) {
            // Do not load the file again if it is already opened.
            if (filepath == currentFilepath) {
                if (lineNumber) aceEditor.gotoLine(lineNumber);
                return;
            }
            // Ask whether to save changes if there are unsaved changes.
            if ((statusCurrentFileUnsaved && confirmSaveChanges()) || (statusCurrentFileExternallyChanged && confirmSaveAndIgnoreExternalChanges())) {
                return editor.save().then(function() {
                    return editor.open(filepath);
                });
            } else {
                if (currentFilepath) closeCurrentFile();
                // Read the file and load its content into the ace editor.
                return loadFile(filepath).then(function () {
                    addToRecentlyOpenedFiles(filepath);
                    // Try to determine the ace mode from the file name.
                    var extensionMatch = filepath.match(/\.\w{1,3}$/i);
                    if (extensionMatch && extensionMatch[0]) {
                        currentFiletype = extensionMatch[0].toLowerCase();
                        aceEditor.session.setMode(modes[currentFiletype] || 'ace/mode/text');
                    } else {
                        currentFiletype = undefined;
                        aceEditor.session.setMode('ace/mode/text');
                    }
                    // Try to jump to the line number where the file was last accessed.
                    if (!lineNumber) lineNumber = settings.get('recently_focused_lines', {})[filepath] || 1;
                    aceEditor.gotoLine(lineNumber); // one-based
                }, function (error) {
                    // notification: File failed to open
                    alert('Failed to open file "' + filepath + '": \n' + error);
                });
            }
        };

        this.save = function () {
            // Ask where to save the file if no file path is associated.
            if (typeof currentFilepath !== 'string') {
                return editor.saveAs();
            } else {
                // Write the content to the file.
                return Bridge.get('writefile', currentFilepath, editor.getContent()).then(function () {
                    // success
                    // The file has been saved successfully, so there are no unsaved changes anymore.
                    statusCurrentFileUnsaved = false;
                    statusCurrentFileExternallyChanged = false;
                    // Trigger an event.
                    trigger('saved', currentFilepath);
                }, function (error) {
                    // error notification
                    alert(Translate.get('Failed to save file') + ' "' + currentFilepath + '": \n' + error);
                });
            }
        };

        this.saveAs = function () {
            // Ask where to save the file.
            return Bridge.get('savepanel', Translate.get('Save the current file as…'), currentFilepath).then(function (filepath) {
                currentFilepath = filepath;
                return editor.save();
            });
        };

        function configureAce (aceEditor) {
            // Set the mode to Ruby.
            aceEditor.session.setMode('ace/mode/ruby_sketchup');
        }

        function alert (message, type) {
            var notify = $.notify(message, {
                type: type || 'danger',
                element: $('#editorContentWrapper'),
                placement: { from: 'top', align: 'center' },
                offset: { x: 0, y: 0 },
                allow_dismiss: true
            });
        }

        function confirm (message, action1, action2) {
            return new Bridge.Promise(function (resolve, reject) {
                var notify = $.notify('', {
                    type: 'warning',
                    element: $('#editorContentWrapper'), // TODO: Remove binding to a specific HTML element.
                    placement: { from: 'top', align: 'center' },
                    offset: { x: 0, y: 0 },
                    allow_dismiss: true,
                    delay: 0,
                    template: '
' +
                        Translate.get(message) + ' <button class="notify_button_action1">' +
                        Translate.get(action1 || 'Yes') + '</button> <button type="button" class="notify_button_action2">' +
                        Translate.get(action2 || 'No') + '</button>
'
                });
                $('.notify_button_action1', notify.$ele).on('click', function() {
                    resolve();
                    notify.close();
                });
                $('.notify_button_action2', notify.$ele).on('click', function() {
                    reject();
                    notify.close();
                });
            });
        }

        function confirmSaveChanges () {
            return window.confirm('Save changes to current file?');
        }

        function confirmSaveAndIgnoreExternalChanges () {
            return window.confirm('The file has been changed externally.\nOverwrite external changes and save the current file?');
        }

        function addToRecentlyOpenedFiles (filepath) {
            var recentlyOpened = settings.get('recently_opened_files', []);
            var index = recentlyOpened.indexOf(filepath);
            if (index != -1) recentlyOpened.splice(index, 1);
            if (index !=  0) recentlyOpened.unshift(filepath);
            if (recentlyOpened.length > 10) recentlyOpened.length = 10;
            settings.set('recently_opened_files', recentlyOpened);
        }

        function loadFile (filepath) {
            if (!filepath) filepath = currentFilepath;
            return Bridge.get('readfile', filepath).then(function (content) {
                editor.setContent(content);
                // Since the file has just been loaded, it has no unsaved changes yet.
                statusCurrentFileUnsaved = false;
                statusCurrentFileExternallyChanged = false;
                currentFilepath = filepath;
                // Notify on external changes of the just opened file.
                Bridge.get('observe_external_file_changes', filepath).then(function (path) {
                    if (path == filepath) {
                        confirm('The file was changed externally.', 'Reload', 'Ignore')
                        .then(loadFile);
                    }
                });
                // Trigger an event.
                trigger('opened', filepath);
            });
        }

        function closeCurrentFile () {
            if (currentFilepath) {
                // Remember the currently focused line for this file.
                var lineNumber = aceEditor.getCursorPosition().row; // zero-based
                var recentlyFocusedLines = settings.get('recently_focused_lines', {});
                recentlyFocusedLines[currentFilepath] = lineNumber+1;
                settings.set('recently_focused_lines', recentlyFocusedLines); // Using the set function to trigger saving.
            }
        }

        initialize();
    };
});
<commit_msg>Fix editor.open not always returning Promise<commit_after>define(['jquery', 'bootstrap-notify', './bridge', './translate'], function ($, _, Bridge, Translate) {
    return function (aceEditor, settings) {

        var editor = this,
            currentFilepath = null,
            currentFiletype = null,
            statusCurrentFileUnsaved = false,
            statusCurrentFileExternallyChanged = false,
            modes = {
                '.rb':   'ace/mode/ruby_sketchup',
                '.css' : 'ace/mode/css',
                '.html': 'ace/mode/html',
                '.htm':  'ace/mode/html',
                '.js':   'ace/mode/javascript',
                '.json': 'ace/mode/json'
            };
        this.aceEditor = aceEditor;

        function initialize () {
            configureAce(aceEditor);
            // Listen for changes in the document to keep the (un)saved status variable up-to-date.
            aceEditor.on('change', function(){
                statusCurrentFileUnsaved = true;
            });
        }

        // Implementation of Observer/Observable

        this.addListener = function (eventName, fn) {
            $(editor).on(eventName, function (event, args) {
                fn.apply(undefined, args);
            });
        };

        function trigger (eventName, data) {
            var args = Array.prototype.slice.call(arguments).slice(1);
            $(editor).trigger(eventName, [args]);
        }

        this.focus = function () {
            aceEditor.focus();
        };

        this.setContent = function (content) {
            aceEditor.session.setValue(content);
        };

        this.getContent = function () {
            return aceEditor.session.getValue();
        };

        this.getCurrentFilepath = function () {
            return currentFilepath;
        };

        this.newDocument = function () {
            // Ask whether to save changes if there are unsaved changes.
            if ((statusCurrentFileUnsaved && confirmSaveChanges()) || (statusCurrentFileExternallyChanged && confirmSaveAndIgnoreExternalChanges())) {
                return editor.save().then(function() {
                    return editor.newDocument();
                });
            } else {
                if (currentFilepath) closeCurrentFile();
                editor.setContent('');
                currentFilepath = null;
                // Set the mode to plain text or ruby or leave the current mode.
                // aceEditor.session.setMode('ace/mode/text');
                // Since the file is new, it has not been saved yet.
                statusCurrentFileUnsaved = true;
                statusCurrentFileExternallyChanged = false;
                // Trigger an event.
                trigger('opened', '');
                return new Bridge.Promise.resolve(true); // Return a resolved promise
            }
        };

        this.open = function (filepath, lineNumber) {
            // Do not load the file again if it is already opened.
            if (filepath == currentFilepath) {
                if (lineNumber) aceEditor.gotoLine(lineNumber);
                return Bridge.Promise.resolve(true); // Return a resolved promise
            }
            // Ask whether to save changes if there are unsaved changes.
            if ((statusCurrentFileUnsaved && confirmSaveChanges()) || (statusCurrentFileExternallyChanged && confirmSaveAndIgnoreExternalChanges())) {
                return editor.save().then(function() {
                    return editor.open(filepath);
                });
            } else {
                if (currentFilepath) closeCurrentFile();
                // Read the file and load its content into the ace editor.
                return loadFile(filepath).then(function () {
                    addToRecentlyOpenedFiles(filepath);
                    // Try to determine the ace mode from the file name.
                    var extensionMatch = filepath.match(/\.\w{1,3}$/i);
                    if (extensionMatch && extensionMatch[0]) {
                        currentFiletype = extensionMatch[0].toLowerCase();
                        aceEditor.session.setMode(modes[currentFiletype] || 'ace/mode/text');
                    } else {
                        currentFiletype = undefined;
                        aceEditor.session.setMode('ace/mode/text');
                    }
                    // Try to jump to the line number where the file was last accessed.
                    if (!lineNumber) lineNumber = settings.get('recently_focused_lines', {})[filepath] || 1;
                    aceEditor.gotoLine(lineNumber); // one-based
                }, function (error) {
                    // notification: File failed to open
                    alert('Failed to open file "' + filepath + '": \n' + error);
                });
            }
        };

        this.save = function () {
            // Ask where to save the file if no file path is associated.
            if (typeof currentFilepath !== 'string') {
                return editor.saveAs();
            } else {
                // Write the content to the file.
                return Bridge.get('writefile', currentFilepath, editor.getContent()).then(function () {
                    // success
                    // The file has been saved successfully, so there are no unsaved changes anymore.
                    statusCurrentFileUnsaved = false;
                    statusCurrentFileExternallyChanged = false;
                    // Trigger an event.
                    trigger('saved', currentFilepath);
                }, function (error) {
                    // error notification
                    alert(Translate.get('Failed to save file') + ' "' + currentFilepath + '": \n' + error);
                });
            }
        };

        this.saveAs = function () {
            // Ask where to save the file.
            return Bridge.get('savepanel', Translate.get('Save the current file as…'), currentFilepath).then(function (filepath) {
                currentFilepath = filepath;
                return editor.save();
            });
        };

        function configureAce (aceEditor) {
            // Set the mode to Ruby.
            aceEditor.session.setMode('ace/mode/ruby_sketchup');
        }

        function alert (message, type) {
            var notify = $.notify(message, {
                type: type || 'danger',
                element: $('#editorContentWrapper'),
                placement: { from: 'top', align: 'center' },
                offset: { x: 0, y: 0 },
                allow_dismiss: true
            });
        }

        function confirm (message, action1, action2) {
            return new Bridge.Promise(function (resolve, reject) {
                var notify = $.notify('', {
                    type: 'warning',
                    element: $('#editorContentWrapper'), // TODO: Remove binding to a specific HTML element.
                    placement: { from: 'top', align: 'center' },
                    offset: { x: 0, y: 0 },
                    allow_dismiss: true,
                    delay: 0,
                    template: '
' +
                        Translate.get(message) + ' <button class="notify_button_action1">' +
                        Translate.get(action1 || 'Yes') + '</button> <button type="button" class="notify_button_action2">' +
                        Translate.get(action2 || 'No') + '</button>
'
                });
                $('.notify_button_action1', notify.$ele).on('click', function() {
                    resolve();
                    notify.close();
                });
                $('.notify_button_action2', notify.$ele).on('click', function() {
                    reject();
                    notify.close();
                });
            });
        }

        function confirmSaveChanges () {
            return window.confirm('Save changes to current file?');
        }

        function confirmSaveAndIgnoreExternalChanges () {
            return window.confirm('The file has been changed externally.\nOverwrite external changes and save the current file?');
        }

        function addToRecentlyOpenedFiles (filepath) {
            var recentlyOpened = settings.get('recently_opened_files', []);
            var index = recentlyOpened.indexOf(filepath);
            if (index != -1) recentlyOpened.splice(index, 1);
            if (index !=  0) recentlyOpened.unshift(filepath);
            if (recentlyOpened.length > 10) recentlyOpened.length = 10;
            settings.set('recently_opened_files', recentlyOpened);
        }

        function loadFile (filepath) {
            if (!filepath) filepath = currentFilepath;
            return Bridge.get('readfile', filepath).then(function (content) {
                editor.setContent(content);
                // Since the file has just been loaded, it has no unsaved changes yet.
                statusCurrentFileUnsaved = false;
                statusCurrentFileExternallyChanged = false;
                currentFilepath = filepath;
                // Notify on external changes of the just opened file.
                Bridge.get('observe_external_file_changes', filepath).then(function (path) {
                    if (path == filepath) {
                        confirm('The file was changed externally.', 'Reload', 'Ignore')
                        .then(loadFile);
                    }
                });
                // Trigger an event.
                trigger('opened', filepath);
            });
        }

        function closeCurrentFile () {
            if (currentFilepath) {
                // Remember the currently focused line for this file.
                var lineNumber = aceEditor.getCursorPosition().row; // zero-based
                var recentlyFocusedLines = settings.get('recently_focused_lines', {});
                recentlyFocusedLines[currentFilepath] = lineNumber+1;
                settings.set('recently_focused_lines', recentlyFocusedLines); // Using the set function to trigger saving.
            }
        }

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


<commit_before>// State
var map, featureLayer;

var state = new State("map", {
  city: undefined,          // String
  location: undefined,      // Object {lat: Number, lng, Number}
  zoom: 13,                 // Number
  selected: null,           // Object? {filter: String, id: String}
});

var zoomLevelPictures = 14;

// editor

var editor = new Editor('Places');

// Template data

Template.map.helpers({
  'state': function() { return state; },
  'editor': function() {
    return editor;
  }
});

Template.map.events({
  "click  #PlacesEditor [action='add']": function() {
    var location = _.pick(map.getCenter(), 'lat', 'lng');
    insertPlace(location, function(id) {
      editor.open('edit', id);
    });
  },
  "click #PlacesEditor [action='edit']": function() {

    // select some
    if (!editor.selectedId()) {
      var min = null;
      var minDist = null;
      featureLayer.eachLayer(function(marker) {
        var dist = map.getCenter().distanceTo(marker.getLatLng());
        var isPlace = marker.feature.properties.filter === 'places';
        var permission = Users.hasOwnerPermission(marker.feature.properties);
        if (isPlace && permission && (!min || dist < minDist)) {
          min = marker;
          minDist = dist;
        }
      });
      if (min)
        editor.select(min.feature.properties.id);
    }
  },
});

// Template instance

Template.map.created = function() {
  var city = Session.get('currentCity');
  if (!state.equals('city', city)) {
    state.set('city', city);
    state.set('location', Geo.getCityLocation(city));
    state.set('zoom', state.defaults.zoom);
  }
}

Template.map.rendered = function() {

  // Setup map
  map           =  setupMap();
  featureLayer  =  setupFeatureLayer(map);
                   setupFilters(featureLayer, this.$);

  // Observers

  var initialized = false;
  this.dataObserver = Places.find({}).observeChanges({
    'added': function() { if (initialized) reload(); },
    'changed': function() { if (initialized) reload(); },
    'removed': function() { if (initialized) reload(); }
  });
  initialized = true;

  this.modeObserver = editor.observe('mode', function(mode) {
    reload();
    if (!mode)
      clear();
  });

  this.editorObserver = editor.observe('selectedId', function(id) {
    state.set('selected', id && {id: id, filter: 'places'} || null);
  });

  this.selectedObserver = state.observe('selected', function(selected) {
    openFeaturePopup(featureLayer, selected);
    editor.select(selected && selected.id);
    if (selected)
      clear(selected.id);
  });

  reload();
}

Template.map.destroyed = function() {
  this.dataObserver.stop();
  this.modeObserver.stop();
  this.editorObserver.stop();
  this.selectedObserver.stop();
}

/* Reload */

var reload = function() {
  setData(featureLayer);
  openFeaturePopup(featureLayer, state.get('selected'))
  switchMode(map, featureLayer);
}

/* Setup */

var setupMap = function() {

  var map = L.mapbox.map('mapbox', 'ramshorst.gd0ekbb3');

  // properties
  map.setView(state.get('location'));
  map.setZoom(state.get('zoom'));
  map.zoomControl.setPosition('topleft');

  // events
  map.on('moveend', function(e) {  // save location state
    state.set('location', map.getCenter())
  });
  map.on('zoomend', function(e) { // save zoom state
    var prevZoom = state.get('zoom');
    var newZoom = map.getZoom();

    // save zoom level
    state.set('zoom', newZoom)

    // reload data when certain zoom level is passed
    if (newZoom < zoomLevelPictures && zoomLevelPictures <= prevZoom
      || newZoom >= zoomLevelPictures && zoomLevelPictures > prevZoom) {
      reload();
    }
  });

  return map;
}

var setupFeatureLayer = function(map) {

  // create marker layer
  var featureLayer = L.mapbox.featureLayer().addTo(map);

  // icon based on feature properties
  featureLayer.on('layeradd', function(e) {
    var marker = e.layer;
    var props = marker.feature.properties;
    var type = props.type;

    if (props.filter === 'places') {

      // places marker
      if (type) {
        marker.setIcon(L.icon({
          iconUrl:      "/img/markers/"+type+".png",
          className:    "marker-place "+type,
          iconSize:     [27, 40], // size of the icon
          iconAnchor:   [13, 40], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -40] // point from which the popup should open relative to the iconAnchor
        }));

        // make popup
        var popup = [];
        if (props.title)       popup.push(""+props.title+"");
        if (props.description) popup.push(props.description);
        if (props.url)         popup.push(Safe.url(props.url));
        marker.bindPopup(popup.join('
'), {closeButton: false, closeOnClick: false, minWidth: 20});
      }

    } else if (props.filter === 'hackers') {

      if (state.get('zoom') >= zoomLevelPictures && props.image) { // show picture

        // hacker image
        marker.setIcon(L.icon({
          iconUrl:      props.image,
          className:    "marker-hacker picture",
          iconSize:     [40, 40], // size of the icon
          iconAnchor:   [20, 20], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -20] // point from which the popup should open relative to the iconAnchor
        }));

      } else {

        // hacker point
        marker.setIcon(L.icon({
          iconUrl:      "/img/markers/point.png",
          className:    "marker-hacker point",
          iconSize:     [6, 6], // size of the icon
          iconAnchor:   [3, 3], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -3] // point from which the popup should open relative to the iconAnchor
        }));
      }

      // make popup
      var popup = [];
      popup.push(""+props.title+"");
      popup.push(Safe.url(Users.userProfilePath(props.id), {text: 'hacker #'+Users.userRank(props.id), target: 'self'}));
      marker.bindPopup(popup.join('
'), {closeButton: false, closeOnClick: false, minWidth: 20});
    }
  });

  return featureLayer;
}

var setupFilters = function(featureLayer, $) {

  // // which filters are active/checked?
  // var getActiveFilters = function() {
  //   return $("[filter]:checked").map(function() {
  //     return $(this).attr('filter');
  //   });
  // }

  // // update filters, show markers of activated filters
  // var updateFilters = function() {
  //   var activeFilters = getActiveFilters();
  //   featureLayer.setFilter(function(feature) {
  //     return _.contains(activeFilters, feature.properties.filter);
  //   });
  // }

  // // handlers
  // $("[filter]").on('change', updateFilters);

  // // initial call
  // updateFilters();
}

var openFeaturePopup = function(featureLayer, selected) {
  featureLayer.eachLayer(function(marker) {
    var props = marker.feature.properties;
    if (selected && selected.id === props.id) {
      marker.openPopup();

      // ambassador can move markers
      if (Users.hasOwnerPermission(props) && editor.mode() === 'edit' && props.filter === 'places')
        marker.dragging.enable();
    }
    else {
      marker.closePopup();
      marker.dragging.disable();
    }
  });
}

/* Mode */

var switchMode = function(map, featureLayer) {
  resetEvents(map, featureLayer);
  setDefaultEvents(map, featureLayer);
}

/* Events */

var resetEvents = function(map, featureLayer) {
  map.off('click');
  featureLayer.off('mouseover');
  featureLayer.off('mouseout');
  featureLayer.off('click');
  featureLayer.eachLayer(function(marker) {
    marker.off('dragend');
  });
}

var setDefaultEvents = function(map, featureLayer) {
  featureLayer.on('click', function(e) {
    var selected = state.get('selected');
    if (selected && selected.id === e.layer.feature.properties.id) {
      state.set('selected', null);
    } else {
      state.set('selected', _.pick(e.layer.feature.properties, 'id', 'filter'));
    }
  });
  featureLayer.on('mouseover', function(e) {
    if (state.get('selected')) return;
    e.layer.openPopup();
  });
  featureLayer.on('mouseout', function(e) {
    if (state.get('selected')) return;
    e.layer.closePopup();
  });

  // dragging
  featureLayer.eachLayer(function(marker) {
    var markerId = marker.feature.properties.id;

    // update location
    marker.on('dragend', function(e) {
      updateLocation(markerId, _.pick(marker.getLatLng(), 'lat', 'lng'));
    });
  });
}

/* Data */

// load data and add markers to map
var setData = function(featureLayer) {
  var geoHackers = hackersFeatures();
  var geoPlaces = placesFeatures();
  var geojson = geoHackers.concat(geoPlaces);
  featureLayer.setGeoJSON(geojson);
}

// create a geojson feature for each hacker
// who have specified a location in their profile
var hackersFeatures = function() {

  // select only users with specified location
  var selector = {
    "city": Session.get('currentCity'),
    "profile.location.lat": {$type: 1},
    "profile.location.lng": {$type: 1},
  };

  return Users.find(selector).map(function(user) {
    return {  // geojson feature object
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [user.profile.location.lng, user.profile.location.lat]
      },
      "properties": {
        "filter": "hackers",
        "title": user.profile.name,
        "image": user.profile.picture,
        "url": Router.routes['hacker'].path(user),
        "id": user._id,
        // "marker-symbol": "marker-stroked",
        "marker-size": "small",
        "marker-color": "#fff",
      },
    };
  });
}

// create a geojson feature for each place from the Places collection.
var placesFeatures = function() {

  return Places.find(selector()).map(function(place) {
    return { // geojson feature object
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [place.location.lng, place.location.lat]
      },
      "properties": {
        "filter": "places",
        "title": place.title,
        "city": place.city,
        "userId": place.userId,
        "description": place.description,
        "type": place.type,
        "url": place.url,
        "id": place._id,
        "marker-color": "#f00",
      },
    };
  });
}

/* DB */

var selector = function() {
  var city = Session.get('currentCity');
  return Users.hasAmbassadorPermission() ? {} : {hiddenIn: {$ne: city}};
}

// create marker on clicked location
var insertPlace = function(location, cb) {
  Places.insert({location: location}, function(err, id) {
    cb && !err && cb(id);
  });
}

// remove marker
var removePlace = function(id) {
  state.set('selected', null);
  Places.remove(id);
}

// update location of selected place
var updateLocation = function(id, location) {
  Places.update(id, {$set: {location: location}});
}

// deselect after submit form
AutoForm.addHooks(editor.formId, {
  beginSubmit: function(formId) {
    var title = $("#"+formId).find("input[name='title']").val();
    if (!title)
      throw "title field is empty";
  }
});

// clear untitled markers
var clear = function(withoutId) {
  Places.find({_id: {$ne: withoutId}, title: {$exists: false}}).forEach(function(place) {
    Places.remove(place._id);
  });
}

<commit_msg>Show map profile pictures on lower zoom level.<commit_after>// State
var map, featureLayer;

var state = new State("map", {
  city: undefined,          // String
  location: undefined,      // Object {lat: Number, lng, Number}
  zoom: 13,                 // Number
  selected: null,           // Object? {filter: String, id: String}
});

var zoomLevelPictures = 13;

// editor

var editor = new Editor('Places');

// Template data

Template.map.helpers({
  'state': function() { return state; },
  'editor': function() {
    return editor;
  }
});

Template.map.events({
  "click  #PlacesEditor [action='add']": function() {
    var location = _.pick(map.getCenter(), 'lat', 'lng');
    insertPlace(location, function(id) {
      editor.open('edit', id);
    });
  },
  "click #PlacesEditor [action='edit']": function() {

    // select some
    if (!editor.selectedId()) {
      var min = null;
      var minDist = null;
      featureLayer.eachLayer(function(marker) {
        var dist = map.getCenter().distanceTo(marker.getLatLng());
        var isPlace = marker.feature.properties.filter === 'places';
        var permission = Users.hasOwnerPermission(marker.feature.properties);
        if (isPlace && permission && (!min || dist < minDist)) {
          min = marker;
          minDist = dist;
        }
      });
      if (min)
        editor.select(min.feature.properties.id);
    }
  },
});

// Template instance

Template.map.created = function() {
  var city = Session.get('currentCity');
  if (!state.equals('city', city)) {
    state.set('city', city);
    state.set('location', Geo.getCityLocation(city));
    state.set('zoom', state.defaults.zoom);
  }
}

Template.map.rendered = function() {

  // Setup map
  map           =  setupMap();
  featureLayer  =  setupFeatureLayer(map);
                   setupFilters(featureLayer, this.$);

  // Observers

  var initialized = false;
  this.dataObserver = Places.find({}).observeChanges({
    'added': function() { if (initialized) reload(); },
    'changed': function() { if (initialized) reload(); },
    'removed': function() { if (initialized) reload(); }
  });
  initialized = true;

  this.modeObserver = editor.observe('mode', function(mode) {
    reload();
    if (!mode)
      clear();
  });

  this.editorObserver = editor.observe('selectedId', function(id) {
    state.set('selected', id && {id: id, filter: 'places'} || null);
  });

  this.selectedObserver = state.observe('selected', function(selected) {
    openFeaturePopup(featureLayer, selected);
    editor.select(selected && selected.id);
    if (selected)
      clear(selected.id);
  });

  reload();
}

Template.map.destroyed = function() {
  this.dataObserver.stop();
  this.modeObserver.stop();
  this.editorObserver.stop();
  this.selectedObserver.stop();
}

/* Reload */

var reload = function() {
  setData(featureLayer);
  openFeaturePopup(featureLayer, state.get('selected'))
  switchMode(map, featureLayer);
}

/* Setup */

var setupMap = function() {

  var map = L.mapbox.map('mapbox', 'ramshorst.gd0ekbb3');

  // properties
  map.setView(state.get('location'));
  map.setZoom(state.get('zoom'));
  map.zoomControl.setPosition('topleft');

  // events
  map.on('moveend', function(e) {  // save location state
    state.set('location', map.getCenter())
  });
  map.on('zoomend', function(e) { // save zoom state
    var prevZoom = state.get('zoom');
    var newZoom = map.getZoom();

    // save zoom level
    state.set('zoom', newZoom)

    // reload data when certain zoom level is passed
    if (newZoom < zoomLevelPictures && zoomLevelPictures <= prevZoom
      || newZoom >= zoomLevelPictures && zoomLevelPictures > prevZoom) {
      reload();
    }
  });

  return map;
}

var setupFeatureLayer = function(map) {

  // create marker layer
  var featureLayer = L.mapbox.featureLayer().addTo(map);

  // icon based on feature properties
  featureLayer.on('layeradd', function(e) {
    var marker = e.layer;
    var props = marker.feature.properties;
    var type = props.type;

    if (props.filter === 'places') {

      // places marker
      if (type) {
        marker.setIcon(L.icon({
          iconUrl:      "/img/markers/"+type+".png",
          className:    "marker-place "+type,
          iconSize:     [27, 40], // size of the icon
          iconAnchor:   [13, 40], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -40] // point from which the popup should open relative to the iconAnchor
        }));

        // make popup
        var popup = [];
        if (props.title)       popup.push(""+props.title+"");
        if (props.description) popup.push(props.description);
        if (props.url)         popup.push(Safe.url(props.url));
        marker.bindPopup(popup.join('
'), {closeButton: false, closeOnClick: false, minWidth: 20});
      }

    } else if (props.filter === 'hackers') {

      if (state.get('zoom') >= zoomLevelPictures && props.image) { // show picture

        // hacker image
        marker.setIcon(L.icon({
          iconUrl:      props.image,
          className:    "marker-hacker picture",
          iconSize:     [40, 40], // size of the icon
          iconAnchor:   [20, 20], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -20] // point from which the popup should open relative to the iconAnchor
        }));

      } else {

        // hacker point
        marker.setIcon(L.icon({
          iconUrl:      "/img/markers/point.png",
          className:    "marker-hacker point",
          iconSize:     [6, 6], // size of the icon
          iconAnchor:   [3, 3], // point of the icon which will correspond to marker's location
          popupAnchor:  [0, -3] // point from which the popup should open relative to the iconAnchor
        }));
      }

      // make popup
      var popup = [];
      popup.push(""+props.title+"");
      popup.push(Safe.url(Users.userProfilePath(props.id), {text: 'hacker #'+Users.userRank(props.id), target: 'self'}));
      marker.bindPopup(popup.join('
'), {closeButton: false, closeOnClick: false, minWidth: 20});
    }
  });

  return featureLayer;
}

var setupFilters = function(featureLayer, $) {

  // // which filters are active/checked?
  // var getActiveFilters = function() {
  //   return $("[filter]:checked").map(function() {
  //     return $(this).attr('filter');
  //   });
  // }

  // // update filters, show markers of activated filters
  // var updateFilters = function() {
  //   var activeFilters = getActiveFilters();
  //   featureLayer.setFilter(function(feature) {
  //     return _.contains(activeFilters, feature.properties.filter);
  //   });
  // }

  // // handlers
  // $("[filter]").on('change', updateFilters);

  // // initial call
  // updateFilters();
}

var openFeaturePopup = function(featureLayer, selected) {
  featureLayer.eachLayer(function(marker) {
    var props = marker.feature.properties;
    if (selected && selected.id === props.id) {
      marker.openPopup();

      // ambassador can move markers
      if (Users.hasOwnerPermission(props) && editor.mode() === 'edit' && props.filter === 'places')
        marker.dragging.enable();
    }
    else {
      marker.closePopup();
      marker.dragging.disable();
    }
  });
}

/* Mode */

var switchMode = function(map, featureLayer) {
  resetEvents(map, featureLayer);
  setDefaultEvents(map, featureLayer);
}

/* Events */

var resetEvents = function(map, featureLayer) {
  map.off('click');
  featureLayer.off('mouseover');
  featureLayer.off('mouseout');
  featureLayer.off('click');
  featureLayer.eachLayer(function(marker) {
    marker.off('dragend');
  });
}

var setDefaultEvents = function(map, featureLayer) {
  featureLayer.on('click', function(e) {
    var selected = state.get('selected');
    if (selected && selected.id === e.layer.feature.properties.id) {
      state.set('selected', null);
    } else {
      state.set('selected', _.pick(e.layer.feature.properties, 'id', 'filter'));
    }
  });
  featureLayer.on('mouseover', function(e) {
    if (state.get('selected')) return;
    e.layer.openPopup();
  });
  featureLayer.on('mouseout', function(e) {
    if (state.get('selected')) return;
    e.layer.closePopup();
  });

  // dragging
  featureLayer.eachLayer(function(marker) {
    var markerId = marker.feature.properties.id;

    // update location
    marker.on('dragend', function(e) {
      updateLocation(markerId, _.pick(marker.getLatLng(), 'lat', 'lng'));
    });
  });
}

/* Data */

// load data and add markers to map
var setData = function(featureLayer) {
  var geoHackers = hackersFeatures();
  var geoPlaces = placesFeatures();
  var geojson = geoHackers.concat(geoPlaces);
  featureLayer.setGeoJSON(geojson);
}

// create a geojson feature for each hacker
// who have specified a location in their profile
var hackersFeatures = function() {

  // select only users with specified location
  var selector = {
    "city": Session.get('currentCity'),
    "profile.location.lat": {$type: 1},
    "profile.location.lng": {$type: 1},
  };

  return Users.find(selector).map(function(user) {
    return {  // geojson feature object
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [user.profile.location.lng, user.profile.location.lat]
      },
      "properties": {
        "filter": "hackers",
        "title": user.profile.name,
        "image": user.profile.picture,
        "url": Router.routes['hacker'].path(user),
        "id": user._id,
        // "marker-symbol": "marker-stroked",
        "marker-size": "small",
        "marker-color": "#fff",
      },
    };
  });
}

// create a geojson feature for each place from the Places collection.
var placesFeatures = function() {

  return Places.find(selector()).map(function(place) {
    return { // geojson feature object
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [place.location.lng, place.location.lat]
      },
      "properties": {
        "filter": "places",
        "title": place.title,
        "city": place.city,
        "userId": place.userId,
        "description": place.description,
        "type": place.type,
        "url": place.url,
        "id": place._id,
        "marker-color": "#f00",
      },
    };
  });
}

/* DB */

var selector = function() {
  var city = Session.get('currentCity');
  return Users.hasAmbassadorPermission() ? {} : {hiddenIn: {$ne: city}};
}

// create marker on clicked location
var insertPlace = function(location, cb) {
  Places.insert({location: location}, function(err, id) {
    cb && !err && cb(id);
  });
}

// remove marker
var removePlace = function(id) {
  state.set('selected', null);
  Places.remove(id);
}

// update location of selected place
var updateLocation = function(id, location) {
  Places.update(id, {$set: {location: location}});
}

// deselect after submit form
AutoForm.addHooks(editor.formId, {
  beginSubmit: function(formId) {
    var title = $("#"+formId).find("input[name='title']").val();
    if (!title)
      throw "title field is empty";
  }
});

// clear untitled markers
var clear = function(withoutId) {
  Places.find({_id: {$ne: withoutId}, title: {$exists: false}}).forEach(function(place) {
    Places.remove(place._id);
  });
}

<|endoftext|>


<commit_before>var locastyle = locastyle || {};

locastyle.popover = (function() {
  'use strict';

  var config = {
    container    : 'body',
    module       : '[data-ls-module="popover"]',
    idPopover    : '#ls-popover-',
    popoverClass : '.ls-popover',
    trigger      : 'click',
    events: {
      created: 'popover:ready',
      clicked: 'popover:clicked',
    }
  }

  function init() {
    checkExists();
    bindPopover();
  }

  function checkExists() {
    $(config.module).each(function(index, el) {
      if(!$(config.idPopover+index).length) {
        buildPopover(index, el);
      }
    });
    $(document).trigger(config.events.created);
  }

  function buildPopover(index, el) {
    var data = {
      index        : index,
      title        : $(el).data('title'),
      content      : $(el).data('content'),
      placement    : $(el).data('placement'),
      customClasses: $(el).data('custom-class')
    }
    setTarget(index, el);
    $(config.container).append(locastyle.templates.popover(data));
    setPosition(index, el);
  }

  // Define position of popover
  function setPosition(index, el) {
    var data = {
        target    : $(el).data('target'),
        top       : $(el).offset().top,
        left      : $(el).offset().left,
        width     : $(el).outerWidth(),
        height    : $(el).outerHeight(),
        placement : $(el).data('placement')
    }
    calcPosition(data);
  }

  // Calc the position of popover called
  function calcPosition(data) {
    var style;
    switch (data.placement) {
      case 'top':
        $(data.target).css({
          top : data.top  -=  12,
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'right':
        $(data.target).css({
          top : data.top  += (data.height/2 -2),
          left: data.left += (data.width + 12)
        });
        break;
      case 'bottom':
        $(data.target).css({
          top : data.top  += (data.height + 12),
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'left':
        $(data.target).css({
          top : data.top  += (data.height/2 -2 ),
          left: data.left -= 12
        });
    }
  }

  function bindPopover() {
    $(document).on(config.events.created, function() {

      // if ( !$(config.module).attr('data-trigger', 'hover').length ){
      //   console.log('true')
      // }
      //
      // var trigger = $(config.module).data('trigger') === 'hover' ? 'mouseover' : config.trigger;

      $(config.module).on('click', function() {
        $(this).trigger(config.events.clicked);
        show($(this).data('target'));
      });
    });
  }

  // Show called popover
  function show(target) {
    $(target).show();
  }

  // Hide all or visible popovers
  function hide(target) {
    $(target || config.popoverClass+':visible').hide();
  }

  // Destroy all created popovers
  function destroy() {
    $(config.popoverClass).remove();

    // Unbind all events.
    $.each(config.events, function(index, event) {
      $(document).unbind(event);
    });

  }

  return {
    init   : init,
    show   : show,
    hide   : hide,
    destroy: destroy
  };

}());
<commit_msg>changing name of event created and adding more events: popover:builded, popover:hastarget and popover:exist<commit_after>var locastyle = locastyle || {};

locastyle.popover = (function() {
  'use strict';

  var config = {
    container    : 'body',
    module       : '[data-ls-module="popover"]',
    idPopover    : '#ls-popover-',
    popoverClass : '.ls-popover',
    trigger      : 'click',
    events: {
      created: 'popover:created',
      clicked: 'popover:clicked',
      builded: 'popover:builded',
      targetSetted: 'popover:hastarget',
      checkedExistence: 'popover:exist'
    }
  }

  function init() {
    checkExists();
    bindPopover();
  }

  function checkExists() {
    $(config.module).each(function(index, el) {
      if(!$(config.idPopover+index).length) {
        buildPopover(index, el);
      }
    });
    $(document).trigger(config.events.created);
  }

  function buildPopover(index, el) {
    var data = {
      index        : index,
      title        : $(el).data('title'),
      content      : $(el).data('content'),
      placement    : $(el).data('placement'),
      customClasses: $(el).data('custom-class')
    }
    setTarget(index, el);
    $(config.container).append(locastyle.templates.popover(data));
    setPosition(index, el);
  }

  // Define position of popover
  function setPosition(index, el) {
    var data = {
        target    : $(el).data('target'),
        top       : $(el).offset().top,
        left      : $(el).offset().left,
        width     : $(el).outerWidth(),
        height    : $(el).outerHeight(),
        placement : $(el).data('placement')
    }
    calcPosition(data);
  }

  // Calc the position of popover called
  function calcPosition(data) {
    var style;
    switch (data.placement) {
      case 'top':
        $(data.target).css({
          top : data.top  -=  12,
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'right':
        $(data.target).css({
          top : data.top  += (data.height/2 -2),
          left: data.left += (data.width + 12)
        });
        break;
      case 'bottom':
        $(data.target).css({
          top : data.top  += (data.height + 12),
          left: data.left += (data.width/2 + 4)
        });
        break;
      case 'left':
        $(data.target).css({
          top : data.top  += (data.height/2 -2 ),
          left: data.left -= 12
        });
    }
  }

  function bindPopover() {
    $(document).on(config.events.created, function() {

      // if ( !$(config.module).attr('data-trigger', 'hover').length ){
      //   console.log('true')
      // }
      //
      // var trigger = $(config.module).data('trigger') === 'hover' ? 'mouseover' : config.trigger;

      $(config.module).on('click', function() {
        $(this).trigger(config.events.clicked);
        show($(this).data('target'));
      });
    });
  }

  // Show called popover
  function show(target) {
    $(target).show();
  }

  // Hide all or visible popovers
  function hide(target) {
    $(target || config.popoverClass+':visible').hide();
  }

  // Destroy all created popovers
  function destroy() {
    $(config.popoverClass).remove();

    // Unbind all events.
    $.each(config.events, function(index, event) {
      $(document).unbind(event);
    });

  }

  return {
    init   : init,
    show   : show,
    hide   : hide,
    destroy: destroy
  };

}());
<|endoftext|>


<commit_before>'use strict';

var manifest = {
  styles: [

    // purecss.io
    'node_modules/purecss/base.css',
    'node_modules/purecss/grids.css',
    'node_modules/purecss/grids-responsive.css',
    'node_modules/purecss/buttons.css',
    'node_modules/purecss/forms.css',
    'node_modules/purecss/menus.css',

    // blog
    'client/assets/main.css',
    'client/assets/syntax-highlighting.css'
  ],
  build: {
    css: '/assets/',
    js: '/assets/'
  }
};

try {
  manifest.build.css += require('./public/assets/styles-manifest.json')['styles.css'];
} catch (err) {
  manifest.build.css += 'styles.css';
}
try {
  manifest.build.js += require('./public/assets/application-manifest.json')['application.js'];
} catch (err) {
  manifest.build.js += 'application.js';
}

module.exports = manifest;

<commit_msg>remove empty lines<commit_after>'use strict';

var manifest = {
  styles: [
    // purecss.io
    'node_modules/purecss/base.css',
    'node_modules/purecss/grids.css',
    'node_modules/purecss/grids-responsive.css',
    'node_modules/purecss/buttons.css',
    'node_modules/purecss/forms.css',
    'node_modules/purecss/menus.css',

    // blog
    'client/assets/main.css',
    'client/assets/syntax-highlighting.css'
  ],
  build: {
    css: '/assets/',
    js: '/assets/'
  }
};

try {
  manifest.build.css += require('./public/assets/styles-manifest.json')['styles.css'];
} catch (err) {
  manifest.build.css += 'styles.css';
}
try {
  manifest.build.js += require('./public/assets/application-manifest.json')['application.js'];
} catch (err) {
  manifest.build.js += 'application.js';
}

module.exports = manifest;
<|endoftext|>