<commit_before>/*
Copyright (c) 2014, EDINA.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
   list of conditions and the following disclaimer in the documentation and/or
   other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must
   display the following acknowledgement: This product includes software
   developed by the EDINA.
4. Neither the name of the EDINA nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific prior
   written permission.

THIS SOFTWARE IS PROVIDED BY EDINA ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL EDINA BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

"use strict";

define(['ui', 'map', 'utils', './cache', './database'], function(ui, map, utils, cache, webdb){
    var MAX_NO_OF_SAVED_MAPS = 3;

    /**
     * Map with local storage caching.
     * @params options:
     *   url - TMS URL
     */
    var getMapWithLocalStorage = function(){
        if(map.isBaseLayerTMS()){
            return new FGBMapWithLocalStorage({
                url: map.getTMSURL()
            });
        }
        else{
            return new OSMMapWithLocalStorage({
                url: utils.getMapServerUrl()+'/${z}/${x}/${y}.png'
            });
        }
    };

    /**
     * FGB Map with local storage caching.
     * @params options:
     *   url - TMS URL
     */
    var FGBMapWithLocalStorage = OpenLayers.Class(OpenLayers.Layer.TMS, {
        initialize: function(options) {
            var baseLayer = map.getBaseLayer();
            this.serviceVersion = baseLayer.serviceVersion;
            this.layername = baseLayer.layername;
            this.type = baseLayer.type;

            // this boolean determines which overriden method is called getURLasync
            // or getURL. Using getURLasync was causing the application to freeze,
            // often getting a ANR
            this.async = typeof(webdb) !== 'undefined';

            this.isBaseLayer = true;
            OpenLayers.Layer.TMS.prototype.initialize.apply(
                this,
                [baseLayer.name, options.url, {}]
            );
        },
        getURLasync: function(bounds, callback, scope) {
            var url = OpenLayers.Layer.TMS.prototype.getURL.apply(this, [bounds]);
            var data = url.match(/\/(\d+)/g).join("").split("/");
            webdb.getCachedTilePath( callback, scope, data[2], data[3] , data[1], url);
        },
        getURL: function(bounds) {
            return OpenLayers.Layer.TMS.prototype.getURL.apply(this, [bounds]);
        },
    });

    /**
     * OSM Map with local storage caching.
     * @params options:
     *     url            - TMS URL
     */
    var OSMMapWithLocalStorage = OpenLayers.Class(OpenLayers.Layer.OSM, {
        initialize: function(options) {

            // this boolean determines which overriden method is called getURLasync
            // or getURL. Using getURLasync was causing the application to freeze,
            // often getting a ANR
            this.async = typeof(webdb) !== 'undefined';
            this.url = [options.url]

            OpenLayers.Layer.OSM.prototype.initialize.apply(
                this,
                []
            );
        },
        getURLasync: function(bounds, callback, scope) {
            var url = OpenLayers.Layer.OSM.prototype.getURL.apply(this, [bounds]);
            var urlData = OpenLayers.Layer.XYZ.prototype.getXYZ.apply(this, [bounds]);
            webdb.getCachedTilePath( callback, scope, urlData.x, urlData.y , urlData.z, url);
        }
    });

    // create layer on map for showing saved map extent
    var savedMapsLayer = map.addLayer({
        id: 'savedMaps',
        style:{colour: 'red'},
        visible:false
    });

    /**
     * Show saved maps screen.
     */
    var offlineMapsPage = function(){
        var maps = cache.getSavedMaps();
        var selectedSavedMap;
        var count = 0;

        ui.mapPage('saved-maps-map');

        if(maps){
            // build saved maps list
            $.each(maps, function(index, value){
                $('#saved-maps-list-list').append(
                    '
<fieldset class="ui-grid-b"> \

\
                         \

' + index + '
\

\

\

\

\

\
                       </fieldset>\

').trigger('create');
                ++count;
            });
        }

        if(count === 0){
            $('#saved-maps-list').html('
No saved maps - go to Download to create saved maps
');
        }
        else if(count < MAX_NO_OF_SAVED_MAPS){
            $('#saved-maps-list').append('
Download more maps
');
        }

        // display a saved map on main map
        var displayOnMap = function(){
            var name = selectedSavedMap.find('h3').text();
            var details = cache.getSavedMapDetails(name);
            if(details){
                map.showBBox({
                    'layer': savedMapsLayer,
                    'bounds': details.bounds,
                    'poi': details.poi
                });
            }
        };

        // context menu popup
        $('#saved-maps-list-popup').bind({
            // populate popup with map name
            popupafteropen: $.proxy(function(event, ui) {
                selectedSavedMap.toBeDeleted = false;
                $('#saved-maps-list-popup [data-role="divider"]').text(
                    selectedSavedMap.find('h3').text());
            }, this),
            popupafterclose: $.proxy(function() {
                if(selectedSavedMap.toBeDeleted){
                    // this hack is in the documentation for chaining popups:
                    // http://jquerymobile.com/demos/1.2.0/docs/pages/popup/index.html
                    setTimeout( function(){
                        $('#saved-maps-delete-popup').popup('open');
                    }, 100);
                }
            }, this)
        });

        $('#saved-maps-list-popup-view').click(function(event){
            // view selected
            $.mobile.changePage('map.html');
            displayOnMap();
        });
        $('#saved-maps-list-popup-delete').click($.proxy(function(event){
            // delete selected
            selectedSavedMap.toBeDeleted = true;
            $('#saved-maps-list-popup').popup('close');
        }, this));
        $('#saved-maps-delete-popup').bind({
            // populate delete dialog with map name
            popupafteropen: $.proxy(function(event, ui) {
                $('#saved-maps-delete-popup-name').text(
                    selectedSavedMap.find('h3').text());
            }, this)
        });
        $('#saved-maps-delete-popup-confirm').click($.proxy(function(event){
            // confirm map delete
            cache.deleteSavedMapDetails(selectedSavedMap.find('h3').text());
            $('#saved-maps-delete-popup').popup("close");
            $(selectedSavedMap).slideUp('slow');
        }, this));

        // click on a saved map
        var taphold = false;
        $('.saved-map-click').on(
            'tap',
            function(event){
                if(!taphold){
                    selectedSavedMap = $(event.target).parents('li');
                    displayOnMap();
                }
                else{
                    // taphold has been lifted
                    taphold = false;

                    // prevent popup dialog closing
                    event.preventDefault();
                }
            }
        );

        // press and hold on a saved map
        $('.saved-map-click').on(
            'taphold',
            function(event){
                selectedSavedMap = $(event.target).parents('li');
                $('#saved-maps-list-popup').popup('open', {positionTo: 'origin'});
                taphold = true;
            }
        );

        // make map list scrollable on touch screens
        utils.touchScroll('#saved-maps-list');

        $('#saved-maps-list-list').listview('refresh');

        // show first map on list
        selectedSavedMap = $('#saved-maps-list li:first');
        displayOnMap();

        savedMapsLayer.setVisibility(true);
    };

    /**
     * Save Map Name dialog.
     */
    var saveMapNamePage = function(){
        var dlSize = cache.totalNumberOfTilesToDownload(
            map.getZoomLevels().current,
            $('#saved-map-name-dialog-save-to').val()) * cache.AV_TILE_SIZE;

        var saveMap = false;

        $('#save-map-name-dialog-info').html(
            '
' + $('#cache-save-details-text-stats').text() + '
');

        $('#saved-map-name-dialog-text').val(new Date().toLocaleString().substr(0, 24));
        $('#saved-map-name-dialog-save-to').val($("#cache-slider").val());
        $('#saved-map-name-dialog-btn').click($.proxy(function(){
            $('.ui-dialog').dialog('close');
            saveMap = true;
        }, this));

        // use pageremove on save map name screen otherwise attaching the
        // showPageLoadingMsg to the page is problematic
        $('#save-map-name-dialog').on(
            'pageremove',
            function(){
                if(saveMap){
                    if(cache.saveMap($('#saved-map-name-dialog-text').val(),
                                     map.getZoomLevels().current,
                                     $('#saved-map-name-dialog-save-to').val())){
                    }
                }
            }
        );
    };

    /**
     * Initialise save map page.
     */
    var saveMapPage = function(){
        $('#cache-slider').bind(
            'change',
            $.proxy(cache.previewImagesChange, cache));
        $('#cache-save-slider .ui-slider-handle').bind(
            'vmousedown',
            $.proxy(cache.previewImagesMouseDown, cache));
        $('#cache-save-slider .ui-slider-handle').bind(
            'vmouseup',
            $.proxy(cache.previewImagesMouseUp, cache));

        map.removeAllFeatures(savedMapsLayer);

        $('#cache-controls').hide();
        $('#cache-preview').hide();
        $('#save-map-buttons').show();

        map.hideAnnotateLayer();
        map.hideRecordsLayer();

        var connection = utils.getConnectionStatus();
        if(utils.isMobileApp &&
           (connection.val === Connection.UNKNOWN ||
            connection.val === Connection.CELL_2G ||
            connection.val === Connection.NONE)){
            console.debug('current connection: ' + connection.str);
            utils.inform("You will need a decent network connection to use this functionality.");
        }

        $('#save-map-buttons-ok').click(function(){
            $('#cache-controls').show();
            $('#save-map-buttons').hide();
        });

        // initialise slider values according to zoom level
        setSliderValues();

        map.registerZoom(this, function(){
            setSliderValues();
        });

        $('#cache-save-details-zoom-level-but').val('1');

        if(cache.getSavedMapsCount() < MAX_NO_OF_SAVED_MAPS){
            $('#save-map-buttons-ok').removeClass('ui-disabled');
        }
        else{
            $('#save-map-buttons-ok').addClass('ui-disabled');

            setTimeout(function(){
                utils.inform('You have reached the maximum number of saved maps.');
            }, 1000);
        }

        // attach map to save-map-map div
        ui.mapPage('save-map-map');
    };

    /**
     * Set cache slider values depending on map resolution.
     */
    var setSliderValues = function(){
        var zooms = map.getZoomLevels();

        if(zooms.current === zooms.max){
            $('#cache-slider').slider("disable");
        }
        else{
            $('#cache-slider').slider("enable");
        }

        $('#cache-slider').attr('min', zooms.current);
        $('#cache-slider').attr('max', zooms.max);
        $("#cache-save-slider input").val(zooms.current).slider("refresh");

        cache.setSaveStats(zooms.current, zooms.current);
    };

    if(typeof(webdb) !== 'undefined'){
        if(localStorage.getItem(webdb.DATABASE_CREATED) !== "true"){
            webdb.createTablesIfRequired();
        }
    }

    $(document).on('pageinit', '#saved-maps-page', offlineMapsPage);
    $(document).on('pageshow', '#saved-maps-page', function(){
        map.updateSize();
    });

    $(document).on('pageshow', '#save-map-page', saveMapPage);
    $(document).on('pageinit', '#save-map-name-dialog', saveMapNamePage);

    // adding stylesheet to beginning of head
    $('head').prepend('<link rel="stylesheet" href="plugins/offline-maps/css/style.css" type="text/css" />');

    map.switchBaseLayer(getMapWithLocalStorage());
});
<commit_msg>Issue edina/fieldtrip-open #8 implement switch base map<commit_after>/*
Copyright (c) 2014, EDINA.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
   list of conditions and the following disclaimer in the documentation and/or
   other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must
   display the following acknowledgement: This product includes software
   developed by the EDINA.
4. Neither the name of the EDINA nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific prior
   written permission.

THIS SOFTWARE IS PROVIDED BY EDINA ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL EDINA BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

"use strict";

define(['ui', 'map', 'utils', './cache', './database'], function(ui, map, utils, cache, webdb){
    var MAX_NO_OF_SAVED_MAPS = 3;

    /**
     * Map with local storage caching.
     * @params options:
     *   url - TMS URL
     */
    var getMapWithLocalStorage = function(url){
        var layer;
        if(map.isBaseLayerTMS()){
            layer = new FGBMapWithLocalStorage({url: map.getTMSURL(url)});
        }
        else{
            layer = new OSMMapWithLocalStorage({
                url: utils.getMapServerUrl()+'/${z}/${x}/${y}.png'
            });
        }

        return layer;
    };

    /**
     * FGB Map with local storage caching.
     * @params options:
     *   url - TMS URL
     */
    var FGBMapWithLocalStorage = OpenLayers.Class(OpenLayers.Layer.TMS, {
        initialize: function(options) {
            var baseLayer = map.getBaseLayer();
            this.serviceVersion = baseLayer.serviceVersion;
            this.layername = baseLayer.layername;
            this.type = baseLayer.type;

            // this boolean determines which overriden method is called getURLasync
            // or getURL. Using getURLasync was causing the application to freeze,
            // often getting a ANR
            this.async = typeof(webdb) !== 'undefined';

            this.isBaseLayer = true;
            OpenLayers.Layer.TMS.prototype.initialize.apply(
                this,
                [baseLayer.name, options.url, {}]
            );
        },
        getURLasync: function(bounds, callback, scope) {
            var url = OpenLayers.Layer.TMS.prototype.getURL.apply(this, [bounds]);
            var data = url.match(/\/(\d+)/g).join("").split("/");
            webdb.getCachedTilePath( callback, scope, data[2], data[3] , data[1], url);
        },
        getURL: function(bounds) {
            return OpenLayers.Layer.TMS.prototype.getURL.apply(this, [bounds]);
        },
    });

    /**
     * OSM Map with local storage caching.
     * @params options:
     *     url            - TMS URL
     */
    var OSMMapWithLocalStorage = OpenLayers.Class(OpenLayers.Layer.OSM, {
        initialize: function(options) {

            // this boolean determines which overriden method is called getURLasync
            // or getURL. Using getURLasync was causing the application to freeze,
            // often getting a ANR
            this.async = typeof(webdb) !== 'undefined';
            this.url = [options.url]

            OpenLayers.Layer.OSM.prototype.initialize.apply(
                this,
                []
            );
        },
        getURLasync: function(bounds, callback, scope) {
            var url = OpenLayers.Layer.OSM.prototype.getURL.apply(this, [bounds]);
            var urlData = OpenLayers.Layer.XYZ.prototype.getXYZ.apply(this, [bounds]);
            webdb.getCachedTilePath( callback, scope, urlData.x, urlData.y , urlData.z, url);
        }
    });

    // create layer on map for showing saved map extent
    var savedMapsLayer = map.addLayer({
        id: 'savedMaps',
        style:{colour: 'red'},
        visible:false
    });

    /**
     * Show saved maps screen.
     */
    var offlineMapsPage = function(){
        var maps = cache.getSavedMaps();
        var selectedSavedMap;
        var count = 0;

        ui.mapPage('saved-maps-map');

        if(maps){
            // build saved maps list
            $.each(maps, function(index, value){
                $('#saved-maps-list-list').append(
                    '
<fieldset class="ui-grid-b"> \

\
                         \

' + index + '
\

\

\

\

\

\
                       </fieldset>\

').trigger('create');
                ++count;
            });
        }

        if(count === 0){
            $('#saved-maps-list').html('
No saved maps - go to Download to create saved maps
');
        }
        else if(count < MAX_NO_OF_SAVED_MAPS){
            $('#saved-maps-list').append('
Download more maps
');
        }

        // display a saved map on main map
        var displayOnMap = function(){
            var name = selectedSavedMap.find('h3').text();
            var details = cache.getSavedMapDetails(name);
            if(details){
                map.showBBox({
                    'layer': savedMapsLayer,
                    'bounds': details.bounds,
                    'poi': details.poi
                });
            }
        };

        // context menu popup
        $('#saved-maps-list-popup').bind({
            // populate popup with map name
            popupafteropen: $.proxy(function(event, ui) {
                selectedSavedMap.toBeDeleted = false;
                $('#saved-maps-list-popup [data-role="divider"]').text(
                    selectedSavedMap.find('h3').text());
            }, this),
            popupafterclose: $.proxy(function() {
                if(selectedSavedMap.toBeDeleted){
                    // this hack is in the documentation for chaining popups:
                    // http://jquerymobile.com/demos/1.2.0/docs/pages/popup/index.html
                    setTimeout( function(){
                        $('#saved-maps-delete-popup').popup('open');
                    }, 100);
                }
            }, this)
        });

        $('#saved-maps-list-popup-view').click(function(event){
            // view selected
            $.mobile.changePage('map.html');
            displayOnMap();
        });
        $('#saved-maps-list-popup-delete').click($.proxy(function(event){
            // delete selected
            selectedSavedMap.toBeDeleted = true;
            $('#saved-maps-list-popup').popup('close');
        }, this));
        $('#saved-maps-delete-popup').bind({
            // populate delete dialog with map name
            popupafteropen: $.proxy(function(event, ui) {
                $('#saved-maps-delete-popup-name').text(
                    selectedSavedMap.find('h3').text());
            }, this)
        });
        $('#saved-maps-delete-popup-confirm').click($.proxy(function(event){
            // confirm map delete
            cache.deleteSavedMapDetails(selectedSavedMap.find('h3').text());
            $('#saved-maps-delete-popup').popup("close");
            $(selectedSavedMap).slideUp('slow');
        }, this));

        // click on a saved map
        var taphold = false;
        $('.saved-map-click').on(
            'tap',
            function(event){
                if(!taphold){
                    selectedSavedMap = $(event.target).parents('li');
                    displayOnMap();
                }
                else{
                    // taphold has been lifted
                    taphold = false;

                    // prevent popup dialog closing
                    event.preventDefault();
                }
            }
        );

        // press and hold on a saved map
        $('.saved-map-click').on(
            'taphold',
            function(event){
                selectedSavedMap = $(event.target).parents('li');
                $('#saved-maps-list-popup').popup('open', {positionTo: 'origin'});
                taphold = true;
            }
        );

        // make map list scrollable on touch screens
        utils.touchScroll('#saved-maps-list');

        $('#saved-maps-list-list').listview('refresh');

        // show first map on list
        selectedSavedMap = $('#saved-maps-list li:first');
        displayOnMap();

        savedMapsLayer.setVisibility(true);
    };

    /**
     * Save Map Name dialog.
     */
    var saveMapNamePage = function(){
        var dlSize = cache.totalNumberOfTilesToDownload(
            map.getZoomLevels().current,
            $('#saved-map-name-dialog-save-to').val()) * cache.AV_TILE_SIZE;

        var saveMap = false;

        $('#save-map-name-dialog-info').html(
            '
' + $('#cache-save-details-text-stats').text() + '
');

        $('#saved-map-name-dialog-text').val(new Date().toLocaleString().substr(0, 24));
        $('#saved-map-name-dialog-save-to').val($("#cache-slider").val());
        $('#saved-map-name-dialog-btn').click($.proxy(function(){
            $('.ui-dialog').dialog('close');
            saveMap = true;
        }, this));

        // use pageremove on save map name screen otherwise attaching the
        // showPageLoadingMsg to the page is problematic
        $('#save-map-name-dialog').on(
            'pageremove',
            function(){
                if(saveMap){
                    if(cache.saveMap($('#saved-map-name-dialog-text').val(),
                                     map.getZoomLevels().current,
                                     $('#saved-map-name-dialog-save-to').val())){
                    }
                }
            }
        );
    };

    /**
     * Initialise save map page.
     */
    var saveMapPage = function(){
        $('#cache-slider').bind(
            'change',
            $.proxy(cache.previewImagesChange, cache));
        $('#cache-save-slider .ui-slider-handle').bind(
            'vmousedown',
            $.proxy(cache.previewImagesMouseDown, cache));
        $('#cache-save-slider .ui-slider-handle').bind(
            'vmouseup',
            $.proxy(cache.previewImagesMouseUp, cache));

        map.removeAllFeatures(savedMapsLayer);

        $('#cache-controls').hide();
        $('#cache-preview').hide();
        $('#save-map-buttons').show();

        map.hideAnnotateLayer();
        map.hideRecordsLayer();

        var connection = utils.getConnectionStatus();
        if(utils.isMobileApp &&
           (connection.val === Connection.UNKNOWN ||
            connection.val === Connection.CELL_2G ||
            connection.val === Connection.NONE)){
            console.debug('current connection: ' + connection.str);
            utils.inform("You will need a decent network connection to use this functionality.");
        }

        $('#save-map-buttons-ok').click(function(){
            $('#cache-controls').show();
            $('#save-map-buttons').hide();
        });

        // initialise slider values according to zoom level
        setSliderValues();

        map.registerZoom(this, function(){
            setSliderValues();
        });

        $('#cache-save-details-zoom-level-but').val('1');

        if(cache.getSavedMapsCount() < MAX_NO_OF_SAVED_MAPS){
            $('#save-map-buttons-ok').removeClass('ui-disabled');
        }
        else{
            $('#save-map-buttons-ok').addClass('ui-disabled');

            setTimeout(function(){
                utils.inform('You have reached the maximum number of saved maps.');
            }, 1000);
        }

        // attach map to save-map-map div
        ui.mapPage('save-map-map');
    };

    /**
     * Set cache slider values depending on map resolution.
     */
    var setSliderValues = function(){
        var zooms = map.getZoomLevels();

        if(zooms.current === zooms.max){
            $('#cache-slider').slider("disable");
        }
        else{
            $('#cache-slider').slider("enable");
        }

        $('#cache-slider').attr('min', zooms.current);
        $('#cache-slider').attr('max', zooms.max);
        $("#cache-save-slider input").val(zooms.current).slider("refresh");

        cache.setSaveStats(zooms.current, zooms.current);
    };

    if(typeof(webdb) !== 'undefined'){
        if(localStorage.getItem(webdb.DATABASE_CREATED) !== "true"){
            webdb.createTablesIfRequired();
        }
    }

    $(document).on('pageinit', '#saved-maps-page', offlineMapsPage);
    $(document).on('pageshow', '#saved-maps-page', function(){
        map.updateSize();
    });

    $(document).on('pageshow', '#save-map-page', saveMapPage);
    $(document).on('pageinit', '#save-map-name-dialog', saveMapNamePage);

    // adding stylesheet to beginning of head
    $('head').prepend('<link rel="stylesheet" href="plugins/offline-maps/css/style.css" type="text/css" />');

    $(document).on('change', '#settings-mapserver-url', function(){
        if(utils.isMobileDevice()){
            map.switchBaseLayer(
                getMapWithLocalStorage(
                    $('#settings-mapserver-url option:selected').val())
            );
        }
        else{
            utils.inform("Switching doesn't work on the desktop.");
        }
    });

    map.switchBaseLayer(getMapWithLocalStorage());
});
<|endoftext|>


<commit_before>/** IE Selection and Range classes
 *
 *  Original created by Tim Cameron Ryan
 *    http://github.com/timcameronryan/IERange
 *  Copyright (c) 2009 Tim Cameron Ryan
 *  Released under the MIT/X License
 *
 *  Modified by Joshua Peek
**/
if (!window.getSelection) {
  // TODO: Move this object into a closure
  var DOMUtils = {
    findChildPosition: function(node) {
      for (var i = 0; node = node.previousSibling; i++)
        continue;
      return i;
    },
    isDataNode: function(node) {
      return node && node.nodeValue !== null && node.data !== null;
    },
    isAncestorOf: function(parent, node) {
      return !DOMUtils.isDataNode(parent) &&
          (parent.contains(DOMUtils.isDataNode(node) ? node.parentNode : node) ||
          node.parentNode == parent);
    },
    isAncestorOrSelf: function(root, node) {
      return DOMUtils.isAncestorOf(root, node) || root == node;
    },
    findClosestAncestor: function(root, node) {
      if (DOMUtils.isAncestorOf(root, node))
        while (node && node.parentNode != root)
          node = node.parentNode;
      return node;
    },
    getNodeLength: function(node) {
      return DOMUtils.isDataNode(node) ? node.length : node.childNodes.length;
    },
    splitDataNode: function(node, offset) {
      if (!DOMUtils.isDataNode(node))
        return false;
      var newNode = node.cloneNode(false);
      node.deleteData(offset, node.length);
      newNode.deleteData(0, offset);
      node.parentNode.insertBefore(newNode, node.nextSibling);
    }
  };

  // TODO: Move this object into a closure
  var TextRangeUtils = {
    convertToDOMRange: function(textRange, document) {
      function adoptBoundary(domRange, textRange, bStart) {
        // iterate backwards through parent element to find anchor location
        var cursorNode = document.createElement('a'), cursor = textRange.duplicate();
        cursor.collapse(bStart);
        var parent = cursor.parentElement();
        do {
          parent.insertBefore(cursorNode, cursorNode.previousSibling);
          cursor.moveToElementText(cursorNode);
        } while (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) > 0 && cursorNode.previousSibling);

        // when we exceed or meet the cursor, we've found the node
        if (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) == -1 && cursorNode.nextSibling) {
          // data node
          cursor.setEndPoint(bStart ? 'EndToStart' : 'EndToEnd', textRange);
          domRange[bStart ? 'setStart' : 'setEnd'](cursorNode.nextSibling, cursor.text.length);
        } else {
          // element
          domRange[bStart ? 'setStartBefore' : 'setEndBefore'](cursorNode);
        }
        cursorNode.parentNode.removeChild(cursorNode);
      }

      // return a DOM range
      var domRange = new Range(document);
      adoptBoundary(domRange, textRange, true);
      adoptBoundary(domRange, textRange, false);
      return domRange;
    },
    convertFromDOMRange: function(domRange) {
      function adoptEndPoint(textRange, domRange, bStart) {
        // find anchor node and offset
        var container = domRange[bStart ? 'startContainer' : 'endContainer'];
        var offset = domRange[bStart ? 'startOffset' : 'endOffset'], textOffset = 0;
        var anchorNode = DOMUtils.isDataNode(container) ? container : container.childNodes[offset];
        var anchorParent = DOMUtils.isDataNode(container) ? container.parentNode : container;
        // visible data nodes need a text offset
        if (container.nodeType == 3 || container.nodeType == 4)
          textOffset = offset;

        // create a cursor element node to position range (since we can't select text nodes)
        var cursorNode = domRange._document.createElement('a');
        anchorParent.insertBefore(cursorNode, anchorNode);
        var cursor = domRange._document.body.createTextRange();
        cursor.moveToElementText(cursorNode);
        cursorNode.parentNode.removeChild(cursorNode);
        // move range
        textRange.setEndPoint(bStart ? 'StartToStart' : 'EndToStart', cursor);
        textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset);
      }

      // return an IE text range
      var textRange = domRange._document.body.createTextRange();
      adoptEndPoint(textRange, domRange, true);
      adoptEndPoint(textRange, domRange, false);
      return textRange;
    }
  };

  window.Range = (function() {
    function Range(document) {
      // save document parameter
      this._document = document;

      // initialize range
      this.startContainer = this.endContainer = document.body;
      this.endOffset = DOMUtils.getNodeLength(document.body);
    }
    Range.START_TO_START = 0;
    Range.START_TO_END = 1;
    Range.END_TO_END = 2;
    Range.END_TO_START = 3;

    Range.prototype = {
      startContainer: null,
      startOffset: 0,
      endContainer: null,
      endOffset: 0,
      commonAncestorContainer: null,
      collapsed: false,
      _document: null,

      _refreshProperties: function() {
        // collapsed attribute
        this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
        // find common ancestor
        var node = this.startContainer;
        while (node && node != this.endContainer && !DOMUtils.isAncestorOf(node, this.endContainer))
          node = node.parentNode;
        this.commonAncestorContainer = node;
      },

      setStart: function(container, offset) {
        this.startContainer = container;
        this.startOffset = offset;
        this._refreshProperties();
      },
      setEnd: function(container, offset) {
        this.endContainer = container;
        this.endOffset = offset;
        this._refreshProperties();
      },
      setStartBefore: function(refNode) {
        // set start to beore this node
        this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode));
      },
      setStartAfter: function(refNode) {
        // select next sibling
        this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1);
      },
      setEndBefore: function(refNode) {
        // set end to beore this node
        this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode));
      },
      setEndAfter: function(refNode) {
        // select next sibling
        this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1);
      },
      selectNode: function(refNode) {
        this.setStartBefore(refNode);
        this.setEndAfter(refNode);
      },
      selectNodeContents: function(refNode) {
        this.setStart(refNode, 0);
        this.setEnd(refNode, DOMUtils.getNodeLength(refNode));
      },
      collapse: function(toStart) {
        if (toStart)
          this.setEnd(this.startContainer, this.startOffset);
        else
          this.setStart(this.endContainer, this.endOffset);
      },

      cloneContents: function() {
        // clone subtree
        return (function cloneSubtree(iterator) {
          for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
            node = node.cloneNode(!iterator.hasPartialSubtree());
            if (iterator.hasPartialSubtree())
              node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
            frag.appendChild(node);
          }
          return frag;
        })(new RangeIterator(this));
      },
      extractContents: function() {
        // cache range and move anchor points
        var range = this.cloneRange();
        if (this.startContainer != this.commonAncestorContainer)
          this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
        this.collapse(true);
        // extract range
        return (function extractSubtree(iterator) {
          for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
            iterator.hasPartialSubtree() ? node = node.cloneNode(false) : iterator.remove();
            if (iterator.hasPartialSubtree())
              node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
            frag.appendChild(node);
          }
          return frag;
        })(new RangeIterator(range));
      },
      deleteContents: function() {
        // cache range and move anchor points
        var range = this.cloneRange();
        if (this.startContainer != this.commonAncestorContainer)
          this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
        this.collapse(true);
        // delete range
        (function deleteSubtree(iterator) {
          while (iterator.next())
            iterator.hasPartialSubtree() ? deleteSubtree(iterator.getSubtreeIterator()) : iterator.remove();
        })(new RangeIterator(range));
      },
      insertNode: function(newNode) {
        // set original anchor and insert node
        if (DOMUtils.isDataNode(this.startContainer)) {
          DOMUtils.splitDataNode(this.startContainer, this.startOffset);
          this.startContainer.parentNode.insertBefore(newNode, this.startContainer.nextSibling);
        } else {
          this.startContainer.insertBefore(newNode, this.startContainer.childNodes[this.startOffset]);
        }
        // resync start anchor
        this.setStart(this.startContainer, this.startOffset);
      },
      surroundContents: function(newNode) {
        // extract and surround contents
        var content = this.extractContents();
        this.insertNode(newNode);
        newNode.appendChild(content);
        this.selectNode(newNode);
      },

      compareBoundaryPoints: function(how, sourceRange) {
        // get anchors
        var containerA, offsetA, containerB, offsetB;
        switch (how) {
            case Range.START_TO_START:
            case Range.START_TO_END:
          containerA = this.startContainer;
          offsetA = this.startOffset;
          break;
            case Range.END_TO_END:
            case Range.END_TO_START:
          containerA = this.endContainer;
          offsetA = this.endOffset;
          break;
        }
        switch (how) {
            case Range.START_TO_START:
            case Range.END_TO_START:
          containerB = sourceRange.startContainer;
          offsetB = sourceRange.startOffset;
          break;
            case Range.START_TO_END:
            case Range.END_TO_END:
          containerB = sourceRange.endContainer;
          offsetB = sourceRange.endOffset;
          break;
        }

        // compare
        return containerA.sourceIndex < containerB.sourceIndex ? -1 :
            containerA.sourceIndex == containerB.sourceIndex ?
                offsetA < offsetB ? -1 : offsetA == offsetB ? 0 : 1
                : 1;
      },
      cloneRange: function() {
        // return cloned range
        var range = new Range(this._document);
        range.setStart(this.startContainer, this.startOffset);
        range.setEnd(this.endContainer, this.endOffset);
        return range;
      },
      detach: function() {
      },
      toString: function() {
        return TextRangeUtils.convertFromDOMRange(this).text;
      },
      createContextualFragment: function(tagString) {
        // parse the tag string in a context node
        var content = (DOMUtils.isDataNode(this.startContainer) ? this.startContainer.parentNode : this.startContainer).cloneNode(false);
        content.innerHTML = tagString;
        // return a document fragment from the created node
        for (var fragment = this._document.createDocumentFragment(); content.firstChild; )
          fragment.appendChild(content.firstChild);
        return fragment;
      }
    };

    function RangeIterator(range) {
      this.range = range;
      if (range.collapsed)
        return;

      // get anchors
      var root = range.commonAncestorContainer;
      this._next = range.startContainer == root && !DOMUtils.isDataNode(range.startContainer) ?
          range.startContainer.childNodes[range.startOffset] :
          DOMUtils.findClosestAncestor(root, range.startContainer);
      this._end = range.endContainer == root && !DOMUtils.isDataNode(range.endContainer) ?
          range.endContainer.childNodes[range.endOffset] :
          DOMUtils.findClosestAncestor(root, range.endContainer).nextSibling;
    }

    RangeIterator.prototype = {
      range: null,
      _current: null,
      _next: null,
      _end: null,

      hasNext: function() {
        return !!this._next;
      },
      next: function() {
        // move to next node
        var current = this._current = this._next;
        this._next = this._current && this._current.nextSibling != this._end ?
            this._current.nextSibling : null;

        // check for partial text nodes
        if (DOMUtils.isDataNode(this._current)) {
          if (this.range.endContainer == this._current)
            (current = current.cloneNode(true)).deleteData(this.range.endOffset, current.length - this.range.endOffset);
          if (this.range.startContainer == this._current)
            (current = current.cloneNode(true)).deleteData(0, this.range.startOffset);
        }
        return current;
      },
      remove: function() {
        // check for partial text nodes
        if (DOMUtils.isDataNode(this._current) &&
            (this.range.startContainer == this._current || this.range.endContainer == this._current)) {
          var start = this.range.startContainer == this._current ? this.range.startOffset : 0;
          var end = this.range.endContainer == this._current ? this.range.endOffset : this._current.length;
          this._current.deleteData(start, end - start);
        } else
          this._current.parentNode.removeChild(this._current);
      },
      hasPartialSubtree: function() {
        // check if this node be partially selected
        return !DOMUtils.isDataNode(this._current) &&
            (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer) ||
                DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer));
      },
      getSubtreeIterator: function() {
        // create a new range
        var subRange = new Range(this.range._document);
        subRange.selectNodeContents(this._current);
        // handle anchor points
        if (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer))
          subRange.setStart(this.range.startContainer, this.range.startOffset);
        if (DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer))
          subRange.setEnd(this.range.endContainer, this.range.endOffset);
        // return iterator
        return new RangeIterator(subRange);
      }
    };

    return Range;
  })();

  document.createRange = function() {
    return new Range(document);
  };

  window.Selection = (function() {
    function Selection(document) {
      this._document = document;

      var selection = this;
      document.attachEvent('onselectionchange', function() {
        selection._selectionChangeHandler();
      });
    }

    Selection.prototype = {
      rangeCount: 0,
      _document: null,

      _selectionChangeHandler: function() {
        this.rangeCount = this._selectionExists(this._document.selection.createRange()) ? 1 : 0;
      },
      _selectionExists: function(textRange) {
        return textRange.compareEndPoints('StartToEnd', textRange) != 0 ||
            textRange.parentElement().isContentEditable;
      },
      addRange: function(range) {
        var selection = this._document.selection.createRange(), textRange = TextRangeUtils.convertFromDOMRange(range);
        if (!this._selectionExists(selection)) {
          textRange.select();
        } else {
          // only modify range if it intersects with current range
          if (textRange.compareEndPoints('StartToStart', selection) == -1)
            if (textRange.compareEndPoints('StartToEnd', selection) > -1 &&
                textRange.compareEndPoints('EndToEnd', selection) == -1)
              selection.setEndPoint('StartToStart', textRange);
          else
            if (textRange.compareEndPoints('EndToStart', selection) < 1 &&
                textRange.compareEndPoints('EndToEnd', selection) > -1)
              selection.setEndPoint('EndToEnd', textRange);
          selection.select();
        }
      },
      removeAllRanges: function() {
        this._document.selection.empty();
      },
      getRangeAt: function(index) {
        var textRange = this._document.selection.createRange();
        if (this._selectionExists(textRange))
          return TextRangeUtils.convertToDOMRange(textRange, this._document);
        return null;
      },
      toString: function() {
        return this._document.selection.createRange().text;
      }
    };

    return Selection;
  })();

  window.getSelection = (function() {
    var selection = new Selection(document);
    return function() { return selection; };
  })();
}
<commit_msg>protect findChildPosition<commit_after>/** IE Selection and Range classes
 *
 *  Original created by Tim Cameron Ryan
 *    http://github.com/timcameronryan/IERange
 *  Copyright (c) 2009 Tim Cameron Ryan
 *  Released under the MIT/X License
 *
 *  Modified by Joshua Peek
**/
if (!window.getSelection) {
  // TODO: Move this object into a closure
  var DOMUtils = {
    isDataNode: function(node) {
      return node && node.nodeValue !== null && node.data !== null;
    },
    isAncestorOf: function(parent, node) {
      return !DOMUtils.isDataNode(parent) &&
          (parent.contains(DOMUtils.isDataNode(node) ? node.parentNode : node) ||
          node.parentNode == parent);
    },
    isAncestorOrSelf: function(root, node) {
      return DOMUtils.isAncestorOf(root, node) || root == node;
    },
    findClosestAncestor: function(root, node) {
      if (DOMUtils.isAncestorOf(root, node))
        while (node && node.parentNode != root)
          node = node.parentNode;
      return node;
    },
    getNodeLength: function(node) {
      return DOMUtils.isDataNode(node) ? node.length : node.childNodes.length;
    },
    splitDataNode: function(node, offset) {
      if (!DOMUtils.isDataNode(node))
        return false;
      var newNode = node.cloneNode(false);
      node.deleteData(offset, node.length);
      newNode.deleteData(0, offset);
      node.parentNode.insertBefore(newNode, node.nextSibling);
    }
  };

  // TODO: Move this object into a closure
  var TextRangeUtils = {
    convertToDOMRange: function(textRange, document) {
      function adoptBoundary(domRange, textRange, bStart) {
        // iterate backwards through parent element to find anchor location
        var cursorNode = document.createElement('a'), cursor = textRange.duplicate();
        cursor.collapse(bStart);
        var parent = cursor.parentElement();
        do {
          parent.insertBefore(cursorNode, cursorNode.previousSibling);
          cursor.moveToElementText(cursorNode);
        } while (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) > 0 && cursorNode.previousSibling);

        // when we exceed or meet the cursor, we've found the node
        if (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) == -1 && cursorNode.nextSibling) {
          // data node
          cursor.setEndPoint(bStart ? 'EndToStart' : 'EndToEnd', textRange);
          domRange[bStart ? 'setStart' : 'setEnd'](cursorNode.nextSibling, cursor.text.length);
        } else {
          // element
          domRange[bStart ? 'setStartBefore' : 'setEndBefore'](cursorNode);
        }
        cursorNode.parentNode.removeChild(cursorNode);
      }

      // return a DOM range
      var domRange = new Range(document);
      adoptBoundary(domRange, textRange, true);
      adoptBoundary(domRange, textRange, false);
      return domRange;
    },
    convertFromDOMRange: function(domRange) {
      function adoptEndPoint(textRange, domRange, bStart) {
        // find anchor node and offset
        var container = domRange[bStart ? 'startContainer' : 'endContainer'];
        var offset = domRange[bStart ? 'startOffset' : 'endOffset'], textOffset = 0;
        var anchorNode = DOMUtils.isDataNode(container) ? container : container.childNodes[offset];
        var anchorParent = DOMUtils.isDataNode(container) ? container.parentNode : container;
        // visible data nodes need a text offset
        if (container.nodeType == 3 || container.nodeType == 4)
          textOffset = offset;

        // create a cursor element node to position range (since we can't select text nodes)
        var cursorNode = domRange._document.createElement('a');
        anchorParent.insertBefore(cursorNode, anchorNode);
        var cursor = domRange._document.body.createTextRange();
        cursor.moveToElementText(cursorNode);
        cursorNode.parentNode.removeChild(cursorNode);
        // move range
        textRange.setEndPoint(bStart ? 'StartToStart' : 'EndToStart', cursor);
        textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset);
      }

      // return an IE text range
      var textRange = domRange._document.body.createTextRange();
      adoptEndPoint(textRange, domRange, true);
      adoptEndPoint(textRange, domRange, false);
      return textRange;
    }
  };

  window.Range = (function() {
    function Range(document) {
      // save document parameter
      this._document = document;

      // initialize range
      this.startContainer = this.endContainer = document.body;
      this.endOffset = DOMUtils.getNodeLength(document.body);
    }
    Range.START_TO_START = 0;
    Range.START_TO_END = 1;
    Range.END_TO_END = 2;
    Range.END_TO_START = 3;

    function findChildPosition(node) {
      for (var i = 0; node = node.previousSibling; i++)
        continue;
      return i;
    }

    Range.prototype = {
      startContainer: null,
      startOffset: 0,
      endContainer: null,
      endOffset: 0,
      commonAncestorContainer: null,
      collapsed: false,
      _document: null,

      _refreshProperties: function() {
        // collapsed attribute
        this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
        // find common ancestor
        var node = this.startContainer;
        while (node && node != this.endContainer && !DOMUtils.isAncestorOf(node, this.endContainer))
          node = node.parentNode;
        this.commonAncestorContainer = node;
      },

      setStart: function(container, offset) {
        this.startContainer = container;
        this.startOffset = offset;
        this._refreshProperties();
      },
      setEnd: function(container, offset) {
        this.endContainer = container;
        this.endOffset = offset;
        this._refreshProperties();
      },
      setStartBefore: function(refNode) {
        // set start to beore this node
        this.setStart(refNode.parentNode, findChildPosition(refNode));
      },
      setStartAfter: function(refNode) {
        // select next sibling
        this.setStart(refNode.parentNode, findChildPosition(refNode) + 1);
      },
      setEndBefore: function(refNode) {
        // set end to beore this node
        this.setEnd(refNode.parentNode, findChildPosition(refNode));
      },
      setEndAfter: function(refNode) {
        // select next sibling
        this.setEnd(refNode.parentNode, findChildPosition(refNode) + 1);
      },
      selectNode: function(refNode) {
        this.setStartBefore(refNode);
        this.setEndAfter(refNode);
      },
      selectNodeContents: function(refNode) {
        this.setStart(refNode, 0);
        this.setEnd(refNode, DOMUtils.getNodeLength(refNode));
      },
      collapse: function(toStart) {
        if (toStart)
          this.setEnd(this.startContainer, this.startOffset);
        else
          this.setStart(this.endContainer, this.endOffset);
      },

      cloneContents: function() {
        // clone subtree
        return (function cloneSubtree(iterator) {
          for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
            node = node.cloneNode(!iterator.hasPartialSubtree());
            if (iterator.hasPartialSubtree())
              node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
            frag.appendChild(node);
          }
          return frag;
        })(new RangeIterator(this));
      },
      extractContents: function() {
        // cache range and move anchor points
        var range = this.cloneRange();
        if (this.startContainer != this.commonAncestorContainer)
          this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
        this.collapse(true);
        // extract range
        return (function extractSubtree(iterator) {
          for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
            iterator.hasPartialSubtree() ? node = node.cloneNode(false) : iterator.remove();
            if (iterator.hasPartialSubtree())
              node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
            frag.appendChild(node);
          }
          return frag;
        })(new RangeIterator(range));
      },
      deleteContents: function() {
        // cache range and move anchor points
        var range = this.cloneRange();
        if (this.startContainer != this.commonAncestorContainer)
          this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
        this.collapse(true);
        // delete range
        (function deleteSubtree(iterator) {
          while (iterator.next())
            iterator.hasPartialSubtree() ? deleteSubtree(iterator.getSubtreeIterator()) : iterator.remove();
        })(new RangeIterator(range));
      },
      insertNode: function(newNode) {
        // set original anchor and insert node
        if (DOMUtils.isDataNode(this.startContainer)) {
          DOMUtils.splitDataNode(this.startContainer, this.startOffset);
          this.startContainer.parentNode.insertBefore(newNode, this.startContainer.nextSibling);
        } else {
          this.startContainer.insertBefore(newNode, this.startContainer.childNodes[this.startOffset]);
        }
        // resync start anchor
        this.setStart(this.startContainer, this.startOffset);
      },
      surroundContents: function(newNode) {
        // extract and surround contents
        var content = this.extractContents();
        this.insertNode(newNode);
        newNode.appendChild(content);
        this.selectNode(newNode);
      },

      compareBoundaryPoints: function(how, sourceRange) {
        // get anchors
        var containerA, offsetA, containerB, offsetB;
        switch (how) {
            case Range.START_TO_START:
            case Range.START_TO_END:
          containerA = this.startContainer;
          offsetA = this.startOffset;
          break;
            case Range.END_TO_END:
            case Range.END_TO_START:
          containerA = this.endContainer;
          offsetA = this.endOffset;
          break;
        }
        switch (how) {
            case Range.START_TO_START:
            case Range.END_TO_START:
          containerB = sourceRange.startContainer;
          offsetB = sourceRange.startOffset;
          break;
            case Range.START_TO_END:
            case Range.END_TO_END:
          containerB = sourceRange.endContainer;
          offsetB = sourceRange.endOffset;
          break;
        }

        // compare
        return containerA.sourceIndex < containerB.sourceIndex ? -1 :
            containerA.sourceIndex == containerB.sourceIndex ?
                offsetA < offsetB ? -1 : offsetA == offsetB ? 0 : 1
                : 1;
      },
      cloneRange: function() {
        // return cloned range
        var range = new Range(this._document);
        range.setStart(this.startContainer, this.startOffset);
        range.setEnd(this.endContainer, this.endOffset);
        return range;
      },
      detach: function() {
      },
      toString: function() {
        return TextRangeUtils.convertFromDOMRange(this).text;
      },
      createContextualFragment: function(tagString) {
        // parse the tag string in a context node
        var content = (DOMUtils.isDataNode(this.startContainer) ? this.startContainer.parentNode : this.startContainer).cloneNode(false);
        content.innerHTML = tagString;
        // return a document fragment from the created node
        for (var fragment = this._document.createDocumentFragment(); content.firstChild; )
          fragment.appendChild(content.firstChild);
        return fragment;
      }
    };

    function RangeIterator(range) {
      this.range = range;
      if (range.collapsed)
        return;

      // get anchors
      var root = range.commonAncestorContainer;
      this._next = range.startContainer == root && !DOMUtils.isDataNode(range.startContainer) ?
          range.startContainer.childNodes[range.startOffset] :
          DOMUtils.findClosestAncestor(root, range.startContainer);
      this._end = range.endContainer == root && !DOMUtils.isDataNode(range.endContainer) ?
          range.endContainer.childNodes[range.endOffset] :
          DOMUtils.findClosestAncestor(root, range.endContainer).nextSibling;
    }

    RangeIterator.prototype = {
      range: null,
      _current: null,
      _next: null,
      _end: null,

      hasNext: function() {
        return !!this._next;
      },
      next: function() {
        // move to next node
        var current = this._current = this._next;
        this._next = this._current && this._current.nextSibling != this._end ?
            this._current.nextSibling : null;

        // check for partial text nodes
        if (DOMUtils.isDataNode(this._current)) {
          if (this.range.endContainer == this._current)
            (current = current.cloneNode(true)).deleteData(this.range.endOffset, current.length - this.range.endOffset);
          if (this.range.startContainer == this._current)
            (current = current.cloneNode(true)).deleteData(0, this.range.startOffset);
        }
        return current;
      },
      remove: function() {
        // check for partial text nodes
        if (DOMUtils.isDataNode(this._current) &&
            (this.range.startContainer == this._current || this.range.endContainer == this._current)) {
          var start = this.range.startContainer == this._current ? this.range.startOffset : 0;
          var end = this.range.endContainer == this._current ? this.range.endOffset : this._current.length;
          this._current.deleteData(start, end - start);
        } else
          this._current.parentNode.removeChild(this._current);
      },
      hasPartialSubtree: function() {
        // check if this node be partially selected
        return !DOMUtils.isDataNode(this._current) &&
            (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer) ||
                DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer));
      },
      getSubtreeIterator: function() {
        // create a new range
        var subRange = new Range(this.range._document);
        subRange.selectNodeContents(this._current);
        // handle anchor points
        if (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer))
          subRange.setStart(this.range.startContainer, this.range.startOffset);
        if (DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer))
          subRange.setEnd(this.range.endContainer, this.range.endOffset);
        // return iterator
        return new RangeIterator(subRange);
      }
    };

    return Range;
  })();

  document.createRange = function() {
    return new Range(document);
  };

  window.Selection = (function() {
    function Selection(document) {
      this._document = document;

      var selection = this;
      document.attachEvent('onselectionchange', function() {
        selection._selectionChangeHandler();
      });
    }

    Selection.prototype = {
      rangeCount: 0,
      _document: null,

      _selectionChangeHandler: function() {
        this.rangeCount = this._selectionExists(this._document.selection.createRange()) ? 1 : 0;
      },
      _selectionExists: function(textRange) {
        return textRange.compareEndPoints('StartToEnd', textRange) != 0 ||
            textRange.parentElement().isContentEditable;
      },
      addRange: function(range) {
        var selection = this._document.selection.createRange(), textRange = TextRangeUtils.convertFromDOMRange(range);
        if (!this._selectionExists(selection)) {
          textRange.select();
        } else {
          // only modify range if it intersects with current range
          if (textRange.compareEndPoints('StartToStart', selection) == -1)
            if (textRange.compareEndPoints('StartToEnd', selection) > -1 &&
                textRange.compareEndPoints('EndToEnd', selection) == -1)
              selection.setEndPoint('StartToStart', textRange);
          else
            if (textRange.compareEndPoints('EndToStart', selection) < 1 &&
                textRange.compareEndPoints('EndToEnd', selection) > -1)
              selection.setEndPoint('EndToEnd', textRange);
          selection.select();
        }
      },
      removeAllRanges: function() {
        this._document.selection.empty();
      },
      getRangeAt: function(index) {
        var textRange = this._document.selection.createRange();
        if (this._selectionExists(textRange))
          return TextRangeUtils.convertToDOMRange(textRange, this._document);
        return null;
      },
      toString: function() {
        return this._document.selection.createRange().text;
      }
    };

    return Selection;
  })();

  window.getSelection = (function() {
    var selection = new Selection(document);
    return function() { return selection; };
  })();
}
<|endoftext|>


