<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */
/**
 * @class
 */
OpenLayers.Layer = Class.create();
OpenLayers.Layer.prototype = {

    /** @type String */
    id: null,

    /** @type String */
    name: null,

    /** @type DOMElement */
    div: null,

    /** This variable is set when the layer is added to the map, via the
     *  accessor function setMap()
     *
     * @type OpenLayers.Map */
    map: null,

    /** Whether or not the layer is a base layer. This should be set
     *   individually by all subclasses.
     *   Default is false
     *
     * @type Boolean
     */
    isBaseLayer: false,

    /** asserts whether or not the layer's images have an alpha channel
     *
     * @type boolean */
    alpha: false,

  // OPTIONS

    /** @type Array */
    options: null,

    /** @type String */
    projection: null,

    /** @type OpenLayers.Bounds */
    maxExtent: null,

    /** @type float */
    maxResolution: null,

    /** @type int */
    minZoomLevel: null,

    /** @type int */
    maxZoomLevel: null,

    /** @type float */
    minScale: null,

    /** @type float */
    maxScale: null,

    /** @type String */
    units: null,

    /**
     * @constructor
     *
     * @param {String} name
     * @param {Object} options Hashtable of extra options to tag onto the layer
     */
    initialize: function(name, options) {
        if (arguments.length > 0) {

            //store a copy of the custom options for later cloning
            this.options = Object.extend(new Object(), options);

            //add options to layer
            Object.extend(this, this.options);

            this.name = name;

            //generate unique id based on name
            this.id = OpenLayers.Util.createUniqueID("Layer_");

            if (this.div == null) {
                this.div = OpenLayers.Util.createDiv();
                this.div.style.width = "100%";
                this.div.style.height = "100%";
            }
        }
    },

    /**
     * Destroy is a destructor: this is to alleviate cyclic references which
     * the Javascript garbage cleaner can not take care of on its own.
     */
    destroy: function() {
        if (this.map != null) {
            this.map.removeLayer(this);
        }
        this.map = null;
        this.name = null;
        this.div = null;
        this.options = null;
    },

   /**
    * @returns An exact clone of this OpenLayers.Layer
    * @type OpenLayers.Layer
    */
    clone: function (obj) {

        if (obj == null) {
            obj = new OpenLayers.Layer(this.name, this.options);
        }

        // catch any randomly tagged-on properties
        obj = OpenLayers.Util.applyDefaults(obj, this);

        // a cloned layer should never have its map property set
        //  because it has not been added to a map yet.
        obj.map = null;

        return obj;
    },

    /**
     * @param {String} newName
     */
    setName: function(newName) {
        this.name = newName;
        this.map.events.triggerEvent("changelayer");
    },

   /**
    * @param {Object} newOptions
    */
    addOptions: function (newOptions) {

        // update our copy for clone
        Object.extend(this.options, newOptions);

        // add new options to this
        Object.extend(this, this.options);
    },

    /**
     * @param {OpenLayers.Bounds} bound
     * @param {Boolean} zoomChanged tells when zoom has changed, as layers
     *                   have to do some init work in that case.
     * @param {Boolean} minor
     */
    moveTo:function(bounds, zoomChanged, minor) {
        //this function can be implemented by subclasses.
    },

    /**
     */
    reproject:function() {
        //this function can be implemented by subclasses.
    },

    /** Set the map property for the layer. This is done through an accessor
     *   so that subclasses can override this and take special action once
     *   they have their map variable set.
     *
     * @param {OpenLayers.Map} map
     */
    setMap: function(map) {
        this.map = map;

        var properties = new Array(
          'projection', 'minExtent', 'maxExtent',
          'minScale', 'maxScale',
          'maxResolution', 'minResolution',
          'minZoomLevel', 'maxZoomLevel', 'units',
          'scales', 'resolutions'

        );
        for(var i=0; i < properties.length; i++) {
            if (this[properties[i]] == null) {
                this[properties[i]] = this.map[properties[i]];
            }
        }
    },

    /**
    * @returns Whether or not the layer is visible
    * @type Boolean
    */
    getVisibility: function() {
        return (this.div.style.display != "none");
    },

    /**
     * @param {Boolean} visible
     * @param {Boolean} noEvent
     */
    setVisibility: function(visible, noEvent) {
        if (visible != this.getVisibility()) {
            this.div.style.display = (visible) ? "block" : "none";
            if ((visible) && (this.map != null)) {
                var extent = this.map.getExtent();
                if (extent != null) {
                    this.moveTo(this.map.getExtent());
                }
            }
            if ((this.map != null) &&
                ((noEvent == null) || (noEvent == false))) {
                this.map.events.triggerEvent("changelayer");
            }
        }
    },

  /********************************************************/
  /*                                                      */
  /*                 Layer Options                        */
  /*                                                      */
  /*    Accessor functions to Layer Options parameters    */
  /*                                                      */
  /********************************************************/

    /**
     * @type String
     */
    getProjection: function() {
        return this.projection;
    },

    /**
     * @type OpenLayers.Bounds
     */
    getMaxExtent: function() {
        return this.maxExtent;
    },

    /**
     * @type float
     */
    getMaxResolution: function() {
        return this.maxResolution;
    },

    /**
     * @returns The minimum zoom level that can be reached in this layer
     * @type int
     */
    getMinZoomLevel: function() {
        return this.minZoomLevel;
    },

    /**
     * @returns The maximum zoom level that can be reached in this layer
     * @type int
     */
    getMaxZoomLevel: function() {
        return this.maxZoomLevel;
    },

  /********************************************************/
  /*                                                      */
  /*                 Baselayer Functions                  */
  /*                                                      */
  /*    The following functions must all be implemented   */
  /*                  by all base layers                  */
  /*                                                      */
  /********************************************************/

    /**
     * @returns Degrees per Pixel
     * @type float
     */
    getResolution: function() {
        var viewSize = this.map.getSize();
        var extent = this.map.getExtent();
        return Math.max( extent.getWidth()  / viewSize.w,
                         extent.getHeight() / viewSize.h );
    },

    /** Calculates using px-> lonlat translation functions on tl and br
     *   corners of viewport
     *
     * @returns A Bounds object which represents the lon/lat bounds of the
     *          current viewPort.
     * @type OpenLayers.Bounds
     */
    getExtent: function () {
        var extent = null;

        var size = this.map.getSize();

        var tlPx = new OpenLayers.Pixel(0,0);
        var tlLL = this.getLonLatFromViewPortPx(tlPx);

        var brPx = new OpenLayers.Pixel(size.w, size.h);
        var brLL = this.getLonLatFromViewPortPx(brPx);

        if ((tlLL != null) && (brLL != null)) {
            extent = new OpenLayers.Bounds(tlLL.lon,
                                       brLL.lat,
                                       brLL.lon,
                                       tlLL.lat);
        }

        return extent;
    },

    /**
    * @param {OpenLayers.Pixel} viewPortPx
    *
    * @returns An OpenLayers.LonLat which is the passed-in view port
    *          OpenLayers.Pixel, translated into lon/lat by the layer
    * @type OpenLayers.LonLat
    */
    getLonLatFromViewPortPx: function (viewPortPx) {
        var size = this.map.getSize();
        var center = this.map.getCenter();        //map center lon/lat
        var res  = this.map.getResolution();

        var delta_x = viewPortPx.x - (size.w / 2);
        var delta_y = viewPortPx.y - (size.h / 2);

        return new OpenLayers.LonLat(center.lon + delta_x * res ,
                                     center.lat - delta_y * res);
    },

    /**
    * @param {OpenLayers.LonLat} lonlat
    *
    * @returns An OpenLayers.Pixel which is the passed-in OpenLayers.LonLat,
    *          translated into view port pixels
    * @type OpenLayers.Pixel
    */
    getViewPortPxFromLonLat: function (lonlat) {
        var resolution = this.map.getResolution();
        var extent = this.map.getExtent();
        return new OpenLayers.Pixel(
                       Math.round(1/resolution * (lonlat.lon - extent.left)),
                       Math.round(1/resolution * (extent.top - lonlat.lat))
                       );
    },

    /**
    * @param {OpenLayers.Bounds} bounds
    *
    * @return {int}
    */
    getZoomForExtent: function (bounds) {
        // this should be implemented by subclasses
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Layer"
};
<commit_msg>Fix in Layer.setName for test failure caused by r1188.<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */
/**
 * @class
 */
OpenLayers.Layer = Class.create();
OpenLayers.Layer.prototype = {

    /** @type String */
    id: null,

    /** @type String */
    name: null,

    /** @type DOMElement */
    div: null,

    /** This variable is set when the layer is added to the map, via the
     *  accessor function setMap()
     *
     * @type OpenLayers.Map */
    map: null,

    /** Whether or not the layer is a base layer. This should be set
     *   individually by all subclasses.
     *   Default is false
     *
     * @type Boolean
     */
    isBaseLayer: false,

    /** asserts whether or not the layer's images have an alpha channel
     *
     * @type boolean */
    alpha: false,

  // OPTIONS

    /** @type Array */
    options: null,

    /** @type String */
    projection: null,

    /** @type OpenLayers.Bounds */
    maxExtent: null,

    /** @type float */
    maxResolution: null,

    /** @type int */
    minZoomLevel: null,

    /** @type int */
    maxZoomLevel: null,

    /** @type float */
    minScale: null,

    /** @type float */
    maxScale: null,

    /** @type String */
    units: null,

    /**
     * @constructor
     *
     * @param {String} name
     * @param {Object} options Hashtable of extra options to tag onto the layer
     */
    initialize: function(name, options) {
        if (arguments.length > 0) {

            //store a copy of the custom options for later cloning
            this.options = Object.extend(new Object(), options);

            //add options to layer
            Object.extend(this, this.options);

            this.name = name;

            //generate unique id based on name
            this.id = OpenLayers.Util.createUniqueID("Layer_");

            if (this.div == null) {
                this.div = OpenLayers.Util.createDiv();
                this.div.style.width = "100%";
                this.div.style.height = "100%";
            }
        }
    },

    /**
     * Destroy is a destructor: this is to alleviate cyclic references which
     * the Javascript garbage cleaner can not take care of on its own.
     */
    destroy: function() {
        if (this.map != null) {
            this.map.removeLayer(this);
        }
        this.map = null;
        this.name = null;
        this.div = null;
        this.options = null;
    },

   /**
    * @returns An exact clone of this OpenLayers.Layer
    * @type OpenLayers.Layer
    */
    clone: function (obj) {

        if (obj == null) {
            obj = new OpenLayers.Layer(this.name, this.options);
        }

        // catch any randomly tagged-on properties
        obj = OpenLayers.Util.applyDefaults(obj, this);

        // a cloned layer should never have its map property set
        //  because it has not been added to a map yet.
        obj.map = null;

        return obj;
    },

    /**
     * @param {String} newName
     */
    setName: function(newName) {
        this.name = newName;
        // assuming a map has been assigned, trigger changelayer
        if (this.map != null)
            this.map.events.triggerEvent("changelayer");
    },

   /**
    * @param {Object} newOptions
    */
    addOptions: function (newOptions) {

        // update our copy for clone
        Object.extend(this.options, newOptions);

        // add new options to this
        Object.extend(this, this.options);
    },

    /**
     * @param {OpenLayers.Bounds} bound
     * @param {Boolean} zoomChanged tells when zoom has changed, as layers
     *                   have to do some init work in that case.
     * @param {Boolean} minor
     */
    moveTo:function(bounds, zoomChanged, minor) {
        //this function can be implemented by subclasses.
    },

    /**
     */
    reproject:function() {
        //this function can be implemented by subclasses.
    },

    /** Set the map property for the layer. This is done through an accessor
     *   so that subclasses can override this and take special action once
     *   they have their map variable set.
     *
     * @param {OpenLayers.Map} map
     */
    setMap: function(map) {
        this.map = map;

        var properties = new Array(
          'projection', 'minExtent', 'maxExtent',
          'minScale', 'maxScale',
          'maxResolution', 'minResolution',
          'minZoomLevel', 'maxZoomLevel', 'units',
          'scales', 'resolutions'

        );
        for(var i=0; i < properties.length; i++) {
            if (this[properties[i]] == null) {
                this[properties[i]] = this.map[properties[i]];
            }
        }
    },

    /**
    * @returns Whether or not the layer is visible
    * @type Boolean
    */
    getVisibility: function() {
        return (this.div.style.display != "none");
    },

    /**
     * @param {Boolean} visible
     * @param {Boolean} noEvent
     */
    setVisibility: function(visible, noEvent) {
        if (visible != this.getVisibility()) {
            this.div.style.display = (visible) ? "block" : "none";
            if ((visible) && (this.map != null)) {
                var extent = this.map.getExtent();
                if (extent != null) {
                    this.moveTo(this.map.getExtent());
                }
            }
            if ((this.map != null) &&
                ((noEvent == null) || (noEvent == false))) {
                this.map.events.triggerEvent("changelayer");
            }
        }
    },

  /********************************************************/
  /*                                                      */
  /*                 Layer Options                        */
  /*                                                      */
  /*    Accessor functions to Layer Options parameters    */
  /*                                                      */
  /********************************************************/

    /**
     * @type String
     */
    getProjection: function() {
        return this.projection;
    },

    /**
     * @type OpenLayers.Bounds
     */
    getMaxExtent: function() {
        return this.maxExtent;
    },

    /**
     * @type float
     */
    getMaxResolution: function() {
        return this.maxResolution;
    },

    /**
     * @returns The minimum zoom level that can be reached in this layer
     * @type int
     */
    getMinZoomLevel: function() {
        return this.minZoomLevel;
    },

    /**
     * @returns The maximum zoom level that can be reached in this layer
     * @type int
     */
    getMaxZoomLevel: function() {
        return this.maxZoomLevel;
    },

  /********************************************************/
  /*                                                      */
  /*                 Baselayer Functions                  */
  /*                                                      */
  /*    The following functions must all be implemented   */
  /*                  by all base layers                  */
  /*                                                      */
  /********************************************************/

    /**
     * @returns Degrees per Pixel
     * @type float
     */
    getResolution: function() {
        var viewSize = this.map.getSize();
        var extent = this.map.getExtent();
        return Math.max( extent.getWidth()  / viewSize.w,
                         extent.getHeight() / viewSize.h );
    },

    /** Calculates using px-> lonlat translation functions on tl and br
     *   corners of viewport
     *
     * @returns A Bounds object which represents the lon/lat bounds of the
     *          current viewPort.
     * @type OpenLayers.Bounds
     */
    getExtent: function () {
        var extent = null;

        var size = this.map.getSize();

        var tlPx = new OpenLayers.Pixel(0,0);
        var tlLL = this.getLonLatFromViewPortPx(tlPx);

        var brPx = new OpenLayers.Pixel(size.w, size.h);
        var brLL = this.getLonLatFromViewPortPx(brPx);

        if ((tlLL != null) && (brLL != null)) {
            extent = new OpenLayers.Bounds(tlLL.lon,
                                       brLL.lat,
                                       brLL.lon,
                                       tlLL.lat);
        }

        return extent;
    },

    /**
    * @param {OpenLayers.Pixel} viewPortPx
    *
    * @returns An OpenLayers.LonLat which is the passed-in view port
    *          OpenLayers.Pixel, translated into lon/lat by the layer
    * @type OpenLayers.LonLat
    */
    getLonLatFromViewPortPx: function (viewPortPx) {
        var size = this.map.getSize();
        var center = this.map.getCenter();        //map center lon/lat
        var res  = this.map.getResolution();

        var delta_x = viewPortPx.x - (size.w / 2);
        var delta_y = viewPortPx.y - (size.h / 2);

        return new OpenLayers.LonLat(center.lon + delta_x * res ,
                                     center.lat - delta_y * res);
    },

    /**
    * @param {OpenLayers.LonLat} lonlat
    *
    * @returns An OpenLayers.Pixel which is the passed-in OpenLayers.LonLat,
    *          translated into view port pixels
    * @type OpenLayers.Pixel
    */
    getViewPortPxFromLonLat: function (lonlat) {
        var resolution = this.map.getResolution();
        var extent = this.map.getExtent();
        return new OpenLayers.Pixel(
                       Math.round(1/resolution * (lonlat.lon - extent.left)),
                       Math.round(1/resolution * (extent.top - lonlat.lat))
                       );
    },

    /**
    * @param {OpenLayers.Bounds} bounds
    *
    * @return {int}
    */
    getZoomForExtent: function (bounds) {
        // this should be implemented by subclasses
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Layer"
};
<|endoftext|>


<commit_before>/* ===================================================
 * bootstrap-tagmanager.js v2.2
 * http://welldonethings.com/tags/manager
 * ===================================================
 * Copyright 2012 Max Favilli
 *
 * Licensed under the Mozilla Public License, Version 2.0 You may not use this work except in compliance with the License.
 *
 * http://www.mozilla.org/MPL/2.0/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

"use strict";

(function (jQuery) {
  if (typeof console === "undefined" || typeof console.log === "undefined") {
    console = {};
    console.log = function () { };
  }

  jQuery.fn.tagsManager = function (options,tagToManipulate) {
    var tagManagerOptions = {
      prefilled: null,
      CapitalizeFirstLetter: false,
      preventSubmitOnEnter: true,
      typeahead: false,
      typeaheadAjaxSource: null,
      typeaheadAjaxPolling: false,
      typeaheadSource: null,
      AjaxPush: null,
      delimeters: [44, 188, 13],
      backspace: [8],
      maxTags: 0,
      hiddenTagListName: null,
      deleteTagsOnBackspace: true,
      tagsContainer: null,
      tagCloseIcon: 'x'
    };

    jQuery.extend(tagManagerOptions, options);

    if (tagManagerOptions.hiddenTagListName === null) {
      tagManagerOptions.hiddenTagListName = "hidden-" + this.attr('name');
    }

    var obj = this;
    var objName = obj.attr('name').replace(/[^\w]/g, '_');
    var queuedTag = "";
    var delimeters = tagManagerOptions.delimeters;
    var backspace = tagManagerOptions.backspace;

    var setupTypeahead = function () {
      if (!obj.typeahead) return;

      if (tagManagerOptions.typeaheadSource != null && jQuery.isFunction(tagManagerOptions.typeaheadSource)) {
        obj.typeahead({ source: tagManagerOptions.typeaheadSource });
      } else if (tagManagerOptions.typeaheadSource != null) {
        obj.typeahead();
        obj.data('active', true);
        obj.data('typeahead').source = tagManagerOptions.typeaheadSource;
        obj.data('active', false);
      } else if (tagManagerOptions.typeaheadAjaxSource != null) {
        if (!tagManagerOptions.typeaheadAjaxPolling) {
          obj.typeahead();
          jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource, function (data) {
            var sourceAjaxArray = [];
            if (data != undefined && data.tags != undefined) {
              sourceAjaxArray.length = 0;
              jQuery.each(data.tags, function (key, val) {
                var a = 1;
                sourceAjaxArray.push(val.tag);
                obj.data('active', true);
                obj.data('typeahead').source = sourceAjaxArray;
                obj.data('active', false);
              });
            }
          });
        } else if (tagManagerOptions.typeaheadAjaxPolling) {
          obj.typeahead({ source: ajaxPolling });
        }
      } else if (tagManagerOptions.typeaheadDelegate) {
        obj.typeahead(tagManagerOptions.typeaheadDelegate)
      }
    };

    var ajaxPolling = function (query, process) {
      jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource, function (data) {
        var sourceAjaxArray = [];
        if (data != undefined && data.tags != undefined) {
          sourceAjaxArray.length = 0;
          jQuery.each(data.tags, function (key, val) {
            var a = 1;
            sourceAjaxArray.push(val.tag);
          });
          process(sourceAjaxArray);
        }
      });
    };

    var trimTag = function (tag) {
      var txt = jQuery.trim(tag);

      var l = txt.length;
      var t = 0;

      for (var i = l - 1; i >= 0; i--) {
        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
        t++;
      }

      txt = txt.substring(0, l - t);
      l = txt.length;
      t = 0;

      //remove from head
      for (var i = 0; i < l; i++) {
        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
        t++;
      }

      txt = txt.substring(t, l);
      return txt;
    };

    //$(this).on('popTag', function (e){
    //  var tlis = obj.data("tlis");
    //  var tlid = obj.data("tlid");

    //  if (tlid.length > 0) {
    //    var tagId = tlid.pop();
    //    tlis.pop();
    //    // console.log("TagIdToRemove: " + tagId);
    //    jQuery("#" + objName + "_" + tagId).remove();
    //    refreshHiddenTagList();
    //    // console.log(tlis);
    //  }
    //});

    var popTag = function () {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      if (tlid.length > 0) {
        var tagId = tlid.pop();
        tlis.pop();
        // console.log("TagIdToRemove: " + tagId);
        jQuery("#" + objName + "_" + tagId).remove();
        refreshHiddenTagList();
        // console.log(tlis);
      }
    };

    var empty = function () {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      while (tlid.length > 0) {
        var tagId = tlid.pop();
        tlis.pop();
        // console.log("TagIdToRemove: " + tagId);
        jQuery("#" + objName + "_" + tagId).remove();
        refreshHiddenTagList();
        // console.log(tlis);
      }
    };

    var refreshHiddenTagList = function () {
      var tlis = obj.data("tlis");
      var lhiddenTagList = obj.data("lhiddenTagList");

      if (lhiddenTagList == undefined)
        return;

      jQuery(lhiddenTagList).val(tlis.join(",")).change();
    };

    var spliceTag = function (tagId) {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      var p = jQuery.inArray(tagId, tlid)

      // console.log("TagIdToRemove: " + tagId);
      // console.log("position: " + p);

      if (-1 != p) {
        jQuery("#" + objName + "_" + tagId).remove();
        tlis.splice(p, 1);
        tlid.splice(p, 1);
        refreshHiddenTagList();
        // console.log(tlis);
      }

      if (tagManagerOptions.maxTags > 0 && tlis.length < tagManagerOptions.maxTags) {
        obj.show();
      }
    };

    var pushTag = function (tag) {
      if (!tag || tag.length <= 0) return;

      if (tagManagerOptions.CapitalizeFirstLetter && tag.length > 1) {
        tag = tag.charAt(0).toUpperCase() + tag.slice(1).toLowerCase();
      }

      // call the validator (if any) and do not let the tag pass if invalid
      if (tagManagerOptions.validator !== undefined) {
        if (tagManagerOptions.validator(tag) !== true) return;
      }

      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      // dont accept new tags beyond the defined maximum
      if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) return;

      var alreadyInList = false;
      var p = jQuery.inArray(tag, tlis);
      if (-1 != p) {
        // console.log("tag:" + tag + " !!already in list!!");
        alreadyInList = true;
      }

      if (alreadyInList) {
        var pTagId = tlid[p];
        jQuery("#" + objName + "_" + pTagId).stop()
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100);
      } else {
        var max = Math.max.apply(null, tlid);
        max = max == -Infinity ? 0 : max;

        var tagId = ++max;
        tlis.push(tag);
        tlid.push(tagId);

        if (tagManagerOptions.AjaxPush != null) {
          jQuery.post(tagManagerOptions.AjaxPush, { tag: tag });
        }

        // console.log("tagList: " + tlis);

        var newTagId = objName + '_' + tagId;
        var newTagRemoveId = objName + '_Remover_' + tagId;
        var html = '';
        html += '' + tag + '  ' + tagManagerOptions.tagCloseIcon + '';

        if (tagManagerOptions.tagsContainer != null) {
          jQuery(tagManagerOptions.tagsContainer).append(html)
        } else {
          obj.before(html);
        }

        jQuery("#" + newTagRemoveId).on("click", obj, function (e) {
          e.preventDefault();
          var TagIdToRemove = parseInt(jQuery(this).attr("TagIdToRemove"));
          spliceTag(TagIdToRemove, e.data);
        });

        refreshHiddenTagList();

        if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) {
          obj.hide();
        }
      }
      obj.val("");
    };

    return this.each(function () {

      if (typeof options == 'string') {
        switch (options) {
          case "empty":
            empty();
            break;
          case "popTag":
            popTag();
            break;
          case "pushTag":
            pushTag(tagToManipulate);
            break;
        }
        return;
      }

      //let's store some instance specific data directly into the DOM object
      var tlis = new Array();
      var tlid = new Array();
      obj.data("tlis", tlis); //list of string tags
      obj.data("tlid", tlid); //list of ID of the string tags

      var html = "";
      html += "<input name='" + tagManagerOptions.hiddenTagListName + "' type='hidden' value=''/>";
      obj.after(html);
      obj.data("lhiddenTagList",
         obj.siblings("input[name='" + tagManagerOptions.hiddenTagListName + "']")[0]
      );

      if (tagManagerOptions.typeahead) {
        setupTypeahead();
        //obj.typeahead({ source: SourceArray })
      }

      obj.on("focus", function (e) {
        if (jQuery(this).popover) {
          jQuery(this).popover("hide");
          //jQuery(this).popover = null;
        }
      });

      // disable submit on enter for this input field
      obj.on("keypress", function (e) {
        if (jQuery(this).popover) {
          jQuery(this).popover("hide");
          //jQuery(this).popover = null;
        }
        if (tagManagerOptions.preventSubmitOnEnter) {
          if (e.which == 13) {
            e.cancelBubble = true;
            e.returnValue = false;
            e.stopPropagation();
            e.preventDefault();
            //e.keyCode = 9;
          }
        }
        // console.log("keyup: " + e.keyCode);
      });

      obj.on("keyup", obj, function (e) {
        var p = jQuery.inArray(e.which, delimeters);
        if (-1 != p) {
          //user just entered a valid delimeter
          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
          user_input = trimTag(user_input);
          pushTag(user_input, e.data);
          // console.log("pushTag: keyup");
        }

        // console.log("keyup: " + e.which);
      });

      if (tagManagerOptions.deleteTagsOnBackspace) {
        obj.on("keydown", obj, function (e) {
          var p = jQuery.inArray(e.which, backspace);
          if (-1 != p) {
            //user just entered backspace or equivalent
            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
            var i = user_input.length;
            if (i <= 0) {
              // console.log("backspace detected");
              e.preventDefault();
              popTag();
            }
          }
        });
      }

      obj.change(function (e) {
        e.cancelBubble = true;
        e.returnValue = false;
        e.stopPropagation();
        e.preventDefault();

        var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
        var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
        var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
        var is_safari = navigator.userAgent.indexOf("Safari") > -1;

        if (!is_chrome && !is_safari)
          jQuery(this).focus();

        // console.log('Handler for .change() called, value selected:' + obj.val());
        var ao = jQuery(".typeahead:visible");
        if (ao[0] != undefined) {
          // console.log('change: typeaheadIsVisible is visible');
          //when the user click with the mouse on the typeahead li element we get the change event fired twice, once when the input field loose focus and later with the input field value is replaced with li value
          var user_input = $(this).data('typeahead').$menu.find('.active').attr('data-value');
          user_input = trimTag(user_input);
          if (queuedTag == obj.val() && queuedTag == user_input) {
            queuedTag = "";
            obj.val(queuedTag);
          } else {
            pushTag(user_input);
            queuedTag = user_input;
            // console.log('Handler for .change() called, typeahead value pushed:' + queuedTag);
          }
        } else {
          // console.log('change: typeaheadIsVisible is NOT visible');
          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
          user_input = trimTag(user_input);
          pushTag(user_input);
          // console.log("pushTag: change ");
        }

      });

      if (1 == 1 || !tagManagerOptions.typeahead) {
        obj.on("blur", function (e) {
          //lost focus
          e.cancelBubble = true;
          e.returnValue = false;
          e.stopPropagation();
          e.preventDefault();

          var push = true;
          if (tagManagerOptions.typeahead) {
            var ao = jQuery(".typeahead:visible");
            if (ao[0] != undefined) {
              // console.log('blur: typeaheadIsVisible is visible');
              push = false;
            } else {
              // console.log('blur: typeaheadIsVisible is NOT visible');
              push = true;
            }
          }

          if (push) {
            // console.log('lost focus');
            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
            user_input = trimTag(user_input);
            pushTag(user_input);
            // console.log("pushTag: blur");
          }
        });
      }

      if (tagManagerOptions.prefilled != null) {
        if (typeof (tagManagerOptions.prefilled) == "object") {
          var pta = tagManagerOptions.prefilled;
          jQuery.each(pta, function (key, val) {
            var a = 1;
            pushTag(val, obj);
          });
        } else if (typeof (tagManagerOptions.prefilled) == "string") {
          var pta = tagManagerOptions.prefilled.split(',');

          jQuery.each(pta, function (key, val) {
            var a = 1;
            pushTag(val, obj);
          });

        }
      }
    });

  }
})(jQuery);<commit_msg>added tagClass to options<commit_after>/* ===================================================
 * bootstrap-tagmanager.js v2.2
 * http://welldonethings.com/tags/manager
 * ===================================================
 * Copyright 2012 Max Favilli
 *
 * Licensed under the Mozilla Public License, Version 2.0 You may not use this work except in compliance with the License.
 *
 * http://www.mozilla.org/MPL/2.0/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

"use strict";

(function (jQuery) {
  if (typeof console === "undefined" || typeof console.log === "undefined") {
    console = {};
    console.log = function () { };
  }

  jQuery.fn.tagsManager = function (options,tagToManipulate) {
    var tagManagerOptions = {
      prefilled: null,
      CapitalizeFirstLetter: false,
      preventSubmitOnEnter: true,
      typeahead: false,
      typeaheadAjaxSource: null,
      typeaheadAjaxPolling: false,
      typeaheadSource: null,
      AjaxPush: null,
      delimeters: [44, 188, 13],
      backspace: [8],
      maxTags: 0,
      hiddenTagListName: null,
      deleteTagsOnBackspace: true,
      tagsContainer: null,
      tagCloseIcon: 'x',
      tagClass: ''
    };

    jQuery.extend(tagManagerOptions, options);

    if (tagManagerOptions.hiddenTagListName === null) {
      tagManagerOptions.hiddenTagListName = "hidden-" + this.attr('name');
    }

    var obj = this;
    var objName = obj.attr('name').replace(/[^\w]/g, '_');
    var queuedTag = "";
    var delimeters = tagManagerOptions.delimeters;
    var backspace = tagManagerOptions.backspace;

    var setupTypeahead = function () {
      if (!obj.typeahead) return;

      if (tagManagerOptions.typeaheadSource != null && jQuery.isFunction(tagManagerOptions.typeaheadSource)) {
        obj.typeahead({ source: tagManagerOptions.typeaheadSource });
      } else if (tagManagerOptions.typeaheadSource != null) {
        obj.typeahead();
        obj.data('active', true);
        obj.data('typeahead').source = tagManagerOptions.typeaheadSource;
        obj.data('active', false);
      } else if (tagManagerOptions.typeaheadAjaxSource != null) {
        if (!tagManagerOptions.typeaheadAjaxPolling) {
          obj.typeahead();
          jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource, function (data) {
            var sourceAjaxArray = [];
            if (data != undefined && data.tags != undefined) {
              sourceAjaxArray.length = 0;
              jQuery.each(data.tags, function (key, val) {
                var a = 1;
                sourceAjaxArray.push(val.tag);
                obj.data('active', true);
                obj.data('typeahead').source = sourceAjaxArray;
                obj.data('active', false);
              });
            }
          });
        } else if (tagManagerOptions.typeaheadAjaxPolling) {
          obj.typeahead({ source: ajaxPolling });
        }
      } else if (tagManagerOptions.typeaheadDelegate) {
        obj.typeahead(tagManagerOptions.typeaheadDelegate)
      }
    };

    var ajaxPolling = function (query, process) {
      jQuery.getJSON(tagManagerOptions.typeaheadAjaxSource, function (data) {
        var sourceAjaxArray = [];
        if (data != undefined && data.tags != undefined) {
          sourceAjaxArray.length = 0;
          jQuery.each(data.tags, function (key, val) {
            var a = 1;
            sourceAjaxArray.push(val.tag);
          });
          process(sourceAjaxArray);
        }
      });
    };

    var trimTag = function (tag) {
      var txt = jQuery.trim(tag);

      var l = txt.length;
      var t = 0;

      for (var i = l - 1; i >= 0; i--) {
        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
        t++;
      }

      txt = txt.substring(0, l - t);
      l = txt.length;
      t = 0;

      //remove from head
      for (var i = 0; i < l; i++) {
        if (-1 == jQuery.inArray(txt.charCodeAt(i), delimeters)) break;
        t++;
      }

      txt = txt.substring(t, l);
      return txt;
    };

    //$(this).on('popTag', function (e){
    //  var tlis = obj.data("tlis");
    //  var tlid = obj.data("tlid");

    //  if (tlid.length > 0) {
    //    var tagId = tlid.pop();
    //    tlis.pop();
    //    // console.log("TagIdToRemove: " + tagId);
    //    jQuery("#" + objName + "_" + tagId).remove();
    //    refreshHiddenTagList();
    //    // console.log(tlis);
    //  }
    //});

    var popTag = function () {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      if (tlid.length > 0) {
        var tagId = tlid.pop();
        tlis.pop();
        // console.log("TagIdToRemove: " + tagId);
        jQuery("#" + objName + "_" + tagId).remove();
        refreshHiddenTagList();
        // console.log(tlis);
      }
    };

    var empty = function () {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      while (tlid.length > 0) {
        var tagId = tlid.pop();
        tlis.pop();
        // console.log("TagIdToRemove: " + tagId);
        jQuery("#" + objName + "_" + tagId).remove();
        refreshHiddenTagList();
        // console.log(tlis);
      }
    };

    var refreshHiddenTagList = function () {
      var tlis = obj.data("tlis");
      var lhiddenTagList = obj.data("lhiddenTagList");

      if (lhiddenTagList == undefined)
        return;

      jQuery(lhiddenTagList).val(tlis.join(",")).change();
    };

    var spliceTag = function (tagId) {
      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      var p = jQuery.inArray(tagId, tlid)

      // console.log("TagIdToRemove: " + tagId);
      // console.log("position: " + p);

      if (-1 != p) {
        jQuery("#" + objName + "_" + tagId).remove();
        tlis.splice(p, 1);
        tlid.splice(p, 1);
        refreshHiddenTagList();
        // console.log(tlis);
      }

      if (tagManagerOptions.maxTags > 0 && tlis.length < tagManagerOptions.maxTags) {
        obj.show();
      }
    };

    var pushTag = function (tag) {
      if (!tag || tag.length <= 0) return;

      if (tagManagerOptions.CapitalizeFirstLetter && tag.length > 1) {
        tag = tag.charAt(0).toUpperCase() + tag.slice(1).toLowerCase();
      }

      // call the validator (if any) and do not let the tag pass if invalid
      if (tagManagerOptions.validator !== undefined) {
        if (tagManagerOptions.validator(tag) !== true) return;
      }

      var tlis = obj.data("tlis");
      var tlid = obj.data("tlid");

      // dont accept new tags beyond the defined maximum
      if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) return;

      var alreadyInList = false;
      var p = jQuery.inArray(tag, tlis);
      if (-1 != p) {
        // console.log("tag:" + tag + " !!already in list!!");
        alreadyInList = true;
      }

      if (alreadyInList) {
        var pTagId = tlid[p];
        jQuery("#" + objName + "_" + pTagId).stop()
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_1 }, 100)
           .animate({ backgroundColor: tagManagerOptions.blinkBGColor_2 }, 100);
      } else {
        var max = Math.max.apply(null, tlid);
        max = max == -Infinity ? 0 : max;

        var tagId = ++max;
        tlis.push(tag);
        tlid.push(tagId);

        if (tagManagerOptions.AjaxPush != null) {
          jQuery.post(tagManagerOptions.AjaxPush, { tag: tag });
        }

        // console.log("tagList: " + tlis);

        var newTagId = objName + '_' + tagId;
        var newTagRemoveId = objName + '_Remover_' + tagId;
        var html = '';
        var cl = tagManagerOptions.tagClass ? ' '+tagManagerOptions.tagClass : '';
        html += '' + tag + '  ' + tagManagerOptions.tagCloseIcon + ' ';

        if (tagManagerOptions.tagsContainer != null) {
          jQuery(tagManagerOptions.tagsContainer).append(html)
        } else {
          obj.before(html);
        }

        jQuery("#" + newTagRemoveId).on("click", obj, function (e) {
          e.preventDefault();
          var TagIdToRemove = parseInt(jQuery(this).attr("TagIdToRemove"));
          spliceTag(TagIdToRemove, e.data);
        });

        refreshHiddenTagList();

        if (tagManagerOptions.maxTags > 0 && tlis.length >= tagManagerOptions.maxTags) {
          obj.hide();
        }
      }
      obj.val("");
    };

    return this.each(function () {

      if (typeof options == 'string') {
        switch (options) {
          case "empty":
            empty();
            break;
          case "popTag":
            popTag();
            break;
          case "pushTag":
            pushTag(tagToManipulate);
            break;
        }
        return;
      }

      //let's store some instance specific data directly into the DOM object
      var tlis = new Array();
      var tlid = new Array();
      obj.data("tlis", tlis); //list of string tags
      obj.data("tlid", tlid); //list of ID of the string tags

      var html = "";
      html += "<input name='" + tagManagerOptions.hiddenTagListName + "' type='hidden' value=''/>";
      obj.after(html);
      obj.data("lhiddenTagList",
         obj.siblings("input[name='" + tagManagerOptions.hiddenTagListName + "']")[0]
      );

      if (tagManagerOptions.typeahead) {
        setupTypeahead();
        //obj.typeahead({ source: SourceArray })
      }

      obj.on("focus", function (e) {
        if (jQuery(this).popover) {
          jQuery(this).popover("hide");
          //jQuery(this).popover = null;
        }
      });

      // disable submit on enter for this input field
      obj.on("keypress", function (e) {
        if (jQuery(this).popover) {
          jQuery(this).popover("hide");
          //jQuery(this).popover = null;
        }
        if (tagManagerOptions.preventSubmitOnEnter) {
          if (e.which == 13) {
            e.cancelBubble = true;
            e.returnValue = false;
            e.stopPropagation();
            e.preventDefault();
            //e.keyCode = 9;
          }
        }
        // console.log("keyup: " + e.keyCode);
      });

      obj.on("keyup", obj, function (e) {
        var p = jQuery.inArray(e.which, delimeters);
        if (-1 != p) {
          //user just entered a valid delimeter
          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
          user_input = trimTag(user_input);
          pushTag(user_input, e.data);
          // console.log("pushTag: keyup");
        }

        // console.log("keyup: " + e.which);
      });

      if (tagManagerOptions.deleteTagsOnBackspace) {
        obj.on("keydown", obj, function (e) {
          var p = jQuery.inArray(e.which, backspace);
          if (-1 != p) {
            //user just entered backspace or equivalent
            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
            var i = user_input.length;
            if (i <= 0) {
              // console.log("backspace detected");
              e.preventDefault();
              popTag();
            }
          }
        });
      }

      obj.change(function (e) {
        e.cancelBubble = true;
        e.returnValue = false;
        e.stopPropagation();
        e.preventDefault();

        var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
        var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
        var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
        var is_safari = navigator.userAgent.indexOf("Safari") > -1;

        if (!is_chrome && !is_safari)
          jQuery(this).focus();

        // console.log('Handler for .change() called, value selected:' + obj.val());
        var ao = jQuery(".typeahead:visible");
        if (ao[0] != undefined) {
          // console.log('change: typeaheadIsVisible is visible');
          //when the user click with the mouse on the typeahead li element we get the change event fired twice, once when the input field loose focus and later with the input field value is replaced with li value
          var user_input = $(this).data('typeahead').$menu.find('.active').attr('data-value');
          user_input = trimTag(user_input);
          if (queuedTag == obj.val() && queuedTag == user_input) {
            queuedTag = "";
            obj.val(queuedTag);
          } else {
            pushTag(user_input);
            queuedTag = user_input;
            // console.log('Handler for .change() called, typeahead value pushed:' + queuedTag);
          }
        } else {
          // console.log('change: typeaheadIsVisible is NOT visible');
          var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
          user_input = trimTag(user_input);
          pushTag(user_input);
          // console.log("pushTag: change ");
        }

      });

      if (1 == 1 || !tagManagerOptions.typeahead) {
        obj.on("blur", function (e) {
          //lost focus
          e.cancelBubble = true;
          e.returnValue = false;
          e.stopPropagation();
          e.preventDefault();

          var push = true;
          if (tagManagerOptions.typeahead) {
            var ao = jQuery(".typeahead:visible");
            if (ao[0] != undefined) {
              // console.log('blur: typeaheadIsVisible is visible');
              push = false;
            } else {
              // console.log('blur: typeaheadIsVisible is NOT visible');
              push = true;
            }
          }

          if (push) {
            // console.log('lost focus');
            var user_input = jQuery(this).val(); //user_input = jQuery().inArray(delimeters[p]);
            user_input = trimTag(user_input);
            pushTag(user_input);
            // console.log("pushTag: blur");
          }
        });
      }

      if (tagManagerOptions.prefilled != null) {
        if (typeof (tagManagerOptions.prefilled) == "object") {
          var pta = tagManagerOptions.prefilled;
          jQuery.each(pta, function (key, val) {
            var a = 1;
            pushTag(val, obj);
          });
        } else if (typeof (tagManagerOptions.prefilled) == "string") {
          var pta = tagManagerOptions.prefilled.split(',');

          jQuery.each(pta, function (key, val) {
            var a = 1;
            pushTag(val, obj);
          });

        }
      }
    });

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


<commit_before>const nest = require('depnest')
const extend = require('xtend')

exports.gives = nest('feed.pull.profile')
exports.needs = nest('sbot.pull.userFeed', 'first')
exports.create = function (api) {
  return nest('feed.pull.profile', (id) => {
    // handle last item passed in as lt
    return function (opts) {
      opts = extend(opts, {
        id, lt: (opts.lt && typeof opts.lt === 'object') ? opts.lt.value.sequence : opts.lt
      })
      return api.sbot.pull.userFeed(opts)
    }
  })
}
<commit_msg>profile: filter out boxed messages<commit_after>const nest = require('depnest')
const extend = require('xtend')
const pull = require('pull-stream')

exports.gives = nest('feed.pull.profile')
exports.needs = nest('sbot.pull.userFeed', 'first')
exports.create = function (api) {
  return nest('feed.pull.profile', (id) => {
    // handle last item passed in as lt
    return function (opts) {
      opts = extend(opts, {
        id, lt: (opts.lt && typeof opts.lt === 'object') ? opts.lt.value.sequence : opts.lt
      })
      return pull(
        api.sbot.pull.userFeed(opts),
        pull.filter(msg => {
          return typeof msg.value.content !== 'string'
        })
      )
    }
  })
}
<|endoftext|>


<commit_before>angular.module('opApp').service('opFilterService', ['opStateService',
        function (opStateService) {
            'use strict';

            var TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss';

            /**
             * Create a WMS TIME parameter formatted filter
             * @param startTime start bounding time
             * @param stopTime stop bounding time
             * @returns {string}
             */
            this.createWmsTimeFilter = function (startTime, stopTime) {
                var startString = startTime.format(TIME_FORMAT) + 'Z';
                var stopString = stopTime.format(TIME_FORMAT) + 'Z';

                return startString + '/' + stopString;
            };

            /**
             * Create a CQL formatted temporal filter using start/stop field names and given values
             * @param startField field name to use as start bounds
             * @param stopField field name to use as stop bounds
             * @param startTime start bounding time
             * @param stopTime stop bounding time
             * @returns {*}
             */
            this.createCqlTemporalFilter = function (startField, stopField, startTime, stopTime) {
                var startString = startTime.format(TIME_FORMAT) + 'Z';
                var stopString = stopTime.format(TIME_FORMAT) + 'Z';

                var cqlFilter;
                // Use BETWEEN when start/stop time is the same
                if (startField === stopField) {
                    cqlFilter = startField + ' BETWEEN ' + startString + ' AND ' + stopString;
                }
                else {
                    cqlFilter = startField + ' >= ' + startString + ' AND ' +
                        stopField + ' <= ' + stopString;
                }

                return cqlFilter;
            };

            /**
             * Create an INTERSECTion query with a passed in WKT value and the geometry of the layer of interest
             * @param geomField name of geometry field in layer
             * @param WKT Well-Known Text of geometry to intersect against layer geometry
             * @returns {*}
             */
            this.createCqlSpatialIntersectsFilter = function (geomField, WKT) {
                var spatialFilter = null;
                if (angular.isDefined(WKT) && WKT !== null) {
                    spatialFilter = 'INTERSECTS("' + geomField + '", ' + WKT + ')';
                }

                return spatialFilter;
            };

            this.createCqlSpatialContainsFilter = function (geomField, WKT) {
                var spatialFilter = null;
                if (angular.isDefined(WKT) && WKT !== null) {
                    spatialFilter = 'CONTAINS("' + geomField + '", ' + WKT + ')';
                }

                return spatialFilter;
            };

            /**
             * Create a BBOX query filter with a passed in west,south,east,north formatted string
             * @param geomField name of geometry field in layer
             * @param westSouthEastNorthBounds string comma delimited bounds
             * @param crs optional EPSG code to be passed when constructing BBOX query
             * @returns {*}
             */
            this.createCqlSpatialBBoxFilter = function (geomField, westSouthEastNorthBounds, crs) {
                var spatialFilter = null;
                var crsOption = '';
                // If crs is specified, construct the 6th parameter.  This will be done for WFS queries.
                if (crs) {
                    crsOption = ', \'' + crs + '\'';
                }
                if (angular.isDefined(westSouthEastNorthBounds) && westSouthEastNorthBounds !== null) {
                    spatialFilter = 'BBOX("' + geomField + '",' + westSouthEastNorthBounds + crsOption + ')';
                }

                return spatialFilter;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null && angular.isDefined(layer.fields.time)) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter = null;

                if (layer.fields.geometry !== null && angular.isDefined(layer.fields.geometry)) {
                    spatialFilter =
                        this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);
                }

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsBboxFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds, crs) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter =
                    this.createCqlSpatialBBoxFilter(layer.fields.geometry.field, spatialBounds, crs);
                //this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsIntersectsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given, spatial (WKT) and temporal bounds
             * @param layer object with a required fields object
             * @param startTime
             * @param stopTime
             * @param spatialBounds
             * @returns {{cql_filter: string}}
             */
            this.createWfsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given spatial (lat/lon) and temporal bounds
             * @param layer
             * @param startTime
             * @param stopTime
             * @param spatialBounds in comma delimited west,south,east,north order
             * @param crs EPSG code to be passed when constructing BBOX query
             * @returns {{}}
             */
            this.createWfsBBoxFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds, crs) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialBBoxFilter(layer.fields.geometry.field, spatialBounds, crs);
                //this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);
                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given spatial WKT and temporal bounds
             * @param layer
             * @param startTime
             * @param stopTime
             * @param spatialBounds in WKT format
             * @returns {{}}
             */
            this.createWfsIntersectsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };
        }]);
