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


/**
 * @requires OpenLayers/Control/DrawFeature.js
 * @requires OpenLayers/Handler/Point.js
 * @requires OpenLayers/Handler/Path.js
 * @requires OpenLayers/Handler/Polygon.js
 * @requires OpenLayers/Util/preciseRound.js
 */

/**
 * Class: OpenLayers.Control.Draw
 * The Draw control contains controllers for drawing point, line or polygon features on a vector layer when active.
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */

OpenLayers.Control.Draw = OpenLayers.Class(OpenLayers.Control, {
	layer: null,
	widget: null,
	div: null,
	cnt: null,
    styleMap: null,
	drawControls: {},
	features: [],
    wgs84: null,
    measuresPrecisionDegrees: 5,
    JSONDataStorageUrl: null,
    savedState: {
        url: null,
        features: []
    },
    measures: {
        wrapper: null,
        lon: {
            label: null,
            data: null
        },
        lat: {
            label: null,
            data: null
        },
        length: {
            label: null,
            data: null
        },
        area: {
            label: null,
            data: null
        }
    },
    measuresUpdatingAllowed: true,
    allowMeasuresUpdating: function () {
        this.measuresUpdatingAllowed = true;
    },
    denyMeasuresUpdating: function () {
        this.measuresUpdatingAllowed = false;
    },
    showLabelEditorPopup: function (evt) {
        var popup;
        var feature = evt.feature;
        var that = this;
        if (!feature.popup) {
          popup = new OpenLayers.Popup.FramedSideAnchored(
            "nk-feature-label", 
            feature.geometry.getBounds().getCenterLonLat(),
            null,
            '<span class="label-text">' + feature.data.label + '</span>', //generatePopupMarkup(feature),
            null, 
            false, 
            null, //onPopupClose
            {x: 0, y: -25},
            'user-marker'
          );

          popup.autoSize = true;
          popup.panMapIfOutOfView = false;
          feature.popup = popup;
          popup.feature = feature;
          map.addPopup(popup);
          popup.show();

          popup.setContentHTML('');

          label = document.createElement('label'); 
          label.setAttribute('for', 'feature-label');
          label.innerHTML = OpenLayers.Lang.translate('Add text');
          popup.contentDiv.appendChild(label);

          popup.input = document.createElement('input');
          popup.input.setAttribute('type', 'text');
          popup.input.setAttribute('id', 'feature-label');
          if (feature.attributes && feature.attributes.label) {
            popup.input.setAttribute('value', feature.attributes.label);
          }
          popup.contentDiv.appendChild(popup.input);

          popup.okButton = document.createElement('button');
          popup.okButton.setAttribute('class', 'update-feature-label');
          popup.okButton.innerHTML = OpenLayers.Lang.translate('Update');

          popup.addLabel = function () {
            var undoBuffer;

            that.drawControls['label'].undoBuffer = that.drawControls['label'].undoBuffer || [];
            undoBuffer = that.drawControls['label'].undoBuffer;
            undoBuffer.push({'previousLabel': popup.feature.attributes.label || '', 'feature': popup.feature})

            popup.feature.attributes.label = this.input.value || '';
            popup.feature.layer.drawFeature(popup.feature);

            that.removeLabelEditorPopup(popup);
          };

          popup.removePopup = function () {
            that.removeLabelEditorPopup(popup);
          };

          OpenLayers.Event.observe(popup.okButton, 'click', function (evt) {
            popup.addLabel(); 
            return false;
          });
          popup.contentDiv.appendChild(popup.okButton);

          popup.cancelButton = document.createElement('button');
          popup.cancelButton.setAttribute('class', 'cancel-feature-label');
          popup.cancelButton.innerHTML = OpenLayers.Lang.translate('Cancel');
          OpenLayers.Event.observe(popup.cancelButton, 'click', popup.removePopup);
          popup.contentDiv.appendChild(popup.cancelButton);

          OpenLayers.Element.addClass(popup.contentDiv, 'edit-popup-content');
          popup.updateSize();

          popup.input.focus();
        }
    },
    removeLabelEditorPopup: function (evt) {
        var popup, 
            feature;

        feature = evt.feature || evt;
        if (feature.popup) {
            popup = feature.popup;
            if (popup.cancelButton) {
                OpenLayers.Event.stopObservingElement(popup.cancelButton);
                popup.cancelButton.parentNode.removeChild(popup.cancelButton);
                popup.cancelButton = null;
                delete popup.cancelButton;
            }
            if (popup.okButton) {
                OpenLayers.Event.stopObservingElement(popup.okButton);
                popup.okButton.parentNode.removeChild(popup.okButton);
                popup.okButton = null;
                delete popup.okButton;
            }
            if (popup.input) {
                popup.input.parentNode.removeChild(popup.input);
                popup.input = null;
                delete popup.input;
            }
            popup.setContentHTML('');
            if (popup.feature) {
                popup.feature = null;
                delete popup.feature;
            }

            popup.destroy();

            popup = null;
            feature.popup = null;
            delete feature.popup;
        } else {
        //    console.log('no feature');
        }

    },
    tools: {
        icons: {
            point: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon point"><circle cx="32" cy="32" r="16" /></svg>',
            line: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon line"><path class="stroked" fill="none" d="M 45.454545,9.8181818 17.272727,23.090909 53.090909,42.727273 5.2727273,58" /></svg>',
            polygon: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon area"><path class="stroked semitransparent" d="M 27.090909,6.9090906 49.818186,5.9999997 31.000004,31.636365 56.545458,57.636366 7.454545,58.909093 l 0,-26.363637 z"/></svg>',
            label: '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" class="icon text" preserveAspectRatio="xMidYMid meet"><path d="M13.16,0l0.176,3.727H12.89c-0.086-0.656-0.203-1.125-0.352-1.406c-0.242-0.453-0.564-0.787-0.967-1.002S10.64,0.996,9.984,0.996H7.746v12.141c0,0.977,0.105,1.586,0.316,1.828c0.297,0.328,0.754,0.492,1.371,0.492h0.551v0.434H3.246v-0.434h0.562c0.672,0,1.148-0.203,1.43-0.609c0.172-0.25,0.258-0.82,0.258-1.711V0.996h-1.91c-0.742,0-1.27,0.055-1.582,0.164C1.598,1.309,1.25,1.594,0.961,2.016S0.5,3.008,0.445,3.727H0L0.188,0H13.16z"/></svg>'
        },
        handlers: {
            point: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.point.activate();
                OpenLayers.Element.addClass(this.tools.buttons.point, 'active');
                this.activeDrawControl = 'point';
                this.resetMeasures();
                this.showPointMeasures();
            },
            line: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.line.activate();

                this.drawControls.line.handler.layer.events.register('featureadded', this, this.allowMeasuresUpdating);
                OpenLayers.Element.addClass(this.tools.buttons.line, 'active');
                this.activeDrawControl = 'line';
                this.resetMeasures();
                this.showLineMeasures();
            },
            polygon: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.polygon.activate();
                this.drawControls.polygon.handler.layer.events.register('featureadded', this, this.allowMeasuresUpdating);
                OpenLayers.Element.addClass(this.tools.buttons.polygon, 'active');
                this.activeDrawControl = 'polygon';
                this.resetMeasures();
                this.showAreaMeasures();
            },
            label: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.label.activate();
                OpenLayers.Element.addClass(this.tools.buttons.label, 'active');
                this.activeDrawControl = 'label';
                this.layer.events.register('featureselected', this, this.showLabelEditorPopup);
                this.layer.events.register('featureunselected', this, this.removeLabelEditorPopup);

            },
            undo: function (evt) {
                var feature,
                    control,
                    sketch,
                    pointIndex,
                    lastLabelChange;

                control = this.drawControls[this.activeDrawControl];
                this.resetMeasures();

                if (this.activeDrawControl === 'label' && control.undoBuffer && control.undoBuffer.length > 0) {
                    lastLabelChange = control.undoBuffer.pop();
                    lastLabelChange.feature.attributes.label = lastLabelChange.previousLabel;
                    lastLabelChange.feature.layer.drawFeature(lastLabelChange.feature);
                } else {
                    // is there an unfinished sketch present?
                    if (control.handler && control.handler.getSketch) {
                        sketch = control.handler.getSketch();
                        if (sketch && !!sketch.geometry) {
                            // sketch exists
                            if (control.handler.getCurrentPointIndex) {
                                pointIndex = control.handler.getCurrentPointIndex();
                                if (pointIndex > 1) {
                                    // sketch contains undoable points: undo last point
                                    control.undo();
                                    return true;
                                } else {
                                    // sketch contains only one point: cancel sketch
                                    control.cancel();
                                }
                            }
                        }
                    }
                    feature = this.features.pop();
                    if (feature) {
                        feature.destroy();
                        feature = null;
                    }
                }
            },
            save: function (evt) {
                var geoJSONData,
                    request;

                geoJSONData = (new OpenLayers.Format.GeoJSON()).write(this.features);

                $.support.cors = true;
                request = $.ajax({
                    url: this.JSONDataStorageUrl,
                    type: 'POST',
                    data: geoJSONData,
                    crossDomain: true,
                    context: this,
                    success: function (response, statusText, jqXHR) {
                        var url,
                            features;

                        if (response.indexOf('http') === 0) {
                            url = response.replace(/\r\n/g, '');
                            this.savedState.url = url;

                            while (this.features.length > 0) {
                                this.features.pop().destroy();
                            }
                            this.features = [];
                            this.hideControls();
                        }
                    },
                    error: function () {
                    },
                    complete: function (response, status) {
                    }
                });
            }
        }     
    },
    resetMeasures: function () {
        this.measures.lon.data.innerHTML = '-';
        this.measures.lat.data.innerHTML = '-';
        this.measures['length'].data.innerHTML = '-';
        this.measures.area.data.innerHTML = '-';
    },
    showPointMeasures: function () {
        OpenLayers.Element.addClass(this.measures.wrapper, 'point');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'line');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'area');
    },
    showLineMeasures: function () {
        OpenLayers.Element.removeClass(this.measures.wrapper, 'point');
        OpenLayers.Element.addClass(this.measures.wrapper, 'line');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'area');
        this.measures.length.label.innerHTML = OpenLayers.Lang.translate('Length');
    },
    showAreaMeasures: function () {
        OpenLayers.Element.removeClass(this.measures.wrapper, 'point');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'line');
        OpenLayers.Element.addClass(this.measures.wrapper, 'area');
        this.measures.length.label.innerHTML = OpenLayers.Lang.translate('Circumference');
    },
	initialize: function (options) {
		OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.wgs84 = new OpenLayers.Projection("EPSG:4326");
        this.title = OpenLayers.Lang.translate('Drawing tool'); 
	},

	addFeature: function (feature) {
		this.features.push(feature);
        this.measuresUpdatingAllowed = false;
	},

	setMap: function (map) {
		var key,
			self = this,
			drawControlOptions,
            layerOptions;

		OpenLayers.Control.prototype.setMap.apply(this, [map]);

        layerOptions = {'visibility': false};
        if (this.styleMap) {
            layerOptions.styleMap = this.styleMap;
        }
		this.layer = new OpenLayers.Layer.Vector(OpenLayers.Lang.translate('Drawing'), layerOptions);
		this.map.addLayer(this.layer);

		drawControlOptions = {featureAdded: OpenLayers.Function.bind(self.addFeature, self)};
        this.drawControls.point = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Point, drawControlOptions);
        this.drawControls.line = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Path, drawControlOptions);
        this.drawControls.polygon = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Polygon, drawControlOptions);
        this.drawControls.label = new OpenLayers.Control.SelectFeature(this.layer);

        this.layer.events.register('sketchmodified', this, this.updateMeasures);


        for (key in this.drawControls) {
        	if (this.drawControls.hasOwnProperty(key)) {
            	this.map.addControl(this.drawControls[key]);
        	}
        }
	},
    updateMeasures: function (evt) {
        var lonLat,
            length,
            area,
            east,
            west,
            north,
            south;

        lonLat = new OpenLayers.LonLat([evt.vertex.x, evt.vertex.y]);
        lonLat.transform(this.map.getProjection(), this.wgs84);
        north = OpenLayers.Lang.translate('N');
        south = OpenLayers.Lang.translate('S');
        east = OpenLayers.Lang.translate('E');
        west = OpenLayers.Lang.translate('V');
        this.measures.lon.data.innerHTML = Math.abs(OpenLayers.Util.preciseRound(lonLat.lon, this.measuresPrecisionDegrees)) + '° ' + ((lonLat.lon > 0) ? east : west);
        this.measures.lon.data.setAttribute('title', lonLat.lon + '° ' + ((lonLat.lon > 0) ? east : west));
        this.measures.lat.data.innerHTML = Math.abs(OpenLayers.Util.preciseRound(lonLat.lat, this.measuresPrecisionDegrees)) + '° ' + ((lonLat.lat > 0) ? north : south);
        this.measures.lat.data.setAttribute('title', lonLat.lat + '° ' + ((lonLat.lat > 0) ? north : south));

        if (this.measuresUpdatingAllowed) {
            length = evt.feature.geometry.getLength();
            this.measures['length'].data.innerHTML = (length > 1000) ? OpenLayers.Util.preciseRound(length / 1000, 2) + ' km' : OpenLayers.Util.preciseRound(length, 2) + ' m';
            this.measures['length'].data.setAttribute('title', length + ' m');

            area = evt.feature.geometry.getArea();
            this.measures.area.data.innerHTML = (area > 1000000) ? OpenLayers.Util.preciseRound(area / 1000000, 2) + ' km²' : OpenLayers.Util.preciseRound(area, 2) + ' m²';
            this.measures.area.data.setAttribute('title', area + ' m²');
        }

    },<commit_msg>added nautical miles to Draw tool. TODO: should this be visible only on sea charts?<commit_after>/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the 2-clause BSD license.
 * See license.txt in the OpenLayers distribution or repository for the
 * full text of the license. */