<commit_before>export default (matrix, xLength, yLength, numXBlocks, numYBlocks) => {
    const xwidth = Math.ceil(xLength / numXBlocks);
    const ywidth = Math.ceil(yLength / numYBlocks);
    const results = [];
    for (let y = 0; y < numYBlocks; y++) {
        for (let x = 0; x < numXBlocks; x++) {
            const result = sumBlock(matrix, x * xwidth, (x + 1) * xwidth, y * ywidth, (y + 1) * ywidth, xLength, yLength);
            results.push(result);
        }
    }
    return results
}

const sumBlock = (matrix, xStart, xEnd, yStart, yEnd, rowLength, yMax) => {
    xEnd = Math.min(xEnd, rowLength);
    yEnd = Math.min(yEnd, yMax);
    const result = {red: 0, green: 0, blue: 0, alpha: 0};
    let count = 0;
    for (let y = yStart; y < yEnd; y += rowLength) {
        for (let x = xStart; x < xEnd; x += 1) {
            const pixel = getPixel(matrix, x, y, rowLength);
            console.log(x, y)
            // console.log(pixel)
            result.red += pixel.red;
            result.green += pixel.green;
            result.blue += pixel.blue;
            result.alpha += pixel.alpha;
            count += 1;
        }
    }
    result.red = result.red / count;
    result.green = result.green / count;
    result.blue = result.blue / count;
    result.alpha = result.alpha / count;
    return result
}