<commit_msg>Updated date range filter to allow querying of data that doesn't start AND end within the date range specified. This lines up with search application date range filtering.<commit_after>angular.module('opApp').service('opFilterService', ['opStateService',
        function (opStateService) {
            'use strict';

            var TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss';

            /**
             * Create a WMS TIME parameter formatted filter
             * @param startTime start bounding time
             * @param stopTime stop bounding time
             * @returns {string}
             */
            this.createWmsTimeFilter = function (startTime, stopTime) {
                var startString = startTime.format(TIME_FORMAT) + 'Z';
                var stopString = stopTime.format(TIME_FORMAT) + 'Z';

                return startString + '/' + stopString;
            };

            /**
             * Create a CQL formatted temporal filter using start/stop field names and given values
             * @param startField field name to use as start bounds
             * @param stopField field name to use as stop bounds
             * @param startTime start bounding time
             * @param stopTime stop bounding time
             * @returns {*}
             */
            this.createCqlTemporalFilter = function (startField, stopField, startTime, stopTime) {
                var startString = startTime.format(TIME_FORMAT) + 'Z';
                var stopString = stopTime.format(TIME_FORMAT) + 'Z';

                var cqlFilter;
                // Use BETWEEN when start/stop time is the same
                if (startField === stopField) {
                    cqlFilter = startField + ' BETWEEN ' + startString + ' AND ' + stopString;
                }
                else {
                    cqlFilter = stopField + ' AFTER ' + startString + ' AND ' +
                        startField + ' BEFORE ' + stopString;
                }

                return cqlFilter;
            };

            /**
             * Create an INTERSECTion query with a passed in WKT value and the geometry of the layer of interest
             * @param geomField name of geometry field in layer
             * @param WKT Well-Known Text of geometry to intersect against layer geometry
             * @returns {*}
             */
            this.createCqlSpatialIntersectsFilter = function (geomField, WKT) {
                var spatialFilter = null;
                if (angular.isDefined(WKT) && WKT !== null) {
                    spatialFilter = 'INTERSECTS("' + geomField + '", ' + WKT + ')';
                }

                return spatialFilter;
            };

            this.createCqlSpatialContainsFilter = function (geomField, WKT) {
                var spatialFilter = null;
                if (angular.isDefined(WKT) && WKT !== null) {
                    spatialFilter = 'CONTAINS("' + geomField + '", ' + WKT + ')';
                }

                return spatialFilter;
            };

            /**
             * Create a BBOX query filter with a passed in west,south,east,north formatted string
             * @param geomField name of geometry field in layer
             * @param westSouthEastNorthBounds string comma delimited bounds
             * @param crs optional EPSG code to be passed when constructing BBOX query
             * @returns {*}
             */
            this.createCqlSpatialBBoxFilter = function (geomField, westSouthEastNorthBounds, crs) {
                var spatialFilter = null;
                var crsOption = '';
                // If crs is specified, construct the 6th parameter.  This will be done for WFS queries.
                if (crs) {
                    crsOption = ', \'' + crs + '\'';
                }
                if (angular.isDefined(westSouthEastNorthBounds) && westSouthEastNorthBounds !== null) {
                    spatialFilter = 'BBOX("' + geomField + '",' + westSouthEastNorthBounds + crsOption + ')';
                }

                return spatialFilter;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null && angular.isDefined(layer.fields.time)) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter = null;

                if (layer.fields.geometry !== null && angular.isDefined(layer.fields.geometry)) {
                    spatialFilter =
                        this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);
                }

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsBboxFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds, crs) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter =
                    this.createCqlSpatialBBoxFilter(layer.fields.geometry.field, spatialBounds, crs);
                //this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a parameter object that is a pure cql_filter or a combination cql/time filter based on whether the
             * layer is time-enabled or not.
             * @param layer object containing time and geometry field data for creating the filters
             * @param startTime temporal lower bound
             * @param stopTime temporal upper bound
             * @param spatialBounds WKT geometry used to enforce intersection with results
             * @returns {{}}
             */
            this.createWmsIntersectsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var response = {};
                var cqlFilters = [];

                if (layer.fields.time !== null) {
                    if (angular.isDefined(layer.fields.time.wmsTime) && layer.fields.time.wmsTime === true) {
                        response['time'] = this.createWmsTimeFilter(startTime, stopTime);
                    }
                    else {
                        cqlFilters.push(this.createCqlTemporalFilter(
                            layer.fields.time.start.field,
                            layer.fields.time.stop.field,
                            startTime, stopTime));
                    }
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given, spatial (WKT) and temporal bounds
             * @param layer object with a required fields object
             * @param startTime
             * @param stopTime
             * @param spatialBounds
             * @returns {{cql_filter: string}}
             */
            this.createWfsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given spatial (lat/lon) and temporal bounds
             * @param layer
             * @param startTime
             * @param stopTime
             * @param spatialBounds in comma delimited west,south,east,north order
             * @param crs EPSG code to be passed when constructing BBOX query
             * @returns {{}}
             */
            this.createWfsBBoxFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds, crs) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialBBoxFilter(layer.fields.geometry.field, spatialBounds, crs);
                //this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);
                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };

            /**
             * Create a cql_filter for a layer given spatial WKT and temporal bounds
             * @param layer
             * @param startTime
             * @param stopTime
             * @param spatialBounds in WKT format
             * @returns {{}}
             */
            this.createWfsIntersectsFilterRequestForLayer = function (layer, startTime, stopTime, spatialBounds) {
                var cqlFilters = [];
                var response = {};

                if (layer.fields.time !== null) {
                    cqlFilters.push(this.createCqlTemporalFilter(
                        layer.fields.time.start.field, layer.fields.time.stop.field, startTime, stopTime));
                }

                var spatialFilter =
                    this.createCqlSpatialIntersectsFilter(layer.fields.geometry.field, spatialBounds);

                if (spatialFilter !== null) {
                    cqlFilters.push(spatialFilter);
                }

                var customFilter = opStateService.getCustomFilterByLayer(layer.workspace + ':' + layer.name);

                if (customFilter !== null) {
                    cqlFilters.push(customFilter);
                }

                if (cqlFilters.length > 0) {
                    response['cql_filter'] = cqlFilters.join(' AND ');
                }

                return response;
            };
        }]);