/**
 * @requires OpenLayers/Control/DrawFeature.js
 * @requires OpenLayers/Handler/Point.js
 * @requires OpenLayers/Handler/Path.js
 * @requires OpenLayers/Handler/Polygon.js
 * @requires OpenLayers/Util/preciseRound.js
 */

/**
 * Class: OpenLayers.Control.Draw
 * The Draw control contains controllers for drawing point, line or polygon features on a vector layer when active.
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */

OpenLayers.Control.Draw = OpenLayers.Class(OpenLayers.Control, {
	layer: null,
	widget: null,
	div: null,
	cnt: null,
    styleMap: null,
	drawControls: {},
	features: [],
    wgs84: null,
    measuresPrecisionDegrees: 5,
    JSONDataStorageUrl: null,
    savedState: {
        url: null,
        features: []
    },
    measures: {
        wrapper: null,
        lon: {
            label: null,
            data: null
        },
        lat: {
            label: null,
            data: null
        },
        length: {
            label: null,
            data: null
        },
        area: {
            label: null,
            data: null
        }
    },
    measuresUpdatingAllowed: true,
    allowMeasuresUpdating: function () {
        this.measuresUpdatingAllowed = true;
    },
    denyMeasuresUpdating: function () {
        this.measuresUpdatingAllowed = false;
    },
    showLabelEditorPopup: function (evt) {
        var popup;
        var feature = evt.feature;
        var that = this;
        if (!feature.popup) {
          popup = new OpenLayers.Popup.FramedSideAnchored(
            "nk-feature-label", 
            feature.geometry.getBounds().getCenterLonLat(),
            null,
            '<span class="label-text">' + feature.data.label + '</span>', //generatePopupMarkup(feature),
            null, 
            false, 
            null, //onPopupClose
            {x: 0, y: -25},
            'user-marker'
          );

          popup.autoSize = true;
          popup.panMapIfOutOfView = false;
          feature.popup = popup;
          popup.feature = feature;
          map.addPopup(popup);
          popup.show();

          popup.setContentHTML('');

          label = document.createElement('label'); 
          label.setAttribute('for', 'feature-label');
          label.innerHTML = OpenLayers.Lang.translate('Add text');
          popup.contentDiv.appendChild(label);

          popup.input = document.createElement('input');
          popup.input.setAttribute('type', 'text');
          popup.input.setAttribute('id', 'feature-label');
          if (feature.attributes && feature.attributes.label) {
            popup.input.setAttribute('value', feature.attributes.label);
          }
          popup.contentDiv.appendChild(popup.input);

          popup.okButton = document.createElement('button');
          popup.okButton.setAttribute('class', 'update-feature-label');
          popup.okButton.innerHTML = OpenLayers.Lang.translate('Update');

          popup.addLabel = function () {
            var undoBuffer;

            that.drawControls['label'].undoBuffer = that.drawControls['label'].undoBuffer || [];
            undoBuffer = that.drawControls['label'].undoBuffer;
            undoBuffer.push({'previousLabel': popup.feature.attributes.label || '', 'feature': popup.feature})

            popup.feature.attributes.label = this.input.value || '';
            popup.feature.layer.drawFeature(popup.feature);

            that.removeLabelEditorPopup(popup);
          };

          popup.removePopup = function () {
            that.removeLabelEditorPopup(popup);
          };

          OpenLayers.Event.observe(popup.okButton, 'click', function (evt) {
            popup.addLabel(); 
            return false;
          });
          popup.contentDiv.appendChild(popup.okButton);

          popup.cancelButton = document.createElement('button');
          popup.cancelButton.setAttribute('class', 'cancel-feature-label');
          popup.cancelButton.innerHTML = OpenLayers.Lang.translate('Cancel');
          OpenLayers.Event.observe(popup.cancelButton, 'click', popup.removePopup);
          popup.contentDiv.appendChild(popup.cancelButton);

          OpenLayers.Element.addClass(popup.contentDiv, 'edit-popup-content');
          popup.updateSize();

          popup.input.focus();
        }
    },
    removeLabelEditorPopup: function (evt) {
        var popup, 
            feature;

        feature = evt.feature || evt;
        if (feature.popup) {
            popup = feature.popup;
            if (popup.cancelButton) {
                OpenLayers.Event.stopObservingElement(popup.cancelButton);
                popup.cancelButton.parentNode.removeChild(popup.cancelButton);
                popup.cancelButton = null;
                delete popup.cancelButton;
            }
            if (popup.okButton) {
                OpenLayers.Event.stopObservingElement(popup.okButton);
                popup.okButton.parentNode.removeChild(popup.okButton);
                popup.okButton = null;
                delete popup.okButton;
            }
            if (popup.input) {
                popup.input.parentNode.removeChild(popup.input);
                popup.input = null;
                delete popup.input;
            }
            popup.setContentHTML('');
            if (popup.feature) {
                popup.feature = null;
                delete popup.feature;
            }

            popup.destroy();

            popup = null;
            feature.popup = null;
            delete feature.popup;
        } else {
        //    console.log('no feature');
        }

    },
    tools: {
        icons: {
            point: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon point"><circle cx="32" cy="32" r="16" /></svg>',
            line: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon line"><path class="stroked" fill="none" d="M 45.454545,9.8181818 17.272727,23.090909 53.090909,42.727273 5.2727273,58" /></svg>',
            polygon: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64" preserveAspectRatio="xMidYMid meet" viewBox="0 0 64 64" class="icon area"><path class="stroked semitransparent" d="M 27.090909,6.9090906 49.818186,5.9999997 31.000004,31.636365 56.545458,57.636366 7.454545,58.909093 l 0,-26.363637 z"/></svg>',
            label: '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" class="icon text" preserveAspectRatio="xMidYMid meet"><path d="M13.16,0l0.176,3.727H12.89c-0.086-0.656-0.203-1.125-0.352-1.406c-0.242-0.453-0.564-0.787-0.967-1.002S10.64,0.996,9.984,0.996H7.746v12.141c0,0.977,0.105,1.586,0.316,1.828c0.297,0.328,0.754,0.492,1.371,0.492h0.551v0.434H3.246v-0.434h0.562c0.672,0,1.148-0.203,1.43-0.609c0.172-0.25,0.258-0.82,0.258-1.711V0.996h-1.91c-0.742,0-1.27,0.055-1.582,0.164C1.598,1.309,1.25,1.594,0.961,2.016S0.5,3.008,0.445,3.727H0L0.188,0H13.16z"/></svg>'
        },
        handlers: {
            point: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.point.activate();
                OpenLayers.Element.addClass(this.tools.buttons.point, 'active');
                this.activeDrawControl = 'point';
                this.resetMeasures();
                this.showPointMeasures();
            },
            line: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.line.activate();

                this.drawControls.line.handler.layer.events.register('featureadded', this, this.allowMeasuresUpdating);
                OpenLayers.Element.addClass(this.tools.buttons.line, 'active');
                this.activeDrawControl = 'line';
                this.resetMeasures();
                this.showLineMeasures();
            },
            polygon: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.polygon.activate();
                this.drawControls.polygon.handler.layer.events.register('featureadded', this, this.allowMeasuresUpdating);
                OpenLayers.Element.addClass(this.tools.buttons.polygon, 'active');
                this.activeDrawControl = 'polygon';
                this.resetMeasures();
                this.showAreaMeasures();
            },
            label: function (evt) {
                this.deactivateDrawControls();
                this.drawControls.label.activate();
                OpenLayers.Element.addClass(this.tools.buttons.label, 'active');
                this.activeDrawControl = 'label';
                this.layer.events.register('featureselected', this, this.showLabelEditorPopup);
                this.layer.events.register('featureunselected', this, this.removeLabelEditorPopup);

            },
            undo: function (evt) {
                var feature,
                    control,
                    sketch,
                    pointIndex,
                    lastLabelChange;

                control = this.drawControls[this.activeDrawControl];
                this.resetMeasures();

                if (this.activeDrawControl === 'label' && control.undoBuffer && control.undoBuffer.length > 0) {
                    lastLabelChange = control.undoBuffer.pop();
                    lastLabelChange.feature.attributes.label = lastLabelChange.previousLabel;
                    lastLabelChange.feature.layer.drawFeature(lastLabelChange.feature);
                } else {
                    // is there an unfinished sketch present?
                    if (control.handler && control.handler.getSketch) {
                        sketch = control.handler.getSketch();
                        if (sketch && !!sketch.geometry) {
                            // sketch exists
                            if (control.handler.getCurrentPointIndex) {
                                pointIndex = control.handler.getCurrentPointIndex();
                                if (pointIndex > 1) {
                                    // sketch contains undoable points: undo last point
                                    control.undo();
                                    return true;
                                } else {
                                    // sketch contains only one point: cancel sketch
                                    control.cancel();
                                }
                            }
                        }
                    }
                    feature = this.features.pop();
                    if (feature) {
                        feature.destroy();
                        feature = null;
                    }
                }
            },
            save: function (evt) {
                var geoJSONData,
                    request;

                geoJSONData = (new OpenLayers.Format.GeoJSON()).write(this.features);

                $.support.cors = true;
                request = $.ajax({
                    url: this.JSONDataStorageUrl,
                    type: 'POST',
                    data: geoJSONData,
                    crossDomain: true,
                    context: this,
                    success: function (response, statusText, jqXHR) {
                        var url,
                            features;

                        if (response.indexOf('http') === 0) {
                            url = response.replace(/\r\n/g, '');
                            this.savedState.url = url;

                            while (this.features.length > 0) {
                                this.features.pop().destroy();
                            }
                            this.features = [];
                            this.hideControls();
                        }
                    },
                    error: function () {
                    },
                    complete: function (response, status) {
                    }
                });
            }
        }     
    },
    resetMeasures: function () {
        this.measures.lon.data.innerHTML = '-';
        this.measures.lat.data.innerHTML = '-';
        this.measures['length'].data.innerHTML = '-';
        this.measures.area.data.innerHTML = '-';
    },
    showPointMeasures: function () {
        OpenLayers.Element.addClass(this.measures.wrapper, 'point');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'line');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'area');
    },
    showLineMeasures: function () {
        OpenLayers.Element.removeClass(this.measures.wrapper, 'point');
        OpenLayers.Element.addClass(this.measures.wrapper, 'line');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'area');
        this.measures.length.label.innerHTML = OpenLayers.Lang.translate('Length');
    },
    showAreaMeasures: function () {
        OpenLayers.Element.removeClass(this.measures.wrapper, 'point');
        OpenLayers.Element.removeClass(this.measures.wrapper, 'line');
        OpenLayers.Element.addClass(this.measures.wrapper, 'area');
        this.measures.length.label.innerHTML = OpenLayers.Lang.translate('Circumference');
    },
	initialize: function (options) {
		OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.wgs84 = new OpenLayers.Projection("EPSG:4326");
        this.title = OpenLayers.Lang.translate('Drawing tool'); 
	},

	addFeature: function (feature) {
		this.features.push(feature);
        this.measuresUpdatingAllowed = false;
	},

	setMap: function (map) {
		var key,
			self = this,
			drawControlOptions,
            layerOptions;

		OpenLayers.Control.prototype.setMap.apply(this, [map]);

        layerOptions = {'visibility': false};
        if (this.styleMap) {
            layerOptions.styleMap = this.styleMap;
        }
		this.layer = new OpenLayers.Layer.Vector(OpenLayers.Lang.translate('Drawing'), layerOptions);
		this.map.addLayer(this.layer);

		drawControlOptions = {featureAdded: OpenLayers.Function.bind(self.addFeature, self)};
        this.drawControls.point = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Point, drawControlOptions);
        this.drawControls.line = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Path, drawControlOptions);
        this.drawControls.polygon = new OpenLayers.Control.DrawFeature(this.layer, OpenLayers.Handler.Polygon, drawControlOptions);
        this.drawControls.label = new OpenLayers.Control.SelectFeature(this.layer);

        this.layer.events.register('sketchmodified', this, this.updateMeasures);


        for (key in this.drawControls) {
        	if (this.drawControls.hasOwnProperty(key)) {
            	this.map.addControl(this.drawControls[key]);
        	}
        }
	},
    updateMeasures: function (evt) {
        var lonLat,
            length,
            area,
            east,
            west,
            north,
            south;

        lonLat = new OpenLayers.LonLat([evt.vertex.x, evt.vertex.y]);
        lonLat.transform(this.map.getProjection(), this.wgs84);
        north = OpenLayers.Lang.translate('N');
        south = OpenLayers.Lang.translate('S');
        east = OpenLayers.Lang.translate('E');
        west = OpenLayers.Lang.translate('V');
        this.measures.lon.data.innerHTML = Math.abs(OpenLayers.Util.preciseRound(lonLat.lon, this.measuresPrecisionDegrees)) + '° ' + ((lonLat.lon > 0) ? east : west);
        this.measures.lon.data.setAttribute('title', lonLat.lon + '° ' + ((lonLat.lon > 0) ? east : west));
        this.measures.lat.data.innerHTML = Math.abs(OpenLayers.Util.preciseRound(lonLat.lat, this.measuresPrecisionDegrees)) + '° ' + ((lonLat.lat > 0) ? north : south);
        this.measures.lat.data.setAttribute('title', lonLat.lat + '° ' + ((lonLat.lat > 0) ? north : south));

        if (this.measuresUpdatingAllowed) {
            length = evt.feature.geometry.getLength();
            this.measures['length'].data.innerHTML = ((length > 1000) ? OpenLayers.Util.preciseRound(length / 1000, 2) + ' km' : OpenLayers.Util.preciseRound(length, 2) + ' m') 
                                                     + '<br/>' + OpenLayers.Util.preciseRound(length / 1852, 2) + ' nm';
            this.measures['length'].data.setAttribute('title', length + ' m');

            area = evt.feature.geometry.getArea();
            this.measures.area.data.innerHTML = (area > 1000000) ? OpenLayers.Util.preciseRound(area / 1000000, 2) + ' km²' : OpenLayers.Util.preciseRound(area, 2) + ' m²';
            this.measures.area.data.setAttribute('title', area + ' m²');
        }

    },
{'fraction_non_alphanumeric': 0.12715485486960365, 'fraction_numerical': 0.03244437895977604, 'mean_word_length': 1.8642808912896691, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 52, 'https://': 0, 'lorem ipsum': 0, 'www.': 8, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6319832', 'n_tokens_mistral': 10435, 'n_tokens_neox': 9281, 'n_words': 1503}