const getPixel = (matrix, x, y, rowLength) => {
    const index = (y * rowLength + x) * 4
    return {red: matrix[index], green: matrix[index + 1], blue: matrix[index + 2], alpha: matrix[index + 3]};
}<commit_msg>Remove redundant code<commit_after>export default (matrix, xLength, yLength, numXBlocks, numYBlocks) => {
    const xwidth = Math.ceil(xLength / numXBlocks);
    const ywidth = Math.ceil(yLength / numYBlocks);
    const results = [];
    for (let y = 0; y < numYBlocks; y++) {
        for (let x = 0; x < numXBlocks; x++) {
            const result = sumBlock(matrix, x * xwidth, (x + 1) * xwidth, y * ywidth, (y + 1) * ywidth, xLength, yLength);
            results.push(result);
        }
    }
    return results
}<|endoftext|>


<commit_before>import L from 'leaflet';
import { jsonp } from './Request';
import {
  geojsonToArcGIS as g2a,
  arcgisToGeoJSON as a2g
} from 'arcgis-to-geojson-utils';

export function geojsonToArcGIS (geojson, idAttr) {
  return g2a(geojson, idAttr);
}

export function arcgisToGeoJSON (arcgis, idAttr) {
  return a2g(arcgis, idAttr);
}

// shallow object clone for feature properties and attributes
// from http://jsperf.com/cloning-an-object/2
export function shallowClone (obj) {
  var target = {};
  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      target[i] = obj[i];
    }
  }
  return target;
}

