<commit_before>/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the 2-clause BSD license.
 * See license.txt in the OpenLayers distribution or repository for the
 * full text of the license. */

/**
 * @requires OpenLayers/Format.js
 * @requires OpenLayers/Feature/Vector.js
 * @requires OpenLayers/Geometry/Point.js
 * @requires OpenLayers/Geometry/MultiPoint.js
 * @requires OpenLayers/Geometry/LineString.js
 * @requires OpenLayers/Geometry/MultiLineString.js
 * @requires OpenLayers/Geometry/Polygon.js
 * @requires OpenLayers/Geometry/MultiPolygon.js
 */

/**
 * Class: OpenLayers.Format.WKT
 * Class for reading and writing Well-Known Text.  Create a new instance
 * with the <OpenLayers.Format.WKT> constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Format>
 */
OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {

    /**
     * Constructor: OpenLayers.Format.WKT
     * Create a new parser for WKT
     *
     * Parameters:
     * options - {Object} An optional object whose properties will be set on
     *           this instance
     *
     * Returns:
     * {<OpenLayers.Format.WKT>} A new WKT parser.
     */
    initialize: function(options) {
        this.regExes = {
            'typeStr': /^\s*(\w+)\s*(\w+)?\s*\(\s*(.*)\s*\)\s*$/,
            'spaces': /\s+/,
            'parenComma': /\)\s*,\s*\(/,
            'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,  // can't use {2} here
            'trimParens': /^\s*\(?(.*?)\)?\s*$/
        };
        OpenLayers.Format.prototype.initialize.apply(this, [options]);
    },

    /**
     * APIMethod: read
     * Deserialize a WKT string and return a vector feature or an
     * array of vector features.  Supports WKT for POINT, MULTIPOINT,
     * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
     * GEOMETRYCOLLECTION.
     *
     * Parameters:
     * wkt - {String} A WKT string
     *
     * Returns:
     * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
     * GEOMETRYCOLLECTION WKT.
     */
    read: function(wkt) {
        var features, type, dim, str;
        wkt = wkt.replace(/[\n\r]/g, " ");
        var matches = this.regExes.typeStr.exec(wkt);
        if(matches) {
            type = matches[1].toLowerCase();
            dim = matches[2];
            str = matches[3];
            if(this.parse[type]) {
                features = this.parse[type].apply(this, [str]);
            }
            if (this.internalProjection && this.externalProjection) {
                if (features &&
                    features.CLASS_NAME == "OpenLayers.Feature.Vector") {
                    features.geometry.transform(this.externalProjection,
                                                this.internalProjection);
                } else if (features &&
                           type != "geometrycollection" &&
                           typeof features == "object") {
                    for (var i=0, len=features.length; i<len; i++) {
                        var component = features[i];
                        component.geometry.transform(this.externalProjection,
                                                     this.internalProjection);
                    }
                }
            }
        }
        return features;
    },

    /**
     * APIMethod: write
     * Serialize a feature or array of features into a WKT string.
     *
     * Parameters:
     * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
     *            features
     *
     * Returns:
     * {String} The WKT string representation of the input geometries
     */
    write: function(features) {
        var collection, geometry, isCollection;
        if (features.constructor == Array) {
            collection = features;
            isCollection = true;
        } else {
            collection = [features];
            isCollection = false;
        }
        var pieces = [];
        if (isCollection) {
            pieces.push('GEOMETRYCOLLECTION(');
        }
        for (var i=0, len=collection.length; i<len; ++i) {
            if (isCollection && i>0) {
                pieces.push(',');
            }
            geometry = collection[i].geometry;
            pieces.push(this.extractGeometry(geometry));
        }
        if (isCollection) {
            pieces.push(')');
        }
        return pieces.join('');
    },

    /**
     * Method: extractGeometry
     * Entry point to construct the WKT for a single Geometry object.
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry.Geometry>}
     *
     * Returns:
     * {String} A WKT string of representing the geometry
     */
    extractGeometry: function(geometry) {
        var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
        if (!this.extract[type]) {
            return null;
        }
        if (this.internalProjection && this.externalProjection) {
            geometry = geometry.clone();
            geometry.transform(this.internalProjection, this.externalProjection);
        }
        var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
        var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
        return data;
    },

    /**
     * Object with properties corresponding to the geometry types.
     * Property values are functions that do the actual data extraction.
     */
    extract: {
        /**
         * Return a space delimited string of point coordinates.
         * @param {OpenLayers.Geometry.Point} point
         * @returns {String} A string of coordinates representing the point
         */
        'point': function(point) {
            return point.x + ' ' + point.y;
        },

        /**
         * Return a comma delimited string of point coordinates from a multipoint.
         * @param {OpenLayers.Geometry.MultiPoint} multipoint
         * @returns {String} A string of point coordinate strings representing
         *                  the multipoint
         */
        'multipoint': function(multipoint) {
            var array = [];
            for(var i=0, len=multipoint.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.point.apply(this, [multipoint.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of point coordinates from a line.
         * @param {OpenLayers.Geometry.LineString} linestring
         * @returns {String} A string of point coordinate strings representing
         *                  the linestring
         */
        'linestring': function(linestring) {
            var array = [];
            for(var i=0, len=linestring.components.length; i<len; ++i) {
                array.push(this.extract.point.apply(this, [linestring.components[i]]));
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of linestring strings from a multilinestring.
         * @param {OpenLayers.Geometry.MultiLineString} multilinestring
         * @returns {String} A string of of linestring strings representing
         *                  the multilinestring
         */
        'multilinestring': function(multilinestring) {
            var array = [];
            for(var i=0, len=multilinestring.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.linestring.apply(this, [multilinestring.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of linear ring arrays from a polygon.
         * @param {OpenLayers.Geometry.Polygon} polygon
         * @returns {String} An array of linear ring arrays representing the polygon
         */
        'polygon': function(polygon) {
            var array = [];
            for(var i=0, len=polygon.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.linestring.apply(this, [polygon.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return an array of polygon arrays from a multipolygon.
         * @param {OpenLayers.Geometry.MultiPolygon} multipolygon
         * @returns {String} An array of polygon arrays representing
         *                  the multipolygon
         */
        'multipolygon': function(multipolygon) {
            var array = [];
            for(var i=0, len=multipolygon.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.polygon.apply(this, [multipolygon.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an <OpenLayers.Geometry.Collection>
         * @param {OpenLayers.Geometry.Collection} collection
         * @returns {String} internal WKT representation of the collection
         */
        'collection': function(collection) {
            var array = [];
            for(var i=0, len=collection.components.length; i<len; ++i) {
                array.push(this.extractGeometry.apply(this, [collection.components[i]]));
            }
            return array.join(',');
        }

    },

    /**
     * Object with properties corresponding to the geometry types.
     * Property values are functions that do the actual parsing.
     */
    parse: {
        /**
         * Return point feature given a point WKT fragment.
         * @param {String} str A WKT fragment representing the point
         * @returns {OpenLayers.Feature.Vector} A point feature
         * @private
         */
        'point': function(str) {
            var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.Point(coords[0], coords[1])
            );
        },

        /**
         * Return a multipoint feature given a multipoint WKT fragment.
         * @param {String} str A WKT fragment representing the multipoint
         * @returns {OpenLayers.Feature.Vector} A multipoint feature
         * @private
         */
        'multipoint': function(str) {
            var point;
            var points = OpenLayers.String.trim(str).split(',');
            var components = [];
            for(var i=0, len=points.length; i<len; ++i) {
                point = points[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.point.apply(this, [point]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiPoint(components)
            );
        },

        /**
         * Return a linestring feature given a linestring WKT fragment.
         * @param {String} str A WKT fragment representing the linestring
         * @returns {OpenLayers.Feature.Vector} A linestring feature
         * @private
         */
        'linestring': function(str) {
            var points = OpenLayers.String.trim(str).split(',');
            var components = [];
            for(var i=0, len=points.length; i<len; ++i) {
                components.push(this.parse.point.apply(this, [points[i]]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.LineString(components)
            );
        },

        /**
         * Return a multilinestring feature given a multilinestring WKT fragment.
         * @param {String} str A WKT fragment representing the multilinestring
         * @returns {OpenLayers.Feature.Vector} A multilinestring feature
         * @private
         */
        'multilinestring': function(str) {
            var line;
            var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
            var components = [];
            for(var i=0, len=lines.length; i<len; ++i) {
                line = lines[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.linestring.apply(this, [line]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiLineString(components)
            );
        },

        /**
         * Return a polygon feature given a polygon WKT fragment.
         * @param {String} str A WKT fragment representing the polygon
         * @returns {OpenLayers.Feature.Vector} A polygon feature
         * @private
         */
        'polygon': function(str) {
            var ring, linestring, linearring;
            var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
            var components = [];
            for(var i=0, len=rings.length; i<len; ++i) {
                ring = rings[i].replace(this.regExes.trimParens, '$1');
                linestring = this.parse.linestring.apply(this, [ring]).geometry;
                linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
                components.push(linearring);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.Polygon(components)
            );
        },

        /**
         * Return a multipolygon feature given a multipolygon WKT fragment.
         * @param {String} str A WKT fragment representing the multipolygon
         * @returns {OpenLayers.Feature.Vector} A multipolygon feature
         * @private
         */
        'multipolygon': function(str) {
            var polygon;
            var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
            var components = [];
            for(var i=0, len=polygons.length; i<len; ++i) {
                polygon = polygons[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.polygon.apply(this, [polygon]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiPolygon(components)
            );
        },

        /**
         * Return an array of features given a geometrycollection WKT fragment.
         * @param {String} str A WKT fragment representing the geometrycollection
         * @returns {Array} An array of OpenLayers.Feature.Vector
         * @private
         */
        'geometrycollection': function(str) {
            // separate components of the collection with |
            str = str.replace(/,\s*([A-Za-z])/g, '|$1');
            var wktArray = OpenLayers.String.trim(str).split('|');
            var components = [];
            for(var i=0, len=wktArray.length; i<len; ++i) {
                components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
            }
            return components;
        }

    },

    CLASS_NAME: "OpenLayers.Format.WKT"
});
<commit_msg>[BUGFIX] WKT parsed geometry with Z, M or ZM pasted to type<commit_after>/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the 2-clause BSD license.
 * See license.txt in the OpenLayers distribution or repository for the
 * full text of the license. */

/**
 * @requires OpenLayers/Format.js
 * @requires OpenLayers/Feature/Vector.js
 * @requires OpenLayers/Geometry/Point.js
 * @requires OpenLayers/Geometry/MultiPoint.js
 * @requires OpenLayers/Geometry/LineString.js
 * @requires OpenLayers/Geometry/MultiLineString.js
 * @requires OpenLayers/Geometry/Polygon.js
 * @requires OpenLayers/Geometry/MultiPolygon.js
 */

/**
 * Class: OpenLayers.Format.WKT
 * Class for reading and writing Well-Known Text.  Create a new instance
 * with the <OpenLayers.Format.WKT> constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Format>
 */
OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {

    /**
     * Constructor: OpenLayers.Format.WKT
     * Create a new parser for WKT
     *
     * Parameters:
     * options - {Object} An optional object whose properties will be set on
     *           this instance
     *
     * Returns:
     * {<OpenLayers.Format.WKT>} A new WKT parser.
     */
    initialize: function(options) {
        this.regExes = {
            'typeStr': /^\s*(\w+)\s*(\w+)?\s*\(\s*(.*)\s*\)\s*$/,
            'spaces': /\s+/,
            'parenComma': /\)\s*,\s*\(/,
            'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,  // can't use {2} here
            'trimParens': /^\s*\(?(.*?)\)?\s*$/
        };
        OpenLayers.Format.prototype.initialize.apply(this, [options]);
    },

    /**
     * APIMethod: read
     * Deserialize a WKT string and return a vector feature or an
     * array of vector features.  Supports WKT for POINT, MULTIPOINT,
     * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
     * GEOMETRYCOLLECTION.
     *
     * Parameters:
     * wkt - {String} A WKT string
     *
     * Returns:
     * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
     * GEOMETRYCOLLECTION WKT.
     */
    read: function(wkt) {
        var features, type, dim, str;
        wkt = wkt.replace(/[\n\r]/g, " ");
        var matches = this.regExes.typeStr.exec(wkt);
        if(matches) {
            type = matches[1].toLowerCase();
            dim = matches[2];
            str = matches[3];
            if (type.endsWith('zm')) {
                dim = type.substring(type.length-2)
                type = type.substring(0, type.length-2)
            } else if (type.endsWith('mz')) {
                dim = type.substring(type.length-2)
                type = type.substring(0, type.length-2)
            } else if (type.endsWith('z')) {
                dim = type.substring(type.length-1)
                type = type.substring(0, type.length-1)
            } else if (type.endsWith('m')) {
                dim = type.substring(type.length-1)
                type = type.substring(0, type.length-1)
            }
            if(this.parse[type]) {
                features = this.parse[type].apply(this, [str]);
            }
            if (this.internalProjection && this.externalProjection) {
                if (features &&
                    features.CLASS_NAME == "OpenLayers.Feature.Vector") {
                    features.geometry.transform(this.externalProjection,
                                                this.internalProjection);
                } else if (features &&
                           type != "geometrycollection" &&
                           typeof features == "object") {
                    for (var i=0, len=features.length; i<len; i++) {
                        var component = features[i];
                        component.geometry.transform(this.externalProjection,
                                                     this.internalProjection);
                    }
                }
            }
        }
        return features;
    },

    /**
     * APIMethod: write
     * Serialize a feature or array of features into a WKT string.
     *
     * Parameters:
     * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
     *            features
     *
     * Returns:
     * {String} The WKT string representation of the input geometries
     */
    write: function(features) {
        var collection, geometry, isCollection;
        if (features.constructor == Array) {
            collection = features;
            isCollection = true;
        } else {
            collection = [features];
            isCollection = false;
        }
        var pieces = [];
        if (isCollection) {
            pieces.push('GEOMETRYCOLLECTION(');
        }
        for (var i=0, len=collection.length; i<len; ++i) {
            if (isCollection && i>0) {
                pieces.push(',');
            }
            geometry = collection[i].geometry;
            pieces.push(this.extractGeometry(geometry));
        }
        if (isCollection) {
            pieces.push(')');
        }
        return pieces.join('');
    },

    /**
     * Method: extractGeometry
     * Entry point to construct the WKT for a single Geometry object.
     *
     * Parameters:
     * geometry - {<OpenLayers.Geometry.Geometry>}
     *
     * Returns:
     * {String} A WKT string of representing the geometry
     */
    extractGeometry: function(geometry) {
        var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
        if (!this.extract[type]) {
            return null;
        }
        if (this.internalProjection && this.externalProjection) {
            geometry = geometry.clone();
            geometry.transform(this.internalProjection, this.externalProjection);
        }
        var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
        var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
        return data;
    },

    /**
     * Object with properties corresponding to the geometry types.
     * Property values are functions that do the actual data extraction.
     */
    extract: {
        /**
         * Return a space delimited string of point coordinates.
         * @param {OpenLayers.Geometry.Point} point
         * @returns {String} A string of coordinates representing the point
         */
        'point': function(point) {
            return point.x + ' ' + point.y;
        },

        /**
         * Return a comma delimited string of point coordinates from a multipoint.
         * @param {OpenLayers.Geometry.MultiPoint} multipoint
         * @returns {String} A string of point coordinate strings representing
         *                  the multipoint
         */
        'multipoint': function(multipoint) {
            var array = [];
            for(var i=0, len=multipoint.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.point.apply(this, [multipoint.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of point coordinates from a line.
         * @param {OpenLayers.Geometry.LineString} linestring
         * @returns {String} A string of point coordinate strings representing
         *                  the linestring
         */
        'linestring': function(linestring) {
            var array = [];
            for(var i=0, len=linestring.components.length; i<len; ++i) {
                array.push(this.extract.point.apply(this, [linestring.components[i]]));
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of linestring strings from a multilinestring.
         * @param {OpenLayers.Geometry.MultiLineString} multilinestring
         * @returns {String} A string of of linestring strings representing
         *                  the multilinestring
         */
        'multilinestring': function(multilinestring) {
            var array = [];
            for(var i=0, len=multilinestring.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.linestring.apply(this, [multilinestring.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return a comma delimited string of linear ring arrays from a polygon.
         * @param {OpenLayers.Geometry.Polygon} polygon
         * @returns {String} An array of linear ring arrays representing the polygon
         */
        'polygon': function(polygon) {
            var array = [];
            for(var i=0, len=polygon.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.linestring.apply(this, [polygon.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return an array of polygon arrays from a multipolygon.
         * @param {OpenLayers.Geometry.MultiPolygon} multipolygon
         * @returns {String} An array of polygon arrays representing
         *                  the multipolygon
         */
        'multipolygon': function(multipolygon) {
            var array = [];
            for(var i=0, len=multipolygon.components.length; i<len; ++i) {
                array.push('(' +
                           this.extract.polygon.apply(this, [multipolygon.components[i]]) +
                           ')');
            }
            return array.join(',');
        },

        /**
         * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an <OpenLayers.Geometry.Collection>
         * @param {OpenLayers.Geometry.Collection} collection
         * @returns {String} internal WKT representation of the collection
         */
        'collection': function(collection) {
            var array = [];
            for(var i=0, len=collection.components.length; i<len; ++i) {
                array.push(this.extractGeometry.apply(this, [collection.components[i]]));
            }
            return array.join(',');
        }

    },

    /**
     * Object with properties corresponding to the geometry types.
     * Property values are functions that do the actual parsing.
     */
    parse: {
        /**
         * Return point feature given a point WKT fragment.
         * @param {String} str A WKT fragment representing the point
         * @returns {OpenLayers.Feature.Vector} A point feature
         * @private
         */
        'point': function(str) {
            var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.Point(coords[0], coords[1])
            );
        },

        /**
         * Return a multipoint feature given a multipoint WKT fragment.
         * @param {String} str A WKT fragment representing the multipoint
         * @returns {OpenLayers.Feature.Vector} A multipoint feature
         * @private
         */
        'multipoint': function(str) {
            var point;
            var points = OpenLayers.String.trim(str).split(',');
            var components = [];
            for(var i=0, len=points.length; i<len; ++i) {
                point = points[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.point.apply(this, [point]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiPoint(components)
            );
        },

        /**
         * Return a linestring feature given a linestring WKT fragment.
         * @param {String} str A WKT fragment representing the linestring
         * @returns {OpenLayers.Feature.Vector} A linestring feature
         * @private
         */
        'linestring': function(str) {
            var points = OpenLayers.String.trim(str).split(',');
            var components = [];
            for(var i=0, len=points.length; i<len; ++i) {
                components.push(this.parse.point.apply(this, [points[i]]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.LineString(components)
            );
        },

        /**
         * Return a multilinestring feature given a multilinestring WKT fragment.
         * @param {String} str A WKT fragment representing the multilinestring
         * @returns {OpenLayers.Feature.Vector} A multilinestring feature
         * @private
         */
        'multilinestring': function(str) {
            var line;
            var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
            var components = [];
            for(var i=0, len=lines.length; i<len; ++i) {
                line = lines[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.linestring.apply(this, [line]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiLineString(components)
            );
        },

        /**
         * Return a polygon feature given a polygon WKT fragment.
         * @param {String} str A WKT fragment representing the polygon
         * @returns {OpenLayers.Feature.Vector} A polygon feature
         * @private
         */
        'polygon': function(str) {
            var ring, linestring, linearring;
            var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
            var components = [];
            for(var i=0, len=rings.length; i<len; ++i) {
                ring = rings[i].replace(this.regExes.trimParens, '$1');
                linestring = this.parse.linestring.apply(this, [ring]).geometry;
                linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
                components.push(linearring);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.Polygon(components)
            );
        },

        /**
         * Return a multipolygon feature given a multipolygon WKT fragment.
         * @param {String} str A WKT fragment representing the multipolygon
         * @returns {OpenLayers.Feature.Vector} A multipolygon feature
         * @private
         */
        'multipolygon': function(str) {
            var polygon;
            var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
            var components = [];
            for(var i=0, len=polygons.length; i<len; ++i) {
                polygon = polygons[i].replace(this.regExes.trimParens, '$1');
                components.push(this.parse.polygon.apply(this, [polygon]).geometry);
            }
            return new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.MultiPolygon(components)
            );
        },

        /**
         * Return an array of features given a geometrycollection WKT fragment.
         * @param {String} str A WKT fragment representing the geometrycollection
         * @returns {Array} An array of OpenLayers.Feature.Vector
         * @private
         */
        'geometrycollection': function(str) {
            // separate components of the collection with |
            str = str.replace(/,\s*([A-Za-z])/g, '|$1');
            var wktArray = OpenLayers.String.trim(str).split('|');
            var components = [];
            for(var i=0, len=wktArray.length; i<len; ++i) {
                components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
            }
            return components;
        }

    },

    CLASS_NAME: "OpenLayers.Format.WKT"
});
<|endoftext|>


<commit_before>"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 *
 */
var Options;
(function (Options) {
    /**
     *
     */
    var QueueMode;
    (function (QueueMode) {
        QueueMode[QueueMode["SALVO"] = 1] = "SALVO";
        QueueMode[QueueMode["SEQUENTIAL"] = 2] = "SEQUENTIAL";
        // SMART 		= 3
    })(QueueMode = Options.QueueMode || (Options.QueueMode = {}));
    /**
     *
     */
    var CasparCGVersion;
    (function (CasparCGVersion) {
        CasparCGVersion[CasparCGVersion["V2xx"] = 2000] = "V2xx";
        CasparCGVersion[CasparCGVersion["V207"] = 2007] = "V207";
        CasparCGVersion[CasparCGVersion["V21x"] = 2100] = "V21x";
        CasparCGVersion[CasparCGVersion["V210"] = 2110] = "V210";
    })(CasparCGVersion = Options.CasparCGVersion || (Options.CasparCGVersion = {}));
})(Options = exports.Options || (exports.Options = {}));
/**
 *
 */
var ConnectionOptions = /** @class */ (function () {
    function ConnectionOptions(hostOrOptions, port) {
        this.host = 'localhost';
        this.port = 5250;
        this.autoConnect = true;
        this.autoReconnect = true;
        this.autoReconnectInterval = 1000;
        this.autoReconnectAttempts = Infinity;
        this.serverVersion = undefined;
        this.queueMode = Options.QueueMode.SALVO;
        this.virginServerCheck = false;
        this.debug = false;
        this.onLog = undefined;
        this.onConnectionStatus = undefined;
        this.onConnectionChanged = undefined;
        this.onConnected = undefined;
        this.onDisconnected = undefined;
        this.onError = undefined;
        // if object
        if (hostOrOptions && typeof hostOrOptions === 'object') {
            if (hostOrOptions.hasOwnProperty('host') && hostOrOptions.host !== undefined) {
                var host = hostOrOptions.host;
                var dnsValidation = /((?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?)(?:\:([0-9]{4}))?/.exec(host);
                if (dnsValidation) {
                    delete hostOrOptions['host'];
                    // host
                    if (dnsValidation[1]) {
                        this.host = dnsValidation[1];
                    }
                    // port
                    if (dnsValidation[2]) {
                        this.port = parseInt(dnsValidation[2], 10);
                    }
                }
            }
            // @todo: object assign
            for (var key in hostOrOptions) {
                if (!hostOrOptions.hasOwnProperty(key)) {
                    continue;
                }
                if (this.hasOwnProperty(key)) {
                    this[key] = hostOrOptions[key];
                }
            }
            return;
        }
        // else
        if (typeof hostOrOptions === 'string') {
            var dnsValidation = /((?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?)(?:\:([0-9]{4}))?/.exec(hostOrOptions.toString());
            if (dnsValidation) {
                // host
                if (dnsValidation[1]) {
                    this.host = dnsValidation[1];
                }
                // port
                if (dnsValidation[2]) {
                    this.port = parseInt(dnsValidation[2], 10);
                }
            }
            if (port) {
                this.port = port;
            }
        }
    }
    return ConnectionOptions;
}());
exports.ConnectionOptions = ConnectionOptions;
<commit_msg>build(JS): Build for release<commit_after>"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 *
 */
var Options;
(function (Options) {
    /**
     *
     */
    var QueueMode;
    (function (QueueMode) {
        QueueMode[QueueMode["SALVO"] = 1] = "SALVO";
        QueueMode[QueueMode["SEQUENTIAL"] = 2] = "SEQUENTIAL";
        // SMART 		= 3
    })(QueueMode = Options.QueueMode || (Options.QueueMode = {}));
    /**
     *
     */
    var CasparCGVersion;
    (function (CasparCGVersion) {
        CasparCGVersion[CasparCGVersion["V2xx"] = 2000] = "V2xx";
        CasparCGVersion[CasparCGVersion["V207"] = 2007] = "V207";
        CasparCGVersion[CasparCGVersion["V21x"] = 2100] = "V21x";
        CasparCGVersion[CasparCGVersion["V210"] = 2110] = "V210";
    })(CasparCGVersion = Options.CasparCGVersion || (Options.CasparCGVersion = {}));
})(Options = exports.Options || (exports.Options = {}));
/**
 *
 */
var ConnectionOptions = /** @class */ (function () {
    function ConnectionOptions(hostOrOptions, port) {
        this.host = 'localhost';
        this.port = 5250;
        this.autoConnect = true;
        this.autoReconnect = true;
        this.autoReconnectInterval = 1000;
        this.autoReconnectAttempts = Infinity;
        this.serverVersion = undefined;
        this.queueMode = Options.QueueMode.SALVO;
        this.virginServerCheck = false;
        this.debug = false;
        this.onLog = undefined;
        this.onConnectionStatus = undefined;
        this.onConnectionChanged = undefined;
        this.onConnected = undefined;
        this.onDisconnected = undefined;
        this.onError = undefined;
        // if object
        var hasSetHostOrPort = false;
        if (hostOrOptions && typeof hostOrOptions === 'object') {
            if (hostOrOptions.hasOwnProperty('host') && hostOrOptions.host !== undefined) {
                var host = hostOrOptions.host;
                var dnsValidation = /((?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?)(?:\:([0-9]{4}))?/.exec(host);
                if (dnsValidation) {
                    // host
                    if (dnsValidation[1]) {
                        // port gets set directly, and we need to ignore it in the loop setting all other options
                        hasSetHostOrPort = true;
                        this.host = dnsValidation[1];
                    }
                    // port
                    if (dnsValidation[2]) {
                        // port gets set directly, and we need to ignore it in the loop setting all other options
                        hasSetHostOrPort = true;
                        this.port = parseInt(dnsValidation[2], 10);
                    }
                }
            }
            // @todo: object assign
            for (var key in hostOrOptions) {
                // host or port has been set directly and should not be overridden again
                if (hasSetHostOrPort && (key === 'host' || key === 'port')) {
                    continue;
                }
                if (!hostOrOptions.hasOwnProperty(key)) {
                    continue;
                }
                if (this.hasOwnProperty(key)) {
                    this[key] = hostOrOptions[key];
                }
            }
            return;
        }
        // else
        if (typeof hostOrOptions === 'string') {
            var dnsValidation = /((?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?)(?:\:([0-9]{4}))?/.exec(hostOrOptions.toString());
            if (dnsValidation) {
                // host
                if (dnsValidation[1]) {
                    this.host = dnsValidation[1];
                }
                // port
                if (dnsValidation[2]) {
                    this.port = parseInt(dnsValidation[2], 10);
                }
            }
            if (port) {
                this.port = port;
            }
        }
    }
    return ConnectionOptions;
}());
exports.ConnectionOptions = ConnectionOptions;
<|endoftext|>


<commit_before>angular.module('ui.cg.numberinput', [])

.constant('numberinputConfig', {
    decimalSeparator: '.',
    decimals: 2,
    step: 1,
    keyboard: true,
    mousewheel: true,
    spinner: true
})

.controller('NumberInputController', ['$scope', '$attrs', 'numberinputConfig', function ($scope, $attrs, numberinputConfig) {
    var HOT_KEYS = [38, 40];

    this.init = function (element) {
        var input = element.find('input').eq(0);

        var keyboard = angular.isDefined($attrs.keyboard) ? $scope.$eval($attrs.keyboard) : numberinputConfig.keyboard;
        if (keyboard) {
            this.bindKeyboardEvents(input);
        }

        var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$eval($attrs.mousewheel) : numberinputConfig.mousewheel;
        if (mousewheel) {
            this.bindMouseWheelEvents(input);
        }
    };

    function stepIt(step) {
        if ($scope.disabled === true) {
            return;
        }

        var modelValue = $scope.number;
        if (isNaN(modelValue)) {
            modelValue = 0;
        }

        var multiplier = decimals === 0 ? 1 : parseInt('1' + Array(decimals + 1).join("0"), 10);
        var modelValue = Math.round((modelValue + step) * multiplier) / multiplier;

        $scope.number = modelValue;

        checkValueBoundaries();
    }

    $scope.increment = function () {
        var step = getStep();
        stepIt(step);
    }

    $scope.decrement = function () {
        var step = getStep();
        stepIt(step * -1);
    }

    this.bindMouseWheelEvents = function(input) {
        var isScrollingUp = function (e) {
            if (e.originalEvent) {
                e = e.originalEvent;
            }

            var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;

            return (e.detail || delta > 0);
        };

        input.bind('mousewheel wheel', function (e) {
            $scope.$apply(isScrollingUp(e) ? $scope.increment() : $scope.decrement());
            e.preventDefault();
        });
    }

    this.bindKeyboardEvents = function(input) {
        input.bind('keydown', function (e) {
            if (HOT_KEYS.indexOf(e.which) === -1) {
                return;
            }

            e.stopPropagation();

            if (e.which === 40) {
                $scope.decrement();
            } else if (e.which === 38) {
                $scope.increment();
            }

            $scope.$apply();
        });
    };

    this.getDecimalSeparator = function () {
        return decimalSeparator;
    }

    var decimalSeparator = numberinputConfig.decimalSeparator;
    if ($attrs.decimalSeparator) {
        $attrs.$observe('decimalSeparator', function (value) {
            var parsed;
            if (!angular.isDefined(value) || value.length === 0) {
                parsed = numberinputConfig.decimalSeparator;
            } else {
                parsed = value[0];
            }

            decimalSeparator = parsed;
        })
    }

    this.getDecimals = function () {
        return decimals;
    }

    var decimals = numberinputConfig.decimals;
    if ($attrs.decimals) {
        $attrs.$observe('decimals', function (value) {
            var parsed;
            if (angular.isUndefined(value) || isNaN(value)) {
                parsed = numberinputConfig.decimals;
            } else {
                parsed = parseInt(value, 10);
            }

            if (parsed < 0) {
                parsed = 0;
            }

            decimals = parsed;
        });
    }

    function getStep() {
        var corrected = step;
        var minimumStep = decimals === 0 ? 1 : parseFloat('0.' + Array(decimals).join("0") + "1", 10);
        if (corrected < minimumStep) {
            corrected = minimumStep;
        }

        return corrected;
    }

    var step = numberinputConfig.step;
    if ($attrs.step) {
        $attrs.$observe('step', function (value) {
            var parsed;
            if (angular.isUndefined(value) || isNaN(value)) {
                parsed = numberinputConfig.step;
            } else {
                parsed = parseFloat(value, 10);
            }

            step = parsed;
        });
    }

    $scope.spinner = numberinputConfig.spinner;
    if ($attrs.spinner) {
        $attrs.$observe('spinner', function (value) {
            $scope.spinner = angular.isDefined(value) ? $scope.$eval(value) : true;
        });
    }

    if ($attrs.maximum) {
        $attrs.$observe('maximum', function (value) {
            $scope.maximum = parseFloat(value, 10);
        });
    }

    if ($attrs.minimum) {
        $attrs.$observe('minimum', function (value) {
            $scope.minimum = parseFloat(value, 10);
        })
    }

    function checkValueBoundaries() {
        if (angular.isUndefined($scope.number) || isNaN($scope.number)) {
            return;
        }

        var multiplier = decimals === 0 ? 1 : parseInt('1' + Array(decimals + 1).join("0"), 10);
        if (angular.isDefined($scope.maximum) && !isNaN($scope.maximum)) {
            if (Math.round($scope.number * multiplier) > Math.round($scope.maximum * multiplier)) {
                updateValue($scope.maximum);
                return;
            }
        }

        if (angular.isDefined($scope.minimum) && !isNaN($scope.minimum)) {
            if (Math.round($scope.number * multiplier) < Math.round($scope.minimum * multiplier)) {
                updateValue($scope.minimum);
                return;
            }
        }
    }

    this.checkValueBoundaries = checkValueBoundaries;

    function  updateValue(value) {
        if (isNaN(value)) {
            return;
        }

        $scope.number = value;
    }
}])

.directive('float', function () {
    return {
        restrict: 'A',
        require: ['^numberinput', '^ngModel'],
        link: function (scope, element, attrs, ctrls) {
            var numberinputCtrl = ctrls[0],
                ngModelCtrl = ctrls[1];

            function sanitizeFloat(input) {
                function clean(input) {
                    return input.replace(/[^-0-9]/g, '');
                }

                function removeMinusSign(input) {
                    return input.replace(/-/g, '');
                }

                var decimalSeparator = numberinputCtrl.getDecimalSeparator();
                var decimals = numberinputCtrl.getDecimals();

                var sanitized = String(input).replace('.', decimalSeparator);

                var position = sanitized.indexOf(decimalSeparator);
                if (position === 0) {
                    sanitized = '';
                } else if (position !== -1) {
                    var part1 = sanitized.substr(0, position);
                    var part2 = sanitized.substr(position + 1);

                    var integerPart = clean(part1);
                    var fractionalPart = clean(part2).substr(0, decimals);

                    sanitized = integerPart + decimalSeparator + fractionalPart;
                } else {
                    sanitized = clean(sanitized);
                }

                position = sanitized.indexOf('-');
                if (position !== -1) {
                    var part1, part2;
                    if (position === 0) {
                        sanitized = sanitized.substr(0, 1) +
                            removeMinusSign(sanitized.substr(1));
                    } else {
                        sanitized = removeMinusSign(sanitized);
                    }
                }

                // Remove the trailing decimals separator if no decimals are allowed
                if (decimals === 0 && sanitized.indexOf(decimalSeparator) === sanitized.length - 1) {
                    sanitized = sanitized.substr(0, sanitized.length - 1);
                }

                return sanitized;
            }

            function convertToFloat(input) {
                if (angular.isUndefined(input) || input.length === 0) {
                    return 0;
                }

                var decimalSeparator = numberinputCtrl.getDecimalSeparator();

                var result = parseFloat(input.replace(decimalSeparator, '.'), 10);
                if (isNaN(result)) { // e.g.: when typing the minus (-) sign
                    result = 0;
                }

                return result;
            }

            function sanitize(input) {
                if (angular.isUndefined(input) || input.length === 0) {
                    return undefined;
                }

                var viewValue = sanitizeFloat(input);
                var modelValue = convertToFloat(viewValue);

                if (viewValue !== input) {
                    ngModelCtrl.$setViewValue(viewValue);
                    ngModelCtrl.$render();
                }

                return modelValue;
            }

            ngModelCtrl.$parsers.unshift(sanitize);
            ngModelCtrl.$formatters.unshift(sanitize);

            ngModelCtrl.$render = function () {
                var decimalSeparator = numberinputCtrl.getDecimalSeparator();
                var viewValue = ngModelCtrl.$viewValue;
                if (!ngModelCtrl.$focused && angular.isDefined(ngModelCtrl.$modelValue)) {
                    var decimals = numberinputCtrl.getDecimals();
                    viewValue = ngModelCtrl.$modelValue.toFixed(decimals);
                    viewValue = viewValue.replace('.', decimalSeparator);
                }

                element.val(viewValue);
            }

            element.bind('blur', function () {
                scope.$apply(function () {
                    numberinputCtrl.checkValueBoundaries();
                });

                ngModelCtrl.$render();
            });

            scope.$watch('decimals + decimalSeparator', function (newVal, oldVal) {
                ngModelCtrl.$render();
            });
        }
    }
})

.directive('numberinput', function () {
    return {
        restrict: 'E',
        require: ['numberinput'],
        controller: 'NumberInputController',
        templateUrl: 'template/numberinput/numberinput.html',
        replace: true,
        scope: {
            number: '=ngModel',
            decimalSeparator: '@',
            decimals: '@',
            step: '@',
            disabled: '=ngDisabled'
        },
        link: function (scope, element, attrs, ctrls) {
            var numberinputCtrl = ctrls[0];
            numberinputCtrl.init(element);
        }
    };
});<commit_msg>numberinputController renders the input if decimal separator or decimals change, removed<commit_after>angular.module('ui.cg.numberinput', [])

.constant('numberinputConfig', {
    decimalSeparator: '.',
    decimals: 2,
    step: 1,
    keyboard: true,
    mousewheel: true,
    spinner: true
})

.controller('NumberInputController', ['$scope', '$attrs', 'numberinputConfig', function ($scope, $attrs, numberinputConfig) {
    var HOT_KEYS = [38, 40];
    var ngModelCtrl;

    this.init = function (element) {
        var input = element.find('input').eq(0);
        ngModelCtrl = input.controller('ngModel');

        var keyboard = angular.isDefined($attrs.keyboard) ? $scope.$eval($attrs.keyboard) : numberinputConfig.keyboard;
        if (keyboard) {
            this.bindKeyboardEvents(input);
        }

        var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$eval($attrs.mousewheel) : numberinputConfig.mousewheel;
        if (mousewheel) {
            this.bindMouseWheelEvents(input);
        }
    };

    function stepIt(step) {
        if ($scope.disabled === true) {
            return;
        }

        var modelValue = $scope.number;
        if (isNaN(modelValue)) {
            modelValue = 0;
        }

        var multiplier = decimals === 0 ? 1 : parseInt('1' + Array(decimals + 1).join("0"), 10);
        var modelValue = Math.round((modelValue + step) * multiplier) / multiplier;

        $scope.number = modelValue;

        checkValueBoundaries();
    }

    $scope.increment = function () {
        var step = getStep();
        stepIt(step);
    }

    $scope.decrement = function () {
        var step = getStep();
        stepIt(step * -1);
    }

    this.bindMouseWheelEvents = function(input) {
        var isScrollingUp = function (e) {
            if (e.originalEvent) {
                e = e.originalEvent;
            }

            var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;

            return (e.detail || delta > 0);
        };

        input.bind('mousewheel wheel', function (e) {
            $scope.$apply(isScrollingUp(e) ? $scope.increment() : $scope.decrement());
            e.preventDefault();
        });
    }

    this.bindKeyboardEvents = function(input) {
        input.bind('keydown', function (e) {
            if (HOT_KEYS.indexOf(e.which) === -1) {
                return;
            }

            e.stopPropagation();

            if (e.which === 40) {
                $scope.decrement();
            } else if (e.which === 38) {
                $scope.increment();
            }

            $scope.$apply();
        });
    };

    this.getDecimalSeparator = function () {
        return decimalSeparator;
    }

    var decimalSeparator = numberinputConfig.decimalSeparator;
    if ($attrs.decimalSeparator) {
        $attrs.$observe('decimalSeparator', function (value) {
            var parsed;
            if (!angular.isDefined(value) || value.length === 0) {
                parsed = numberinputConfig.decimalSeparator;
            } else {
                parsed = value[0];
            }

            decimalSeparator = parsed;

            ngModelCtrl.$render();
        })
    }

    this.getDecimals = function () {
        return decimals;
    }

    var decimals = numberinputConfig.decimals;
    if ($attrs.decimals) {
        $attrs.$observe('decimals', function (value) {
            var parsed;
            if (angular.isUndefined(value) || isNaN(value)) {
                parsed = numberinputConfig.decimals;
            } else {
                parsed = parseInt(value, 10);
            }

            if (parsed < 0) {
                parsed = 0;
            }

            decimals = parsed;

            ngModelCtrl.$render();
        });
    }

    function getStep() {
        var corrected = step;
        var minimumStep = decimals === 0 ? 1 : parseFloat('0.' + Array(decimals).join("0") + "1", 10);
        if (corrected < minimumStep) {
            corrected = minimumStep;
        }

        return corrected;
    }

    var step = numberinputConfig.step;
    if ($attrs.step) {
        $attrs.$observe('step', function (value) {
            var parsed;
            if (angular.isUndefined(value) || isNaN(value)) {
                parsed = numberinputConfig.step;
            } else {
                parsed = parseFloat(value, 10);
            }

            step = parsed;
        });
    }

    $scope.spinner = numberinputConfig.spinner;
    if ($attrs.spinner) {
        $attrs.$observe('spinner', function (value) {
            $scope.spinner = angular.isDefined(value) ? $scope.$eval(value) : true;
        });
    }

    if ($attrs.maximum) {
        $attrs.$observe('maximum', function (value) {
            $scope.maximum = parseFloat(value, 10);
        });
    }

    if ($attrs.minimum) {
        $attrs.$observe('minimum', function (value) {
            $scope.minimum = parseFloat(value, 10);
        })
    }

    function checkValueBoundaries() {
        if (angular.isUndefined($scope.number) || isNaN($scope.number)) {
            return;
        }

        var multiplier = decimals === 0 ? 1 : parseInt('1' + Array(decimals + 1).join("0"), 10);
        if (angular.isDefined($scope.maximum) && !isNaN($scope.maximum)) {
            if (Math.round($scope.number * multiplier) > Math.round($scope.maximum * multiplier)) {
                updateValue($scope.maximum);
                return;
            }
        }

        if (angular.isDefined($scope.minimum) && !isNaN($scope.minimum)) {
            if (Math.round($scope.number * multiplier) < Math.round($scope.minimum * multiplier)) {
                updateValue($scope.minimum);
                return;
            }
        }
    }

    this.checkValueBoundaries = checkValueBoundaries;

    function updateValue(value) {
        if (isNaN(value)) {
            return;
        }

        $scope.number = value;
    }
}])

.directive('float', function () {
    return {
        restrict: 'A',
        require: ['^numberinput', '^ngModel'],
        link: function (scope, element, attrs, ctrls) {
            var numberinputCtrl = ctrls[0],
                ngModelCtrl = ctrls[1];

            function sanitizeFloat(input) {
                function clean(input) {
                    return input.replace(/[^-0-9]/g, '');
                }

                function removeMinusSign(input) {
                    return input.replace(/-/g, '');
                }

                var decimalSeparator = numberinputCtrl.getDecimalSeparator();
                var decimals = numberinputCtrl.getDecimals();

                var sanitized = String(input).replace('.', decimalSeparator);

                var position = sanitized.indexOf(decimalSeparator);
                if (position === 0) {
                    sanitized = '';
                } else if (position !== -1) {
                    var part1 = sanitized.substr(0, position);
                    var part2 = sanitized.substr(position + 1);

                    var integerPart = clean(part1);
                    var fractionalPart = clean(part2).substr(0, decimals);

                    sanitized = integerPart + decimalSeparator + fractionalPart;
                } else {
                    sanitized = clean(sanitized);
                }

                position = sanitized.indexOf('-');
                if (position !== -1) {
                    var part1, part2;
                    if (position === 0) {
                        sanitized = sanitized.substr(0, 1) +
                            removeMinusSign(sanitized.substr(1));
                    } else {
                        sanitized = removeMinusSign(sanitized);
                    }
                }

                // Remove the trailing decimals separator if no decimals are allowed
                if (decimals === 0 && sanitized.indexOf(decimalSeparator) === sanitized.length - 1) {
                    sanitized = sanitized.substr(0, sanitized.length - 1);
                }

                return sanitized;
            }

            function convertToFloat(input) {
                if (angular.isUndefined(input) || input.length === 0) {
                    return 0;
                }

                var decimalSeparator = numberinputCtrl.getDecimalSeparator();

                var result = parseFloat(input.replace(decimalSeparator, '.'), 10);
                if (isNaN(result)) { // e.g.: when typing the minus (-) sign
                    result = 0;
                }

                return result;
            }

            function sanitize(input) {
                if (angular.isUndefined(input) || input.length === 0) {
                    return undefined;
                }

                var viewValue = sanitizeFloat(input);
                var modelValue = convertToFloat(viewValue);

                if (viewValue !== input) {
                    ngModelCtrl.$setViewValue(viewValue);
                    ngModelCtrl.$render();
                }

                return modelValue;
            }

            ngModelCtrl.$parsers.unshift(sanitize);
            ngModelCtrl.$formatters.unshift(sanitize);

            ngModelCtrl.$render = function () {
                var decimalSeparator = numberinputCtrl.getDecimalSeparator();
                var viewValue = ngModelCtrl.$viewValue;
                if (!ngModelCtrl.$focused && angular.isDefined(ngModelCtrl.$modelValue)) {
                    var decimals = numberinputCtrl.getDecimals();
                    viewValue = ngModelCtrl.$modelValue.toFixed(decimals);
                    viewValue = viewValue.replace('.', decimalSeparator);
                }

                element.val(viewValue);
            }

            element.bind('blur', function () {
                scope.$apply(function () {
                    numberinputCtrl.checkValueBoundaries();
                });

                ngModelCtrl.$render();
            });
        }
    }
})

.directive('numberinput', function () {
    return {
        restrict: 'E',
        require: ['numberinput'],
        controller: 'NumberInputController',
        templateUrl: 'template/numberinput/numberinput.html',
        replace: true,
        scope: {
            number: '=ngModel',
            decimalSeparator: '@',
            decimals: '@',
            step: '@',
            disabled: '=ngDisabled'
        },
        link: function (scope, element, attrs, ctrls) {
            var numberinputCtrl = ctrls[0];
            numberinputCtrl.init(element);
        }
    };
});<|endoftext|>


<commit_before>import expect from 'expect';

import Link from '../../lib/reducer/link';
import {Connectors} from '../../lib/reducer/connectors';

describe('Connectors store', () => {
  it('Starts an empty connectors object', () => {
    const connectors = new Connectors();
    expect(connectors.connectors).toEqual({});
  });

  const connectors = new Connectors();

  it('Adds a single connector from data added', () => {
    connectors.processConnectors(
      {
        connector1: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            pages: {
              addPage: 'Some'
            }
          }
        },
        connectorX: { // shouldn't be added
          fragments: {
            else: {
              _id: 1,
              title: 1
            }
          }
        }
      },
      'pages',
      'a',
      ['a', 'b']
    );
    expect(connectors.connectors).toEqual({
      connector1: {
        data: {
          pages: 'a'
        },
        listens: {
          pages: ['a', 'b']
        },
        mutations: {
          pages: {
            addPage: 'Some'
          }
        }
      }
    });
  });

  it('Adds connector with array data', () => {
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          }
        }
      },
      'pages',
      ['a', 'b'],
      ['a', 'b', 'c']
    );
    expect(connectors.connectors).toEqual({
      connector1: {
        data: {
          pages: 'a'
        },
        listens: {
          pages: ['a', 'b']
        },
        mutations: {
          pages: {
            addPage: 'Some'
          }
        }
      },
      connector2: {
        data: {
          pages: ['a', 'b']
        },
        listens: {
          pages: ['a', 'b', 'c']
        },
        mutations: {}
      }
    });
  });

  it('Deletes connector', () => {
    connectors.deleteConnector('connector1');
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['a', 'b']
        },
        listens: {
          pages: ['a', 'b', 'c']
        },
        mutations: {}
      }
    });
  });

  it('Updates connector', () => {
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            page: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            page: {
              something: 'something'
            }
          }
        }
      },
      'page',
      'd',
      ['d']
    );
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['a', 'b'],
          page: 'd'
        },
        listens: {
          pages: ['a', 'b', 'c'],
          page: ['d']
        },
        mutations: {
          page: {
            something: 'something'
          }
        }
      }
    });
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            page: {
              something: 'something else'
            }
          }
        }
      },
      'pages',
      ['d', 'e', 'f'],
      ['d', 'e', 'f', 'g']
    );
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['d', 'e', 'f'],
          page: 'd'
        },
        listens: {
          pages: ['d', 'e', 'f', 'g'],
          page: ['d']
        },
        mutations: {
          page: {
            something: 'something else'
          }
        }
      }
    });
  });
});
<commit_msg>connectors generate connector data by id test<commit_after>import expect from 'expect';

import store from '../../lib/reducer/store';
import {Connectors} from '../../lib/reducer/connectors';

describe('Connectors store', () => {
  it('Starts an empty connectors object', () => {
    const connectors = new Connectors();
    expect(connectors.connectors).toEqual({});
  });

  const connectors = new Connectors();

  it('Adds a single connector from data added', () => {
    connectors.processConnectors(
      {
        connector1: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            pages: {
              addPage: 'Some'
            }
          }
        },
        connectorX: { // shouldn't be added
          fragments: {
            else: {
              _id: 1,
              title: 1
            }
          }
        }
      },
      'pages',
      'a',
      ['a', 'b']
    );
    expect(connectors.connectors).toEqual({
      connector1: {
        data: {
          pages: 'a'
        },
        listens: {
          pages: ['a', 'b']
        },
        mutations: {
          pages: {
            addPage: 'Some'
          }
        }
      }
    });
  });

  it('Adds connector with array data', () => {
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          }
        }
      },
      'pages',
      ['a', 'b'],
      ['a', 'b', 'c']
    );
    expect(connectors.connectors).toEqual({
      connector1: {
        data: {
          pages: 'a'
        },
        listens: {
          pages: ['a', 'b']
        },
        mutations: {
          pages: {
            addPage: 'Some'
          }
        }
      },
      connector2: {
        data: {
          pages: ['a', 'b']
        },
        listens: {
          pages: ['a', 'b', 'c']
        },
        mutations: {}
      }
    });
  });

  it('Deletes connector', () => {
    connectors.deleteConnector('connector1');
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['a', 'b']
        },
        listens: {
          pages: ['a', 'b', 'c']
        },
        mutations: {}
      }
    });
  });

  it('Updates connector', () => {
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            page: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            page: {
              something: 'something'
            }
          }
        }
      },
      'page',
      'd',
      ['d']
    );
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['a', 'b'],
          page: 'd'
        },
        listens: {
          pages: ['a', 'b', 'c'],
          page: ['d']
        },
        mutations: {
          page: {
            something: 'something'
          }
        }
      }
    });
    connectors.processConnectors(
      {
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          },
          mutations: {
            page: {
              something: 'something else'
            }
          }
        }
      },
      'pages',
      ['d', 'e', 'f'],
      ['d', 'e', 'f', 'g']
    );
    expect(connectors.connectors).toEqual({
      connector2: {
        data: {
          pages: ['d', 'e', 'f'],
          page: 'd'
        },
        listens: {
          pages: ['d', 'e', 'f', 'g'],
          page: ['d']
        },
        mutations: {
          page: {
            something: 'something else'
          }
        }
      }
    });
  });

  it('Generates data for connector', () => {
    store.db = {
      a: {
        _id: 'a',
        title: 'A'
      },
      b: {
        _id: 'b',
        title: 'B'
      }
    };

    connectors.connectors = {
      connector1: {
        data: {
          pages: ['a', 'b'],
          page: 'a'
        }
      }
    };

    expect(connectors.generateConnectorData('connector1')).toEqual({
      pages: [
        {
          _id: 'a',
          title: 'A'
        },
        {
          _id: 'b',
          title: 'B'
        }
      ],
      page: {
        _id: 'a',
        title: 'A'
      }
    });

    // Clean up
    store.db = {};
  });
});
<|endoftext|>