<|endoftext|>


<commit_before>'use strict';
angular.module('copayApp.controllers').controller('bitpayCardIntroController', function($scope, $log, $state, $ionicHistory, storageService, externalLinkService, bitpayCardService, gettextCatalog, popupService) {

  var checkOtp = function(obj, cb) {
    if (obj.otp) {
      var msg = gettextCatalog.getString('Enter Two Factor for BitPay Cards');
      popupService.showPrompt(null, msg, null, function(res) {
        cb(res);
      });
    } else {
      cb();
    }
  };

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    if (data.stateParams && data.stateParams.secret) {
      var obj = {
        secret: data.stateParams.secret,
        email: data.stateParams.email,
        otp: data.stateParams.otp
      };
      checkOtp(obj, function(otp) {
        obj.otp = otp;
        bitpayCardService.bitAuthPair(obj, function(err, data) {
          if (err) {
            popupService.showAlert(null, err);
            return;
          }
          var title = gettextCatalog.getString('Add BitPay Cards?');
          var msg = gettextCatalog.getString('Would you like to add this account ({{email}}) to your wallet?', {email: obj.email});
          var ok = gettextCatalog.getString('Add cards');
          var cancel = gettextCatalog.getString('Go back');
          popupService.showConfirm(title, msg, ok, cancel, function(res) {
            if (res) {
              // Set flag for nextStep
              storageService.setNextStep('BitpayCard', true, function(err) {});
              // Save data
              bitpayCardService.setBitpayDebitCards(data, function(err) {
                if (err) return;
                $ionicHistory.nextViewOptions({
                  disableAnimate: true
                });
                $state.go('tabs.home').then(function() {
                  if (data.cards[0]) {
                    $state.transitionTo('tabs.bitpayCard', {id: data.cards[0].id});
                  }
                });
              });
            }
          });
        });
      });
    } else {
      bitpayCardService.getCredentials(function(err, credentials) {
        if (err) popupService.showAlert(null, err);
        else $log.info('BitPay Debit Card Credentials: Ok.');
      });
    }
  });

  $scope.orderBitPayCard = function() {
    var url = 'https://bitpay.com/visa/';
    var target = '_system';
    externalLinkService.open(url, target);
  };

  $scope.connectBitPayCard = function() {
    var url = 'https://bitpay.com/visa/login';
    var target = '_system';
    externalLinkService.open(url, target);
  };
});