// convert an extent (ArcGIS) to LatLngBounds (Leaflet)
export function extentToBounds (extent) {
  var sw = L.latLng(extent.ymin, extent.xmin);
  var ne = L.latLng(extent.ymax, extent.xmax);
  return L.latLngBounds(sw, ne);
}

// convert an LatLngBounds (Leaflet) to extent (ArcGIS)
export function boundsToExtent (bounds) {
  bounds = L.latLngBounds(bounds);
  return {
    'xmin': bounds.getSouthWest().lng,
    'ymin': bounds.getSouthWest().lat,
    'xmax': bounds.getNorthEast().lng,
    'ymax': bounds.getNorthEast().lat,
    'spatialReference': {
      'wkid': 4326
    }
  };
}

export function responseToFeatureCollection (response, idAttribute) {
  var objectIdField;

  if (idAttribute) {
    objectIdField = idAttribute;
  } else if (response.objectIdFieldName) {
    objectIdField = response.objectIdFieldName;
  } else if (response.fields) {
    for (var j = 0; j <= response.fields.length - 1; j++) {
      if (response.fields[j].type === 'esriFieldTypeOID') {
        objectIdField = response.fields[j].name;
        break;
      }
    }
  } else {
    objectIdField = 'OBJECTID';
  }

  var featureCollection = {
    type: 'FeatureCollection',
    features: []
  };
  var features = response.features || response.results;
  if (features.length) {
    for (var i = features.length - 1; i >= 0; i--) {
      var feature = arcgisToGeoJSON(features[i], objectIdField);
      featureCollection.features.push(feature);
    }
  }

  return featureCollection;
}

  // trim url whitespace and add a trailing slash if needed