<commit_before>// Register the serviceWorker script at /serviceworker.js from your server if supported
if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/serviceworker.js');
    if (window.vapidPublicKey) {
        navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
            serviceWorkerRegistration.pushManager.subscribe({
                userVisibleOnly: true,
                applicationServerKey: window.vapidPublicKey
            }).then(function(subscription) {
                $.post(window.webpush.subscribePath, { subscription: subscription.toJSON() });
            });
        });
    }
}
<commit_msg>Webpush only for authorized users.<commit_after>// Register the serviceWorker script at /serviceworker.js from your server if supported
if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/serviceworker.js');
    if (window.vapidPublicKey && window.webpush.active) {
        navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
            serviceWorkerRegistration.pushManager.subscribe({
                userVisibleOnly: true,
                applicationServerKey: window.vapidPublicKey
            }).then(function(subscription) {
                $.post(window.webpush.subscribePath, { subscription: subscription.toJSON() });
            });
        });
    }
}
<|endoftext|>


<commit_before>/**
 * @copyright   2010-2013, The Titon Project
 * @license     http://opensource.org/licenses/bsd-license.php
 * @link        http://titon.io
 */

(function() {
    'use strict';

Toolkit.Input = new Class({
    Extends: Toolkit.Component,

    /** Wrapping custom input */
    wrapper: null,

    /** Default options */
    options: {
        checkbox: 'input[type="checkbox"]',
        radio: 'input[type="radio"]',
        select: 'select'
    },

    /**
     * Initialize custom inputs on target forms.
     *
     * @param {Element} element
     * @param {Object} [options]
     */
    initialize: function(element, options) {
        this.parent(options);
        this.setElement(element);

        if (!this.element) {
            return;
        }

        this.bindEvents();
        this.fireEvent('init');
    },

    /**
     * Replace specific form elements with custom replacements.
     *
     * @returns {Toolkit.Input}
     */
    bindEvents: function() {
        var options = this.options;

        // Checkboxes
        if (options.checkbox) {
            this.element.getElements(options.checkbox).each(function(el) {
                el.$checkbox = new Toolkit.Input.Checkbox(el, options);
            });
        }

        // Radios
        if (options.radio) {
            this.element.getElements(options.radio).each(function(el) {
                el.$radio = new Toolkit.Input.Radio(el, options);
            });
        }

        // Selects
        if (options.select) {
            this.element.getElements(options.select).each(function(el) {
                if (el.multiple && !options.multiple) {
                    return; // Do not style multi-selects
                }

                el.$select = new Toolkit.Input.Select(el, options);
            });
        }

        return this;
    },

    /**
     * Build the element to wrap custom inputs with.
     * Copy over the original class names.
     *
     * @private
     * @param {Element} element
     * @returns {Element}
     */
    _buildWrapper: function(element) {
        var div = new Element('div.' + Toolkit.options.vendor +'custom-input'),
            classes = (element.get('class') || '').replace(/\binput\b/, '').trim();

        if (classes) {
            div.addClass(classes);
        }

        div.wraps(element);

        this.wrapper = div;

        return div;
    }

});

Toolkit.Input.Checkbox = new Class({
    Extends: Toolkit.Input,

    /** Base checkbox */
    checkbox: null,

    /**
     * Wrap the checkbox with a custom element.
     *
     * @param {Element} checkbox
     * @param {Object} options
     */
    initialize: function(checkbox, options) {
        this.setOptions(options);

        this.checkbox = checkbox;

        this._buildWrapper(checkbox);

        this.setElement(
            new Element('label.' + Toolkit.options.vendor + 'checkbox')
                .setProperty('for', checkbox.get('id'))
                .inject(checkbox, 'after')
        );
    }
});

Toolkit.Input.Radio = new Class({
    Extends: Toolkit.Input,

    /** Base radio */
    radio: null,

    /**
     * Wrap the radio with a custom element.
     *
     * @param {Element} radio
     * @param {Object} options
     */
    initialize: function(radio, options) {
        this.setOptions(options);

        this.radio = radio;

        this._buildWrapper(radio);

        this.setElement(
            new Element('label.' + Toolkit.options.vendor + 'radio')
                .setProperty('for', radio.get('id'))
                .inject(radio, 'after')
        );
    }
});

Toolkit.Input.Select = new Class({
    Extends: Toolkit.Input,
    Binds: ['_buildOption', '__change'],

    /** Base select */
    select: null,

    /** Custom button */
    button: null,

    /** Custom dropdown */
    dropdown: null,

    /** Options */
    options: {
        multiple: false,
        dropdown: true
    },

    initialize: function(select, options) {
        this.setOptions(options);
        this.select = select;

        // Create custom elements
        this._buildWrapper(select);
        this._buildButton(select);

        // Custom dropdowns
        if (this.options.dropdown) {
            this._buildDropdown(select);

            this.button.addEvent('click', this.__show);

            select
                .addEvent('focus', this.__show)
                .addEvent('blur', this.__show)

                // Cant hide/invisible or we lose focus/blur
                .setStyle('z-index', 1);
        }

        select.addEvent('change', this.__change);
    },

    /**
     * Build the element to represent the select button with label and arrow.
     *
     * @private
     * @param {Element} select
     * @returns {Element}
     */
    _buildButton: function(select) {
        var vendor = Toolkit.options.vendor;

        return this.button = new Element('div.' + vendor + 'select')
            .grab(new Element('div.' + vendor + 'select-arrow').set('html', ''))
            .grab(new Element('div.' + vendor + 'select-label').set('text', select[select.selectedIndex].textContent))
            .setStyle('min-width', select.getWidth())
            .inject(select, 'after');
    },

    /**
     * Build the custom dropdown to hold a list of option items.
     *
     * @private
     * @param {Element} select
     * @returns {Element}
     */
    _buildDropdown: function(select) {
        var vendor = Toolkit.options.vendor,
            buildOption = this._buildOption,
            dropdown = new Element('ul.' + vendor + 'dropdown');

        this.dropdown = dropdown;
        this.wrapper.grab(dropdown);

        Array.from(select.children).each(function(optgroup) {
            if (optgroup.get('tag') === 'optgroup') {
                dropdown.grab(
                    new Element('li')
                        .addClass(vendor + 'dropdown-heading')
                        .set('text', optgroup.get('label'))
                );

                Array.from(optgroup.children).each(function(option) {
                    dropdown.grab( buildOption(option) );
                });
            } else {
                dropdown.grab( buildOption(optgroup) );
            }
        });

        return dropdown;
    },

    /**
     * Build the list item to represent the select option.
     *
     * @private
     * @param {Element} option
     * @returns {Element}
     */
    _buildOption: function(option) {
        var select = this.select,
            dropdown = this.dropdown,
            activeClass = Toolkit.options.isPrefix + 'active';

        // Create elements
        var li = new Element('li');

        if (option.selected) {
            li.addClass(activeClass);
        }

        var a = new Element('a')
            .set('text', option.textContent)
            .set('href', 'javascript:;')
            .addEvent('click', function() {
                select.set('value', option.value);
                select.fireEvent('change', { target: select });

                dropdown.conceal();
                dropdown.getElements('li').removeClass(activeClass);

                this.getParent().addClass(activeClass);
            });

        return li.grab(a);
    },

    /**
     * Event handler for select option changing.
     *
     * @private
     * @param {DOMEvent} e
     */
    __change: function(e) {
        var select = e.target;

        if (select[select.selectedIndex]) {
            select.getParent().getElement('.' + Toolkit.options.vendor + 'select-label')
                .set('text', select[select.selectedIndex].textContent);
        }
    },

    /**
     * Event handler for toggling custom dropdown display.
     *
     * @private
     * @param {DOMEvent} e
     */
    __show: function(e) {
        if (this.select.disabled) {
            return;
        }

        var dropdown = this.dropdown;

        if (dropdown.isShown()) {
            dropdown.conceal();
        } else {
            dropdown.reveal();
        }

        this.button.toggleClass('is-active');
    }
});

/**
 * Enable custom inputs and selects within forms by calling input().
 * An object of options can be passed as the 1st argument.
 *
 * @example
 *     $$('form').input();
 *
 * @param {Object} [options]
 * @returns {Element}
 */
Element.implement('input', function(options) {
    if (!this.$input) {
        this.$input = new Toolkit.Input(this, options);
    }

    return this;
});

})();<commit_msg>Cleaning up new Input code<commit_after>/**
 * @copyright   2010-2013, The Titon Project
 * @license     http://opensource.org/licenses/bsd-license.php
 * @link        http://titon.io
 */