<commit_msg>Fix open external link<commit_after>'use strict';
angular.module('copayApp.controllers').controller('bitpayCardIntroController', function($scope, $log, $state, $ionicHistory, storageService, externalLinkService, bitpayCardService, gettextCatalog, popupService) {

  var checkOtp = function(obj, cb) {
    if (obj.otp) {
      var msg = gettextCatalog.getString('Enter Two Factor for BitPay Cards');
      popupService.showPrompt(null, msg, null, function(res) {
        cb(res);
      });
    } else {
      cb();
    }
  };

  $scope.$on("$ionicView.beforeEnter", function(event, data) {

    if (data.stateParams && data.stateParams.secret) {
      var obj = {
        secret: data.stateParams.secret,
        email: data.stateParams.email,
        otp: data.stateParams.otp
      };
      checkOtp(obj, function(otp) {
        obj.otp = otp;
        bitpayCardService.bitAuthPair(obj, function(err, data) {
          if (err) {
            popupService.showAlert(null, err);
            return;
          }
          var title = gettextCatalog.getString('Add BitPay Cards?');
          var msg = gettextCatalog.getString('Would you like to add this account ({{email}}) to your wallet?', {email: obj.email});
          var ok = gettextCatalog.getString('Add cards');
          var cancel = gettextCatalog.getString('Go back');
          popupService.showConfirm(title, msg, ok, cancel, function(res) {
            if (res) {
              // Set flag for nextStep
              storageService.setNextStep('BitpayCard', true, function(err) {});
              // Save data
              bitpayCardService.setBitpayDebitCards(data, function(err) {
                if (err) return;
                $ionicHistory.nextViewOptions({
                  disableAnimate: true
                });
                $state.go('tabs.home').then(function() {
                  if (data.cards[0]) {
                    $state.transitionTo('tabs.bitpayCard', {id: data.cards[0].id});
                  }
                });
              });
            }
          });
        });
      });
    } else {
      bitpayCardService.getCredentials(function(err, credentials) {
        if (err) popupService.showAlert(null, err);
        else $log.info('BitPay Debit Card Credentials: Ok.');
      });
    }
  });

  $scope.orderBitPayCard = function() {
    var url = 'https://bitpay.com/visa/';
    externalLinkService.open(url);
  };

  $scope.connectBitPayCard = function() {
    var url = 'https://bitpay.com/visa/login';
    externalLinkService.open(url);
  };
});