export function cleanUrl (url) {
  // trim leading and trailing spaces, but not spaces inside the url
  url = L.Util.trim(url);

  // add a trailing slash to the url if the user omitted it
  if (url[url.length - 1] !== '/') {
    url += '/';
  }

  return url;
}

export function isArcgisOnline (url) {
  /* hosted feature services can emit geojson natively. */
  return (/\.arcgis\.com.*?FeatureServer/g).test(url);
}

export function geojsonTypeToArcGIS (geoJsonType) {
  var arcgisGeometryType;
  switch (geoJsonType) {
    case 'Point':
      arcgisGeometryType = 'esriGeometryPoint';
      break;
    case 'MultiPoint':
      arcgisGeometryType = 'esriGeometryMultipoint';
      break;
    case 'LineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'MultiLineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'Polygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
    case 'MultiPolygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
  }

  return arcgisGeometryType;
}

export function warn () {
  if (console && console.warn) {
    console.warn.apply(console, arguments);
  }
}

export function calcAttributionWidth (map) {
  // slightly less than the width of the map
  return (map.getSize().x - 20) + 'px';
}

export function setEsriAttribution (map) {
  if (map.attributionControl && !map.attributionControl._esriAttributionAdded) {
    map.attributionControl.setPrefix('Leaflet | Powered by Esri');

    var hoverAttributionStyle = document.createElement('style');
    hoverAttributionStyle.type = 'text/css';
    hoverAttributionStyle.innerHTML = '.esri-truncated-attribution:hover {' +
      'white-space: normal;'
    '}';

    document.getElementsByTagName('head')[0].appendChild(hoverAttributionStyle);
    L.DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution:hover');

    // define a new css class in JS to trim attribution into a single line
    var attributionStyle = document.createElement('style');
    attributionStyle.type = 'text/css';
    attributionStyle.innerHTML = '.esri-truncated-attribution {' +
      'vertical-align: -3px;' +
      'white-space: nowrap;' +
      'overflow: hidden;' +
      'text-overflow: "john";' +
      'display: inline-block;' +
      'transition: 0s white-space;' +
      'transition-delay: 1s;' +
      'max-width:' + L.esri.Util.calcAttributionWidth(map) +';'
    '}';

    document.getElementsByTagName('head')[0].appendChild(attributionStyle);
    L.DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution');

    // update the width used to truncate when the map itself is resized
    map.on('resize', function (e) {
      map.attributionControl._container.style.maxWidth = L.esri.Util.calcAttributionWidth(e.target);
    });

    map.attributionControl._esriAttributionAdded = true;
  }
}