(function() {
    'use strict';

    Toolkit.Input = new Class({
        Extends: Toolkit.Component,

        /** Wrapping div */
        wrapper: null,

        /** Base input */
        input: null,

        /** Default options */
        options: {
            checkbox: 'input[type="checkbox"]',
            radio: 'input[type="radio"]',
            select: 'select'
        },

        /**
         * Initialize custom inputs on target forms.
         *
         * @param {Element} element
         * @param {Object} [options]
         */
        initialize: function(element, options) {
            this.parent(options);
            this.setElement(element);

            if (!this.element) {
                return;
            }

            this.bindEvents();
            this.fireEvent('init');
        },

        /**
         * Replace specific form elements with custom replacements.
         *
         * @returns {Toolkit.Input}
         */
        bindEvents: function() {
            var options = this.options;

            if (options.checkbox) {
                this.element.getElements(options.checkbox).checkbox(options);
            }

            if (options.radio) {
                this.element.getElements(options.radio).radio(options);
            }

            if (options.select) {
                this.element.getElements(options.select).select(options);
            }

            return this;
        },

        /**
         * Build the element to wrap custom inputs with.
         * Copy over the original class names.
         *
         * @param {Element} element
         * @returns {Toolkit.Input}
         */
        buildWrapper: function(element) {
            var div = new Element('div.' + Toolkit.options.vendor +'custom-input'),
                classes = (element.get('class') || '').replace(/\binput\b/, '').trim();

            if (classes) {
                div.addClass(classes);
            }

            div.wraps(element);

            this.wrapper = div;

            return this;
        }
    });

    /**
     * Wraps a checkbox with a custom input.
     * Uses a label for checkbox toggling so no JavaScript events are required.
     */
    Toolkit.Input.Checkbox = new Class({
        Extends: Toolkit.Input,

        /**
         * Wrap the checkbox with a custom element.
         *
         * @param {Element} checkbox
         * @param {Object} [options]
         */
        initialize: function(checkbox, options) {
            this.input = checkbox;
            this.setOptions(options);

            this.buildWrapper(checkbox);

            this.setElement(
                new Element('label.' + Toolkit.options.vendor + 'checkbox')
                    .setProperty('for', checkbox.get('id'))
                    .inject(checkbox, 'after')
            );

            this.fireEvent('init');
        }
    });

    /**
     * Wraps a radio with a custom input.
     * Uses a label for radio toggling so no JavaScript events are required.
     */
    Toolkit.Input.Radio = new Class({
        Extends: Toolkit.Input,

        /**
         * Wrap the radio with a custom element.
         *
         * @param {Element} radio
         * @param {Object} [options]
         */
        initialize: function(radio, options) {
            this.input = radio;
            this.setOptions(options);

            this.buildWrapper(radio);

            this.setElement(
                new Element('label.' + Toolkit.options.vendor + 'radio')
                    .setProperty('for', radio.get('id'))
                    .inject(radio, 'after')
            );

            this.fireEvent('init');
        }
    });

    /**
     * Wraps a select dropdown with a custom input.
     * Supports native or custom dropdowns.
     */
    Toolkit.Input.Select = new Class({
        Extends: Toolkit.Input,
        Binds: ['_buildOption', '__change', '__toggle'],

        /** Custom button */
        button: null,

        /** Custom dropdown */
        dropdown: null,

        /** Default options */
        options: {
            multiple: false,
            dropdown: true,
            arrowContent: '',
            defaultLabel: ''
        },

        /**
         * Wrap the select with a custom element.
         *
         * @param {Element} select
         * @param {Object} [options]
         */
        initialize: function(select, options) {
            this.input = select;
            this.setOptions(options);

            // Do not style multi-selects
            if (select.multiple && !this.options.multiple) {
                return;
            }

            // Create custom elements
            this.buildWrapper(select);
            this.buildButton(select);

            // Custom dropdowns
            if (this.options.dropdown) {
                this.buildDropdown(select);

                // Trigger focus on the real select when the custom button is clicked
                this.button.addEvent('click', function(e) {
                    e.preventDefault();

                    select.fireEvent('focus', { target: select });
                });

                select
                    // Open the dropdown when the real select gets/loses focus via label
                    .addEvent('focus', this.__toggle)
                    .addEvent('blur', this.__hide)

                    // Cant hide/invisible the real select or we lose focus/blur
                    // So place it below .custom-input
                    .setStyle('z-index', 1);
            }

            // All change events behave the same
            select.addEvent('change', this.__change);
        },

        /**
         * Build the element to represent the select button with label and arrow.
         *
         * @param {Element} select
         * @returns {Toolkit.Input.Select}
         */
        buildButton: function(select) {
            var vendor = Toolkit.options.vendor;

            this.button = new Element('div.' + vendor + 'select')
                .grab(new Element('div.' + vendor + 'select-arrow').set('html', this.options.arrowContent))
                .grab(new Element('div.' + vendor + 'select-label').set('text', this.options.defaultLabel || select[select.selectedIndex].textContent))
                .setStyle('min-width', select.getWidth())
                .inject(select, 'after');

            return this;
        },

        /**
         * Build the custom dropdown to hold a list of option items.
         *
         * @param {Element} select
         * @returns {Toolkit.Input.Select}
         */
        buildDropdown: function(select) {
            var vendor = Toolkit.options.vendor,
                buildOption = this.buildOption.bind(this),
                dropdown = new Element('ul.' + vendor + 'drop--down');

            this.dropdown = dropdown;

            Array.from(select.children).each(function(optgroup) {
                if (optgroup.get('tag') === 'optgroup') {
                    dropdown.grab(
                        new Element('li')
                            .addClass(vendor + 'drop-heading')
                            .set('text', optgroup.get('label'))
                    );

                    Array.from(optgroup.children).each(function(option) {
                        dropdown.grab( buildOption(option) );
                    });
                } else {
                    dropdown.grab( buildOption(optgroup) );
                }
            });

            this.wrapper.grab(dropdown);

            return this;
        },

        /**
         * Build the list item to represent the select option.
         *
         * @param {Element} option
         * @returns {Element}
         */
        buildOption: function(option) {
            var select = this.select,
                dropdown = this.dropdown,
                activeClass = Toolkit.options.isPrefix + 'active';

            // Create elements
            var li = new Element('li');

            if (option.selected) {
                li.addClass(activeClass);
            }

            var a = new Element('a')
                .set('text', option.textContent)
                .set('href', 'javascript:;')
                .addEvent('click', function() {
                    dropdown.conceal();
                    dropdown.getElements('li').removeClass(activeClass);

                    this.getParent().addClass(activeClass);

                    select.set('value', option.value);
                    select.fireEvent('change', { target: select });
                });

            return li.grab(a);
        },

        /**
         * Hide the dropdown and remove active states.
         *
         * @returns {Toolkit.Input.Select}
         */
        hide: function() {
            this.button.removeClass(Toolkit.options.isPrefix + 'active');
            this.dropdown.conceal();
            this.fireEvent('hide');

            return this;
        },

        /**
         * Show the dropdown and apply active states.
         *
         * @returns {Toolkit.Input.Select}
         */
        show: function() {
            this.button.addClass(Toolkit.options.isPrefix + 'active');
            this.dropdown.reveal();
            this.fireEvent('show');

            return this;
        },

        /**
         * Event handler for select option changing.
         *
         * @private
         * @param {DOMEvent} e
         */
        __change: function(e) {
            var select = e.target;

            if (select[select.selectedIndex]) {
                select.getParent().getElement('.' + Toolkit.options.vendor + 'select-label')
                    .set('text', select[select.selectedIndex].textContent);
            }

            select.fireEvent('blur', { target: select });

            this.fireEvent('change');
        },

        /**
         * Event handler for toggling custom dropdown display.
         *
         * @private
         * @param {DOMEvent} e
         */
        __toggle: function(e) {
            if (!this.enabled || this.select.disabled) {
                return;
            }

            this.dropdown.isShown() ? this.hide() : this.show();
        }
    });

    /**
     * Enable custom inputs and selects within forms by calling input().
     * An object of options can be passed as the 1st argument.
     *
     * @example
     *     $$('form').input();
     *     $$('input[type="radio"]').radio();
     *     $$('input[type="checkbox"]').checkbox();
     *     $$('select').select();
     *
     * @param {Object} [options]
     * @returns {Element}
     */
    Element.implement({
        input: function(options) {
            new Toolkit.Input(this, options);

            return this;
        },
        radio: function(options) {
            if (!this.$radio) {
                this.$radio = new Toolkit.Input.Radio(this, options);
            }

            return this;
        },
        checkbox: function(options) {
            if (!this.$checkbox) {
                this.$checkbox = new Toolkit.Input.Checkbox(this, options);
            }

            return this;
        },
        select: function(options) {
            if (!this.$select) {
                this.$select = new Toolkit.Input.Select(this, options);
            }

            return this;
        }
    });

})();<|endoftext|>