<|endoftext|>


<commit_before>import escape from 'lodash.escape';
import punycode from 'punycode';

/* Browser and window tools */

export function isiOS() {
  return /iPad|iPhone|iPod/.test(navigator.userAgent);
}

export function getURL(location) {
  return location.pathname + location.search;
}

export function trigger(target, name, detail) {
  const event = detail ? new CustomEvent(name, {detail}) : new Event(name);
  target.dispatchEvent(event);
}

/* HTML */

export function bigLoader(progress=0.25) {
  return `<div class="big-loader-container">${loader(progress)}</div>`;
}

export function loader(progress=0.25) {
  const dashOffset = 565.48 * (1 - progress);
  return `
    <svg class="loader" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin">
      <circle r="90" cx="100" cy="100" fill="transparent"
              stroke-dasharray="565.48" stroke-dashoffset="0"
              style="stroke-dashoffset: ${dashOffset}px;">
      </circle>
    </svg>
  `
}

export function preventBreakingRanges(string) {
  return string.replace(/(\d[:.\d]*\s?[\-–]\s?[:.\d]*\d)/g, unbreakable('$1'));
}

export function unbreakable(string) {
  return `<span class="unbreakable">${escape(string)}</span>`;
}

/* Element manipulations */

export function clear(element) {
  element.innerHTML = '';
}