export function _getAttributionData (url, map) {
  jsonp(url, {}, L.Util.bind(function (error, attributions) {
    if (error) { return; }
    map._esriAttributions = [];
    for (var c = 0; c < attributions.contributors.length; c++) {
      var contributor = attributions.contributors[c];

      for (var i = 0; i < contributor.coverageAreas.length; i++) {
        var coverageArea = contributor.coverageAreas[i];
        var southWest = L.latLng(coverageArea.bbox[0], coverageArea.bbox[1]);
        var northEast = L.latLng(coverageArea.bbox[2], coverageArea.bbox[3]);
        map._esriAttributions.push({
          attribution: contributor.attribution,
          score: coverageArea.score,
          bounds: L.latLngBounds(southWest, northEast),
          minZoom: coverageArea.zoomMin,
          maxZoom: coverageArea.zoomMax
        });
      }
    }

    map._esriAttributions.sort(function (a, b) {
      return b.score - a.score;
    });

    // pass the same argument as the map's 'moveend' event
    var obj = { target: map };
    _updateMapAttribution(obj);
  }, this));
}

export function _updateMapAttribution (evt) {
  var map = evt.target;
  var oldAttributions = map._esriAttributions;

  if (map && map.attributionControl && oldAttributions) {
    var newAttributions = '';
    var bounds = map.getBounds();
    var wrappedBounds = L.latLngBounds(
      bounds.getSouthWest().wrap(),
      bounds.getNorthEast().wrap()
    );
    var zoom = map.getZoom();

    for (var i = 0; i < oldAttributions.length; i++) {
      var attribution = oldAttributions[i];
      var text = attribution.attribution;

      if (!newAttributions.match(text) && attribution.bounds.intersects(wrappedBounds) && zoom >= attribution.minZoom && zoom <= attribution.maxZoom) {
        newAttributions += (', ' + text);
      }
    }

    newAttributions = newAttributions.substr(2);
    var attributionElement = map.attributionControl._container.querySelector('.esri-dynamic-attribution');

    attributionElement.innerHTML = newAttributions;
    attributionElement.style.maxWidth = calcAttributionWidth(map);

    map.fire('attributionupdated', {
      attribution: newAttributions
    });
  }
}

export var Util = {
  shallowClone: shallowClone,
  warn: warn,
  cleanUrl: cleanUrl,
  isArcgisOnline: isArcgisOnline,
  geojsonTypeToArcGIS: geojsonTypeToArcGIS,
  responseToFeatureCollection: responseToFeatureCollection,
  geojsonToArcGIS: geojsonToArcGIS,
  arcgisToGeoJSON: arcgisToGeoJSON,
  boundsToExtent: boundsToExtent,
  extentToBounds: extentToBounds,
  calcAttributionWidth: calcAttributionWidth,
  setEsriAttribution: setEsriAttribution,
  _getAttributionData: _getAttributionData,
  _updateMapAttribution: _updateMapAttribution
};

export default Util;
<commit_msg>definitely ellipsis<commit_after>import L from 'leaflet';
import { jsonp } from './Request';
import {
  geojsonToArcGIS as g2a,
  arcgisToGeoJSON as a2g
} from 'arcgis-to-geojson-utils';