<commit_before>services.factory('Events', ['$resource', function($resource){
    var eventUrl = 'api/v1/events/:eventId';
    return $resource(eventUrl, {
        eventId: '@id'
    }, {
        update: {
            method: 'PUT'
        },
        getBySlug:{
            url: eventUrl + '/slug/:slug',
            method: 'GET'
        }
    });
}]);
<commit_msg>Updated Events service definition<commit_after>'use strict';

var services = angular.module('app.services');

services.factory('Events', ['$resource', function($resource){
    var eventUrl = 'api/v1/events/:eventId';
    return $resource(eventUrl, {
        eventId: '@id'
    }, {
        update: {
            method: 'PUT'
        },
        getBySlug:{
            url: eventUrl + '/slug/:slug',
            method: 'GET'
        }
    });
}]);
<|endoftext|>


<commit_before>var assert = require('assert');
var RegExpRouter = require('../regexp_router');

describe('RegExpRouter', function() {
  it('sets params as RegExp result', function() {
    var router = RegExpRouter.create();
    router.add('^/hello/([^\/]+)$', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/hello/world', 'GET');
    assert.equal(result.params[1], 'world');
  });

  it('returns a NotFound warning when route does not exist', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/goodbye', 'GET');
    assert.equal(result.warning, 'NotFound');
  });

  it('returns a MethodNotSupported warning when method does not exist', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['PUT'] }, new Function() /* handleFn */);
    var result = router.find('/hello', 'GET');
    assert.equal(result.warning, 'MethodNotSupported');
  });

  it('matches all routes when an asterisk is used', function() {
    var router = RegExpRouter.create();
    router.add('*', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/hello/there/buddy', 'GET');
    assert.ok(!result.warning);
  });

  it('matches all methods when an asterisk is used', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['*'] }, new Function() /* handleFn */);
    var result = router.find('/hello', 'OPTIONS');
    assert.ok(!result.warning);
  });

  it('can truncate a path with a RegExp prefix', function() {
    var router = RegExpRouter.create();
    var path = router.truncate('/hello/world', '^/hello');
    assert.equal(path, '/world');
  });

  it('gracefully returns the path when trying to truncate using an asterisk', function() {
    var router = RegExpRouter.create();
    var path = router.truncate('/hello/world', '*');
    assert.equal(path, '/hello/world');
  });

  it('removes `$` in regular expression syntax when actsAsPrefix is set', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { actsAsPrefix: true }, new Function() /* handleFn */);
    var result = router.find('/hello/world', 'GET');
    assert.ok(!result.warning);
  });
});
<commit_msg>Adding a test to ensure truncated paths are always matched at the beginning.<commit_after>var assert = require('assert');
var RegExpRouter = require('../regexp_router');