export function toggleClass(element, className, condition=undefined) {
  /* This shim is used because older Safari and IE don't support
     the second arg to classList.toggle */
  if (condition === undefined) {
    condition = element.classList.contains(className);
  }

  if (condition) {
    element.classList.add(className);
  } else {
    element.classList.remove(className);
  }
}

export function toggle(element, condition=undefined) {
  if (condition === undefined) {
    condition = element.hasAttribute('hidden');
  }

  if (condition) {
    show(element);
  } else {
    hide(element);
  }
}

export function show(element) {
  element.removeAttribute('hidden');
}

export function hide(element) {
  element.setAttribute('hidden', 'hidden');
}

/* URLs */

export function niceURL(s) {
  s = trim(s, '/');
  s = unprefix(s, 'http://');
  s = unprefix(s, 'https://');
  return punycode.toUnicode(s);
}

export function makeAbsoluteURL(url) {
  return url.startsWith('http://') ? url : 'http://theatrics.ru' + url;
}

/* Strings */

export function capfirst(s) {
  if (!s) return s;
  return s.slice(0, 1).toUpperCase() + s.slice(1);
}

export function unprefix(s, prefix) {
  return s.startsWith(prefix) ? s.slice(prefix.length) : s;
}

export function trim(s, char=' ') {
  s = trimStart(s, char);
  s = trimEnd(s, char);
  return s;
}