export function geojsonToArcGIS (geojson, idAttr) {
  return g2a(geojson, idAttr);
}

export function arcgisToGeoJSON (arcgis, idAttr) {
  return a2g(arcgis, idAttr);
}

// shallow object clone for feature properties and attributes
// from http://jsperf.com/cloning-an-object/2
export function shallowClone (obj) {
  var target = {};
  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      target[i] = obj[i];
    }
  }
  return target;
}

// convert an extent (ArcGIS) to LatLngBounds (Leaflet)
export function extentToBounds (extent) {
  var sw = L.latLng(extent.ymin, extent.xmin);
  var ne = L.latLng(extent.ymax, extent.xmax);
  return L.latLngBounds(sw, ne);
}

// convert an LatLngBounds (Leaflet) to extent (ArcGIS)
export function boundsToExtent (bounds) {
  bounds = L.latLngBounds(bounds);
  return {
    'xmin': bounds.getSouthWest().lng,
    'ymin': bounds.getSouthWest().lat,
    'xmax': bounds.getNorthEast().lng,
    'ymax': bounds.getNorthEast().lat,
    'spatialReference': {
      'wkid': 4326
    }
  };
}

export function responseToFeatureCollection (response, idAttribute) {
  var objectIdField;

  if (idAttribute) {
    objectIdField = idAttribute;
  } else if (response.objectIdFieldName) {
    objectIdField = response.objectIdFieldName;
  } else if (response.fields) {
    for (var j = 0; j <= response.fields.length - 1; j++) {
      if (response.fields[j].type === 'esriFieldTypeOID') {
        objectIdField = response.fields[j].name;
        break;
      }
    }
  } else {
    objectIdField = 'OBJECTID';
  }

  var featureCollection = {
    type: 'FeatureCollection',
    features: []
  };
  var features = response.features || response.results;
  if (features.length) {
    for (var i = features.length - 1; i >= 0; i--) {
      var feature = arcgisToGeoJSON(features[i], objectIdField);
      featureCollection.features.push(feature);
    }
  }

  return featureCollection;
}

  // trim url whitespace and add a trailing slash if needed
export function cleanUrl (url) {
  // trim leading and trailing spaces, but not spaces inside the url
  url = L.Util.trim(url);

  // add a trailing slash to the url if the user omitted it
  if (url[url.length - 1] !== '/') {
    url += '/';
  }

  return url;
}

export function isArcgisOnline (url) {
  /* hosted feature services can emit geojson natively. */
  return (/\.arcgis\.com.*?FeatureServer/g).test(url);
}

export function geojsonTypeToArcGIS (geoJsonType) {
  var arcgisGeometryType;
  switch (geoJsonType) {
    case 'Point':
      arcgisGeometryType = 'esriGeometryPoint';
      break;
    case 'MultiPoint':
      arcgisGeometryType = 'esriGeometryMultipoint';
      break;
    case 'LineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'MultiLineString':
      arcgisGeometryType = 'esriGeometryPolyline';
      break;
    case 'Polygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
    case 'MultiPolygon':
      arcgisGeometryType = 'esriGeometryPolygon';
      break;
  }

  return arcgisGeometryType;
}

export function warn () {
  if (console && console.warn) {
    console.warn.apply(console, arguments);
  }
}

export function calcAttributionWidth (map) {
  // slightly less than the width of the map
  return (map.getSize().x - 20) + 'px';
}

export function setEsriAttribution (map) {
  if (map.attributionControl && !map.attributionControl._esriAttributionAdded) {
    map.attributionControl.setPrefix('Leaflet | Powered by Esri');

    var hoverAttributionStyle = document.createElement('style');
    hoverAttributionStyle.type = 'text/css';
    hoverAttributionStyle.innerHTML = '.esri-truncated-attribution:hover {' +
      'white-space: normal;'
    '}';

    document.getElementsByTagName('head')[0].appendChild(hoverAttributionStyle);
    L.DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution:hover');

    // define a new css class in JS to trim attribution into a single line
    var attributionStyle = document.createElement('style');
    attributionStyle.type = 'text/css';
    attributionStyle.innerHTML = '.esri-truncated-attribution {' +
      'vertical-align: -3px;' +
      'white-space: nowrap;' +
      'overflow: hidden;' +
      'text-overflow: ellipsis;' +
      'display: inline-block;' +
      'transition: 0s white-space;' +
      'transition-delay: 1s;' +
      'max-width:' + L.esri.Util.calcAttributionWidth(map) +';'
    '}';

    document.getElementsByTagName('head')[0].appendChild(attributionStyle);
    L.DomUtil.addClass(map.attributionControl._container, 'esri-truncated-attribution');

    // update the width used to truncate when the map itself is resized
    map.on('resize', function (e) {
      map.attributionControl._container.style.maxWidth = L.esri.Util.calcAttributionWidth(e.target);
    });

    map.attributionControl._esriAttributionAdded = true;
  }
}

export function _getAttributionData (url, map) {
  jsonp(url, {}, L.Util.bind(function (error, attributions) {
    if (error) { return; }
    map._esriAttributions = [];
    for (var c = 0; c < attributions.contributors.length; c++) {
      var contributor = attributions.contributors[c];

      for (var i = 0; i < contributor.coverageAreas.length; i++) {
        var coverageArea = contributor.coverageAreas[i];
        var southWest = L.latLng(coverageArea.bbox[0], coverageArea.bbox[1]);
        var northEast = L.latLng(coverageArea.bbox[2], coverageArea.bbox[3]);
        map._esriAttributions.push({
          attribution: contributor.attribution,
          score: coverageArea.score,
          bounds: L.latLngBounds(southWest, northEast),
          minZoom: coverageArea.zoomMin,
          maxZoom: coverageArea.zoomMax
        });
      }
    }

    map._esriAttributions.sort(function (a, b) {
      return b.score - a.score;
    });

    // pass the same argument as the map's 'moveend' event
    var obj = { target: map };
    _updateMapAttribution(obj);
  }, this));
}

export function _updateMapAttribution (evt) {
  var map = evt.target;
  var oldAttributions = map._esriAttributions;

  if (map && map.attributionControl && oldAttributions) {
    var newAttributions = '';
    var bounds = map.getBounds();
    var wrappedBounds = L.latLngBounds(
      bounds.getSouthWest().wrap(),
      bounds.getNorthEast().wrap()
    );
    var zoom = map.getZoom();

    for (var i = 0; i < oldAttributions.length; i++) {
      var attribution = oldAttributions[i];
      var text = attribution.attribution;

      if (!newAttributions.match(text) && attribution.bounds.intersects(wrappedBounds) && zoom >= attribution.minZoom && zoom <= attribution.maxZoom) {
        newAttributions += (', ' + text);
      }
    }

    newAttributions = newAttributions.substr(2);
    var attributionElement = map.attributionControl._container.querySelector('.esri-dynamic-attribution');

    attributionElement.innerHTML = newAttributions;
    attributionElement.style.maxWidth = calcAttributionWidth(map);

    map.fire('attributionupdated', {
      attribution: newAttributions
    });
  }
}

export var Util = {
  shallowClone: shallowClone,
  warn: warn,
  cleanUrl: cleanUrl,
  isArcgisOnline: isArcgisOnline,
  geojsonTypeToArcGIS: geojsonTypeToArcGIS,
  responseToFeatureCollection: responseToFeatureCollection,
  geojsonToArcGIS: geojsonToArcGIS,
  arcgisToGeoJSON: arcgisToGeoJSON,
  boundsToExtent: boundsToExtent,
  extentToBounds: extentToBounds,
  calcAttributionWidth: calcAttributionWidth,
  setEsriAttribution: setEsriAttribution,
  _getAttributionData: _getAttributionData,
  _updateMapAttribution: _updateMapAttribution
};

export default Util;
<|endoftext|>


<commit_before>var a404 = function () {
    //Main Background
    var a404 = document.createElement('div');
    a404.style.position = 'absolute';
    a404.style.top = '0';
    a404.style.left = '0';
    a404.style.width = '100%';
    a404.style.height = '100%';
    a404.style.background = 'url("http://assets-9gag-fun.9cache.com/s/fab0aa49/9513ffa5939495f655f7ab8edb7f40ce59feb032/static/dist/web6/img/404/bg.gif") center center no-repeat';
    a404.style.backgroundSize = 'cover';
    a404.style.zIndex = '1500';
    a404.style.opacity = '.2';

    document.body.appendChild(a404);

    //Texts Container
    var a404MessageContainer = document.createElement('div');
    a404MessageContainer.style.position = 'absolute';
    a404MessageContainer.style.textAlign = 'center';
    a404MessageContainer.style.width = '100%';
    a404MessageContainer.style.top = '50%';
    a404MessageContainer.style.transform = 'translateY(-50%)';
    a404MessageContainer.style.zIndex = '1501';

    //Texts
    //H1
    var a404H1 = document.createElement('h1');
    a404H1.innerHTML = '404';
    a404H1.style.fontSize = '144px';
    a404H1.style.fontWeight = '100';
    a404H1.style.marginBottom = '16px';
    a404H1.style.color = '#ffffff';
    a404MessageContainer.appendChild(a404H1);

    //H2
    var a404H2 = document.createElement('h2');
    a404H2.innerHTML = 'There\'s Nothing Here.';
    a404H2.style.marginBottom = '24px';
    a404H2.style.color = '#ffffff';
    a404MessageContainer.appendChild(a404H2);

    document.body.appendChild(a404MessageContainer);
};