describe('RegExpRouter', function() {
  it('sets params as RegExp result', function() {
    var router = RegExpRouter.create();
    router.add('^/hello/([^\/]+)$', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/hello/world', 'GET');
    assert.equal(result.params[1], 'world');
  });

  it('returns a NotFound warning when route does not exist', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/goodbye', 'GET');
    assert.equal(result.warning, 'NotFound');
  });

  it('returns a MethodNotSupported warning when method does not exist', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['PUT'] }, new Function() /* handleFn */);
    var result = router.find('/hello', 'GET');
    assert.equal(result.warning, 'MethodNotSupported');
  });

  it('matches all routes when an asterisk is used', function() {
    var router = RegExpRouter.create();
    router.add('*', { methods: ['GET'] }, new Function() /* handleFn */);
    var result = router.find('/hello/there/buddy', 'GET');
    assert.ok(!result.warning);
  });

  it('matches all methods when an asterisk is used', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { methods: ['*'] }, new Function() /* handleFn */);
    var result = router.find('/hello', 'OPTIONS');
    assert.ok(!result.warning);
  });

  it('can truncate a path with a RegExp prefix', function() {
    var router = RegExpRouter.create();
    var path = router.truncate('/hello/world', '^/hello');
    assert.equal(path, '/world');
  });

  it('ensures pattern matching starts at the beginning of the path when truncating', function() {
    var router = RegExpRouter.create();
    var path = router.truncate('/hello/world', '/hello');
    assert.equal(path, '/world');
  });

  it('gracefully returns the path when trying to truncate using an asterisk', function() {
    var router = RegExpRouter.create();
    var path = router.truncate('/hello/world', '*');
    assert.equal(path, '/hello/world');
  });

  it('removes `$` in regular expression syntax when actsAsPrefix is set', function() {
    var router = RegExpRouter.create();
    router.add('^/hello$', { actsAsPrefix: true }, new Function() /* handleFn */);
    var result = router.find('/hello/world', 'GET');
    assert.ok(!result.warning);
  });
});
<|endoftext|>