export function trimStart(s, char=' ') {
  while (s.startsWith(char)) s = s.slice(1);
  return s;
}

export function trimEnd(s, char=' ') {
  while (s.endsWith(char)) s = s.slice(0, -1);
  return s;
}

export function regexpEscape(s) {
  return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

export function uuid() {
  // this is not a real UUID, but we don't really need a real one
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

/* Arrays */

export function range(bound) {
  const range = [];
  for (let n = 0; n <= bound; n++) {
    range.push(n);
  }
  return range;
}

export function rotateLeft(array, n) {
  return array.slice(n).concat(array.slice(0, n));
}

export function groupArray(array, name, callback, equal=(a, b) => a == b) {
  const groups = [];
  let lastGroup = null;
  array.forEach(item => {
    const groupValue = callback(item);
    if (lastGroup && equal(lastGroup[name], groupValue)) {
      lastGroup.items.push(item);
    } else {
      lastGroup = {items: [item]};
      lastGroup[name] = groupValue;
      groups.push(lastGroup);
    }
  });
  return groups;
}

/* Objects */

export function zipIntoObject(keys, values) {
  const obj = {}
  for (let x = 0; x < values.length; x++) {
    obj[keys[x]] = values[x];
  }
  return obj;
}

export function merge(...objects) {
  return Object.assign({}, ...objects);
}

/* Formatting */

export function formatPriceRange(lower, upper, currency) {
  if (lower == null && upper == null) {
    return '—';
  } else if (lower == 0 && upper == 0){
    return 'бесплатно';
  } else if (lower == upper) {
    return formatCurrency(lower, currency);
  } else if (upper && !lower) {
    return `до ${formatCurrency(upper, currency)}`;
  } else if (!upper && lower) {
    return `от ${formatCurrency(lower, currency)}`;
  } else {
    return formatCurrency(
      `${formatNumber(lower)}–${formatNumber(upper)}`,
      currency
    );
  }
}

export function formatCurrency(value, currency, useGrouping=false) {
  const format = getCurrencyFormat(currency);
  if (typeof value == 'number') value = formatNumber(value, useGrouping);
  return format.replace('{value}', value);
}

export function getCurrencyFormat(currency) {
  const sentinel = 1234;
  const localized = sentinel.toLocaleString('ru', {
    currency,
    useGrouping: false,
    style: 'currency',
    minimumFractionDigits: 0,
  });
  return localized.replace(String(sentinel), '{value}');
}

export function formatNumber(n, useGrouping=false) {
  return n.toLocaleString('ru', {
    useGrouping,
    style: 'decimal',
    minimumFractionDigits: 0,
  });
}

export function formatPhoneNumber(number, region) {
  return number
    .replace(/\+7 (\d\d\d) (\d\d\d-\d\d-\d\d)/, '+7 ($1) $2')
    .replace(/-/g, '‒');
}

export function formatDuration(duration) {
  const days = Math.floor(duration.asDays());
  const hours = duration.hours();
  const minutes = duration.minutes();
  const parts = [];
  if (days) parts.push(pluralize.days(days));
  if (hours) parts.push(pluralize.hours(hours));
  if (minutes) parts.push(pluralize.minutes(minutes));
  return parts.join(' ');
}

export function pluralize(forms, n) {
  // this is a pluralization function for Russian language
  const form = (
    (n % 10 === 1 && n % 100 !== 11)
    ? forms[0]
    : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20))
    ? forms[1]
    : forms[2]
  );
  return `${n} ${form}`;
}