anything.prototype.a404 = a404;<commit_msg>fix style<commit_after>var a404 = function () {
    //Main Background
    var a404 = document.createElement('div');
    a404.style.position = 'absolute';
    a404.style.top = '0';
    a404.style.left = '0';
    a404.style.width = '100%';
    a404.style.height = '100%';
    a404.style.background = 'url("http://assets-9gag-fun.9cache.com/s/fab0aa49/9513ffa5939495f655f7ab8edb7f40ce59feb032/static/dist/web6/img/404/bg.gif") center center no-repeat';
    a404.style.backgroundSize = 'cover';
    a404.style.zIndex = '1500';
    a404.style.opacity = '.2';

    document.body.appendChild(a404);

    //Texts Container
    var a404MessageContainer = document.createElement('div');
    a404MessageContainer.style.position = 'absolute';
    a404MessageContainer.style.textAlign = 'center';
    a404MessageContainer.style.width = '100%';
    a404MessageContainer.style.top = '50%';
    a404MessageContainer.style.transform = 'translateY(-50%)';
    a404MessageContainer.style.zIndex = '1501';

    //Texts
    //H1
    var a404H1 = document.createElement('h1');
    a404H1.innerHTML = '404';
    a404H1.style.fontSize = '144px';
    a404H1.style.fontWeight = '100';
    a404H1.style.marginBottom = '16px';
    a404H1.style.color = '#ffffff';
    a404MessageContainer.appendChild(a404H1);

    //H2
    var a404H2 = document.createElement('h2');
    a404H2.innerHTML = 'There\'s Nothing Here.';
    a404H2.style.marginBottom = '24px';
    a404H2.style.color = '#ffffff';
    a404H2.style.fontSize = '30px';
    a404H2.style.fontWeight = '100';
    a404MessageContainer.appendChild(a404H2);

    document.body.appendChild(a404MessageContainer);
};

anything.prototype.a404 = a404;<|endoftext|>


<commit_before>hqDefine('hqwebapp/js/ui_elements/ui-element-key-val-list', [
    'jquery',
    'underscore',
    'hqwebapp/js/main',
    'hqwebapp/js/ui_elements/ui-element-input-map',
], function (
    $,
    _,
    hqMain,
    uiInputMap
) {
    'use strict';
    var module = {};

    var KeyValList = function (guid, modalTitle, subTitle, placeholders, maxDisplay) {
        var that = this;
        hqMain.eventize(this);
        this.placeholders = placeholders;
        this.ui = $('
');
        this.value = {};
        this.translated_value = {};
        this.edit = true;
        this.modal_id = 'enumModal-' + guid;
        this.modal_title = modalTitle
        this.sub_title = subTitle ? '
' + subTitle + '
' : ''
        this.max_display = maxDisplay

        this.$edit_view = $('
');
        this.$noedit_view = $('
');
        this.$formatted_view = $('<input type="hidden" />');
        this.$modal_trigger = $('').html(' ' + django.gettext('Edit'));

        // Create new modal controller for this element
        var $enumModal = $('
');
        var $modalDialog = $('
');
        var $modalContent = $('
');

        $modalContent.prepend('
×
'
            + this.modal_title + '
' + this.sub_title + '
');
        var $modal_form = $('<form class="form-horizontal hq-enum-editor" action="" />'),
            $modal_body = $('
');
        $modal_body.append($('<fieldset />'));
        $modal_body.append(' ' +
            django.gettext('Add Item') + '');

        $modal_form.append($modal_body);
        $modal_form.append('
<button class="btn btn-primary" data-dismiss="modal">' +
            django.gettext('Done') + '</button>
');
        $modalContent.append($modal_form);
        $modalDialog.append($modalContent);
        $enumModal.append($modalDialog);

        $('#hq-content').append($enumModal);

        $('#' + this.modal_id).on('hide.bs.modal', function () {
            var $inputMap = $(this).find('form .hq-input-map'),
                pairs = {};
            for (var i = 0; i < $inputMap.length; i++) {
                var key = $($inputMap[i]).find('.enum-key').val(),
                    mapVal = $($inputMap[i]).find('.enum-value').val();
                if (key !== undefined) {
                    pairs[key] = mapVal.toString();
                }
            }
            that.val(pairs);
            that.fire('change');
        });

        $('#' + this.modal_id + ' a').click(function () {
            if ($(this).attr('data-enum-action') === 'add') {
                $(this).parent().parent().find('fieldset').append(uiInputMap.new(true, placeholders).ui);
                $(this).parent().parent().find('fieldset input.enum-key').last().focus();
            }
            if (!$(this).attr('data-dismiss'))
                return false;
        });

        this.setEdit(this.edit);
    };
    KeyValList.prototype = {
        val: function (original_pairs, translated_pairs) {
            if (original_pairs === undefined) {
                return this.value;
            } else {
                var $modal_fields = $('#' + this.modal_id + ' form fieldset');
                $modal_fields.text('');
                this.$noedit_view.text('');
                this.$edit_view.html(django.gettext('Click Edit to Add Values'));

                this.value = original_pairs;
                if (translated_pairs !== undefined) {
                    this.translated_value = translated_pairs;
                }
                this.$formatted_view.val(JSON.stringify(this.value));
                if (!_.isEmpty(this.value)) {
                    this.$edit_view.text('');
                }
                let i = 0;
                for (var key in this.value) {
                    $modal_fields.append(uiInputMap.new(true, this.placeholders).val(key, this.value[key], this.translated_value[key]).ui);
                    if (this.max_display === undefined || i < this.max_display) {
                        this.$edit_view.append(uiInputMap.new(true, this.placeholders).val(key, this.value[key], this.translated_value[key]).setEdit(false).$noedit_view);
                    } else if (i === this.max_display) {
                        this.$edit_view.append('
…
');
                    }
                    i++;
                }
            }

        },
        setEdit: function (edit) {
            this.edit = edit;
            this.$edit_view.detach();
            this.$noedit_view.detach();
            this.$modal_trigger.detach();
            if (this.edit) {
                this.$edit_view.appendTo(this.ui);
                this.$modal_trigger.appendTo(this.ui);
                this.$formatted_view.appendTo(this.ui);
            } else {
                this.$noedit_view.appendTo(this.ui);
            }
            return this;
        },
    };

    module.new = function (guid, modalTitle, subTitle, placeholders, maxDisplay) {
        return new KeyValList(guid, modalTitle, subTitle, placeholders, maxDisplay);
    };

    return module;

});
<commit_msg>Add missing semicolons;<commit_after>hqDefine('hqwebapp/js/ui_elements/ui-element-key-val-list', [
    'jquery',
    'underscore',
    'hqwebapp/js/main',
    'hqwebapp/js/ui_elements/ui-element-input-map',
], function (
    $,
    _,
    hqMain,
    uiInputMap
) {
    'use strict';
    var module = {};

    var KeyValList = function (guid, modalTitle, subTitle, placeholders, maxDisplay) {
        var that = this;
        hqMain.eventize(this);
        this.placeholders = placeholders;
        this.ui = $('
');
        this.value = {};
        this.translated_value = {};
        this.edit = true;
        this.modal_id = 'enumModal-' + guid;
        this.modal_title = modalTitle;
        this.sub_title = subTitle ? '
' + subTitle + '
' : '';
        this.max_display = maxDisplay;

        this.$edit_view = $('
');
        this.$noedit_view = $('
');
        this.$formatted_view = $('<input type="hidden" />');
        this.$modal_trigger = $('').html(' ' + django.gettext('Edit'));

        // Create new modal controller for this element
        var $enumModal = $('
');
        var $modalDialog = $('
');
        var $modalContent = $('
');

        $modalContent.prepend('
×
'
            + this.modal_title + '
' + this.sub_title + '
');
        var $modal_form = $('<form class="form-horizontal hq-enum-editor" action="" />'),
            $modal_body = $('
');
        $modal_body.append($('<fieldset />'));
        $modal_body.append(' ' +
            django.gettext('Add Item') + '');

        $modal_form.append($modal_body);
        $modal_form.append('
<button class="btn btn-primary" data-dismiss="modal">' +
            django.gettext('Done') + '</button>
');
        $modalContent.append($modal_form);
        $modalDialog.append($modalContent);
        $enumModal.append($modalDialog);

        $('#hq-content').append($enumModal);

        $('#' + this.modal_id).on('hide.bs.modal', function () {
            var $inputMap = $(this).find('form .hq-input-map'),
                pairs = {};
            for (var i = 0; i < $inputMap.length; i++) {
                var key = $($inputMap[i]).find('.enum-key').val(),
                    mapVal = $($inputMap[i]).find('.enum-value').val();
                if (key !== undefined) {
                    pairs[key] = mapVal.toString();
                }
            }
            that.val(pairs);
            that.fire('change');
        });

        $('#' + this.modal_id + ' a').click(function () {
            if ($(this).attr('data-enum-action') === 'add') {
                $(this).parent().parent().find('fieldset').append(uiInputMap.new(true, placeholders).ui);
                $(this).parent().parent().find('fieldset input.enum-key').last().focus();
            }
            if (!$(this).attr('data-dismiss'))
                return false;
        });

        this.setEdit(this.edit);
    };
    KeyValList.prototype = {
        val: function (original_pairs, translated_pairs) {
            if (original_pairs === undefined) {
                return this.value;
            } else {
                var $modal_fields = $('#' + this.modal_id + ' form fieldset');
                $modal_fields.text('');
                this.$noedit_view.text('');
                this.$edit_view.html(django.gettext('Click Edit to Add Values'));

                this.value = original_pairs;
                if (translated_pairs !== undefined) {
                    this.translated_value = translated_pairs;
                }
                this.$formatted_view.val(JSON.stringify(this.value));
                if (!_.isEmpty(this.value)) {
                    this.$edit_view.text('');
                }
                let i = 0;
                for (var key in this.value) {
                    $modal_fields.append(uiInputMap.new(true, this.placeholders).val(key, this.value[key], this.translated_value[key]).ui);
                    if (this.max_display === undefined || i < this.max_display) {
                        this.$edit_view.append(uiInputMap.new(true, this.placeholders).val(key, this.value[key], this.translated_value[key]).setEdit(false).$noedit_view);
                    } else if (i === this.max_display) {
                        this.$edit_view.append('
…
');
                    }
                    i++;
                }
            }

        },
        setEdit: function (edit) {
            this.edit = edit;
            this.$edit_view.detach();
            this.$noedit_view.detach();
            this.$modal_trigger.detach();
            if (this.edit) {
                this.$edit_view.appendTo(this.ui);
                this.$modal_trigger.appendTo(this.ui);
                this.$formatted_view.appendTo(this.ui);
            } else {
                this.$noedit_view.appendTo(this.ui);
            }
            return this;
        },
    };

    module.new = function (guid, modalTitle, subTitle, placeholders, maxDisplay) {
        return new KeyValList(guid, modalTitle, subTitle, placeholders, maxDisplay);
    };

    return module;

});
<|endoftext|>