pluralize.days = n => pluralize(['день', 'дня', 'дней'], n);
pluralize.hours = n => pluralize(['час', 'часа', 'часов'], n);
pluralize.minutes = n => pluralize(['минута', 'минуты', 'минут'], n);

/* Misc */

export function getMapURL(title, address, location, isiOS) {
  if (isiOS) {
    return `//maps.apple.com/?q=${title}&address=${address}, ${location}`;
  } else {
    return `//maps.google.com/?q=${title}, ${address}, ${location}`;
  }
}
<commit_msg>Make element showing and hiding functions safe<commit_after>import escape from 'lodash.escape';
import punycode from 'punycode';

/* Browser and window tools */

export function isiOS() {
  return /iPad|iPhone|iPod/.test(navigator.userAgent);
}

export function getURL(location) {
  return location.pathname + location.search;
}

export function trigger(target, name, detail) {
  const event = detail ? new CustomEvent(name, {detail}) : new Event(name);
  target.dispatchEvent(event);
}

/* HTML */

export function bigLoader(progress=0.25) {
  return `<div class="big-loader-container">${loader(progress)}</div>`;
}

export function loader(progress=0.25) {
  const dashOffset = 565.48 * (1 - progress);
  return `
    <svg class="loader" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin">
      <circle r="90" cx="100" cy="100" fill="transparent"
              stroke-dasharray="565.48" stroke-dashoffset="0"
              style="stroke-dashoffset: ${dashOffset}px;">
      </circle>
    </svg>
  `
}

export function preventBreakingRanges(string) {
  return string.replace(/(\d[:.\d]*\s?[\-–]\s?[:.\d]*\d)/g, unbreakable('$1'));
}

export function unbreakable(string) {
  return `<span class="unbreakable">${escape(string)}</span>`;
}

/* Element manipulations */

export function clear(element) {
  element.innerHTML = '';
}

export function toggleClass(element, className, condition=undefined) {
  /* This shim is used because older Safari and IE don't support
     the second arg to classList.toggle */
  if (condition === undefined) {
    condition = element.classList.contains(className);
  }

  if (condition) {
    element.classList.add(className);
  } else {
    element.classList.remove(className);
  }
}

export function toggle(element, condition=undefined) {
  if (condition === undefined) {
    condition = element.hasAttribute('hidden');
  }

  if (condition) {
    show(element);
  } else {
    hide(element);
  }
}

export function show(element) {
  element && element.removeAttribute('hidden');
}

export function hide(element) {
  element && element.setAttribute('hidden', 'hidden');
}

/* URLs */

export function niceURL(s) {
  s = trim(s, '/');
  s = unprefix(s, 'http://');
  s = unprefix(s, 'https://');
  return punycode.toUnicode(s);
}

export function makeAbsoluteURL(url) {
  return url.startsWith('http://') ? url : 'http://theatrics.ru' + url;
}

/* Strings */

export function capfirst(s) {
  if (!s) return s;
  return s.slice(0, 1).toUpperCase() + s.slice(1);
}

export function unprefix(s, prefix) {
  return s.startsWith(prefix) ? s.slice(prefix.length) : s;
}

export function trim(s, char=' ') {
  s = trimStart(s, char);
  s = trimEnd(s, char);
  return s;
}

export function trimStart(s, char=' ') {
  while (s.startsWith(char)) s = s.slice(1);
  return s;
}

export function trimEnd(s, char=' ') {
  while (s.endsWith(char)) s = s.slice(0, -1);
  return s;
}

export function regexpEscape(s) {
  return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

export function uuid() {
  // this is not a real UUID, but we don't really need a real one
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

/* Arrays */

export function range(bound) {
  const range = [];
  for (let n = 0; n <= bound; n++) {
    range.push(n);
  }
  return range;
}

export function rotateLeft(array, n) {
  return array.slice(n).concat(array.slice(0, n));
}

export function groupArray(array, name, callback, equal=(a, b) => a == b) {
  const groups = [];
  let lastGroup = null;
  array.forEach(item => {
    const groupValue = callback(item);
    if (lastGroup && equal(lastGroup[name], groupValue)) {
      lastGroup.items.push(item);
    } else {
      lastGroup = {items: [item]};
      lastGroup[name] = groupValue;
      groups.push(lastGroup);
    }
  });
  return groups;
}

/* Objects */

export function zipIntoObject(keys, values) {
  const obj = {}
  for (let x = 0; x < values.length; x++) {
    obj[keys[x]] = values[x];
  }
  return obj;
}

export function merge(...objects) {
  return Object.assign({}, ...objects);
}

/* Formatting */

export function formatPriceRange(lower, upper, currency) {
  if (lower == null && upper == null) {
    return '—';
  } else if (lower == 0 && upper == 0){
    return 'бесплатно';
  } else if (lower == upper) {
    return formatCurrency(lower, currency);
  } else if (upper && !lower) {
    return `до ${formatCurrency(upper, currency)}`;
  } else if (!upper && lower) {
    return `от ${formatCurrency(lower, currency)}`;
  } else {
    return formatCurrency(
      `${formatNumber(lower)}–${formatNumber(upper)}`,
      currency
    );
  }
}

export function formatCurrency(value, currency, useGrouping=false) {
  const format = getCurrencyFormat(currency);
  if (typeof value == 'number') value = formatNumber(value, useGrouping);
  return format.replace('{value}', value);
}

export function getCurrencyFormat(currency) {
  const sentinel = 1234;
  const localized = sentinel.toLocaleString('ru', {
    currency,
    useGrouping: false,
    style: 'currency',
    minimumFractionDigits: 0,
  });
  return localized.replace(String(sentinel), '{value}');
}

export function formatNumber(n, useGrouping=false) {
  return n.toLocaleString('ru', {
    useGrouping,
    style: 'decimal',
    minimumFractionDigits: 0,
  });
}

export function formatPhoneNumber(number, region) {
  return number
    .replace(/\+7 (\d\d\d) (\d\d\d-\d\d-\d\d)/, '+7 ($1) $2')
    .replace(/-/g, '‒');
}

export function formatDuration(duration) {
  const days = Math.floor(duration.asDays());
  const hours = duration.hours();
  const minutes = duration.minutes();
  const parts = [];
  if (days) parts.push(pluralize.days(days));
  if (hours) parts.push(pluralize.hours(hours));
  if (minutes) parts.push(pluralize.minutes(minutes));
  return parts.join(' ');
}

export function pluralize(forms, n) {
  // this is a pluralization function for Russian language
  const form = (
    (n % 10 === 1 && n % 100 !== 11)
    ? forms[0]
    : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20))
    ? forms[1]
    : forms[2]
  );
  return `${n} ${form}`;
}

pluralize.days = n => pluralize(['день', 'дня', 'дней'], n);
pluralize.hours = n => pluralize(['час', 'часа', 'часов'], n);
pluralize.minutes = n => pluralize(['минута', 'минуты', 'минут'], n);

/* Misc */

export function getMapURL(title, address, location, isiOS) {
  if (isiOS) {
    return `//maps.apple.com/?q=${title}&address=${address}, ${location}`;
  } else {
    return `//maps.google.com/?q=${title}, ${address}, ${location}`;
  }
}
<|endoftext|>