1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('Handlebars'), require('Bloodhound'), require('CodeMirror')) : 3 typeof define === 'function' && define.amd ? define(['exports', 'Handlebars', 'Bloodhound', 'CodeMirror'], factory) : 4 (global = global || self, factory(global.mapsvg = {}, global.Handlebars, global.Bloodhound, global.CodeMirror)); 5}(this, (function (exports, Handlebars, Bloodhound, CodeMirror) { 'use strict'; 6 7 Handlebars = Handlebars && Handlebars.hasOwnProperty('default') ? Handlebars['default'] : Handlebars; 8 Bloodhound = Bloodhound && Bloodhound.hasOwnProperty('default') ? Bloodhound['default'] : Bloodhound; 9 10 /** 11 * Global MapSVG class. It contains all other MapSVG classes and some static methods. 12 * @constructor 13 * @example 14 * var mapsvg = MapSVG.get(0); // get first map instance 15 * var mapsvg2 = MapSVG.get(1); // get second map instance 16 * var mapsvg3 = MapSVG.getById(123); // get map by ID 17 * 18 * var mapsvg = new MapSVG.Map("my-container",{ 19 * source: "/path/to/map.svg" 20 * }); 21 * 22 * var marker = new MapSVG.Marker({ 23 * location: location, 24 * mapsvg: mapsvg 25 * }); 26 * 27 * if(MapSVG.isPhone){ 28 * // do something special for mobile devices 29 * } 30 * 31 * 32 */ 33 var MapSVG = function () {}; 34 const $ = jQuery; 35 36 MapSVG.formBuilder = {}; 37 MapSVG.mediaUploader = {}; 38 39 if (typeof wp !== "undefined" && typeof wp.media !== "undefined") { 40 MapSVG.mediaUploader = wp.media({ 41 title: "Choose images", 42 button: { 43 text: "Choose images", 44 }, 45 multiple: true, 46 }); 47 } 48 49 /** 50 * Keeps loaded HBS templates 51 * @type {Array} 52 * @private 53 * @static 54 * @property 55 */ 56 MapSVG.templatesLoaded = {}; 57 58 /** 59 * Keeps URLs 60 * @type {Array} 61 * @private 62 * @static 63 * @property 64 */ 65 if (typeof mapsvg_paths !== "undefined") { 66 MapSVG.urls = mapsvg_paths; 67 } else { 68 MapSVG.urls = {}; 69 } 70 if (typeof ajaxurl !== "undefined") { 71 MapSVG.urls.ajaxurl = ajaxurl; 72 } 73 74 /** 75 * Keeps map instances 76 * @type {Array} 77 * @private 78 * @static 79 * @property 80 */ 81 MapSVG.instances = []; 82 83 MapSVG.userAgent = navigator.userAgent.toLowerCase(); 84 85 /** 86 * Determines if current device is touch-device 87 * @type {boolean} 88 * @static 89 * @property 90 */ 91 MapSVG.touchDevice = 92 "ontouchstart" in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; 93 // (MapSVG.userAgent.indexOf("ipad") > -1) || 94 // (MapSVG.userAgent.indexOf("iphone") > -1) || 95 // (MapSVG.userAgent.indexOf("ipod") > -1) || 96 // (MapSVG.userAgent.indexOf("android") > -1); 97 98 /** 99 * Determines if current device is iOS-device 100 * @type {boolean} 101 * @static 102 * @property 103 */ 104 MapSVG.ios = 105 MapSVG.userAgent.indexOf("ipad") > -1 || 106 MapSVG.userAgent.indexOf("iphone") > -1 || 107 MapSVG.userAgent.indexOf("ipod") > -1; 108 109 /** 110 * Determines if current device is Android-device 111 * @type {boolean} 112 * @static 113 * @property 114 */ 115 MapSVG.android = MapSVG.userAgent.indexOf("android"); 116 117 /** 118 * Determines if current device is mobile-device 119 * @type {boolean} 120 * @static 121 * @property 122 */ 123 MapSVG.isPhone = window.matchMedia("only screen and (max-width: 812px)").matches; 124 125 /** 126 * Keeps browser information 127 * @type {object} 128 * @static 129 * @property 130 */ 131 MapSVG.browser = {}; 132 MapSVG.browser.ie = 133 MapSVG.userAgent.indexOf("msie") > -1 || 134 MapSVG.userAgent.indexOf("trident") > -1 || 135 MapSVG.userAgent.indexOf("edge") > -1 136 ? {} 137 : false; 138 MapSVG.browser.firefox = MapSVG.userAgent.indexOf("firefox") > -1; 139 140 /** 141 * Contains device information 142 * @type {object} 143 * @static 144 * @property 145 */ 146 var ua = window.navigator.userAgent; 147 MapSVG.device = {}; 148 MapSVG.device.ios = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i); 149 MapSVG.device.android = !!ua.match(/Android/i); 150 151 if (!String.prototype.trim) { 152 String.prototype.trim = function () { 153 return this.replace(/^\s+|\s+$/g, ""); 154 }; 155 } 156 157 /** 158 * Converts mouse event object to x/y coordinates 159 * @param e 160 * @returns {{x: *, y: *}} 161 */ 162 MapSVG.mouseCoords = function (e) { 163 if (e.clientX) { 164 return { x: e.clientX + $(document).scrollLeft(), y: e.clientY + $(document).scrollTop() }; 165 } 166 if (e.pageX) { 167 return { x: e.pageX, y: e.pageY }; 168 } else if (MapSVG.touchDevice) { 169 e = e.originalEvent || e; 170 return e.touches && e.touches[0] 171 ? { x: e.touches[0].pageX, y: e.touches[0].pageY } 172 : { x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY }; 173 } 174 }; 175 176 /** 177 * Adds new instance of the map 178 * @param {MapSVG.Map} mapsvg 179 */ 180 MapSVG.addInstance = function (mapsvg) {
181 MapSVG.instances.push(mapsvg); 182 }; 183 184 MapSVG.get = function (index) { 185 return MapSVG.instances[index]; 186 }; 187 188 MapSVG.getById = function (id) { 189 var instance = MapSVG.instances.filter(function (i) { 190 return i.id == id; 191 }); 192 if (instance.length > 0) { 193 return instance[0]; 194 } 195 }; 196 197 MapSVG.getByContainerId = function (id) { 198 var instance = MapSVG.instances.filter(function (i) { 199 return i.$map.attr("id") == id; 200 }); 201 if (instance.length > 0) { 202 return instance[0]; 203 } 204 }; 205 206 MapSVG.extend = function (sub, base) { 207 sub.prototype = Object.create(base.prototype); 208 sub.prototype.constructor = sub; 209 }; 210 211 MapSVG.ucfirst = function (string) { 212 return string.charAt(0).toUpperCase() + string.slice(1); 213 }; 214 MapSVG.parseBoolean = function (string) { 215 switch (String(string).toLowerCase()) { 216 case "on": 217 case "true": 218 case "1": 219 case "yes": 220 case "y": 221 return true; 222 case "off": 223 case "false": 224 case "0": 225 case "no": 226 case "n": 227 return false; 228 default: 229 return undefined; 230 } 231 }; 232 MapSVG.isNumber = function (n) { 233 return !isNaN(parseFloat(n)) && isFinite(n); 234 }; 235 236 MapSVG.safeURL = function (url) { 237 if (url.indexOf("http://") == 0 || url.indexOf("https://") == 0) 238 url = "//" + url.split("://").pop(); 239 return url.replace(/^.*\/\/[^\/]+/, ""); 240 }; 241 242 MapSVG.convertToText = function (obj) { 243 //create an array that will later be joined into a string. 244 var string = []; 245 246 //is object 247 // Both arrays and objects seem to return "object" 248 // when typeof(obj) is applied to them. So instead 249 // I am checking to see if they have the property 250 // join, which normal objects don't have but 251 // arrays do. 252 if (obj === null) { 253 return null; 254 } 255 if (obj === undefined) { 256 return '""'; 257 } else if (typeof obj == "object" && obj.join == undefined) { 258 var prop; 259 for (prop in obj) { 260 if (obj.hasOwnProperty(prop)) { 261 var key = '"' + prop.replace(/\"/g, '\\"') + '"'; //prop.search(/[^a-zA-Z]+/) === -1 ? prop : ... 262 string.push(key + ": " + MapSVG.convertToText(obj[prop])); 263 } 264 } 265 return "{" + string.join(",") + "}"; 266 267 //is array 268 } else if (typeof obj == "object" && !(obj.join == undefined)) { 269 var prop; 270 for (prop in obj) { 271 string.push(MapSVG.convertToText(obj[prop])); 272 } 273 return "[" + string.join(",") + "]"; 274 275 //is function 276 } else if (typeof obj == "function") { 277 return obj.toString().replace("function anonymous", "function"); 278 // string.push(obj.toString().replace('function anonymous','function')); 279 280 //all other values can be done with JSON.stringify 281 } else { 282 return JSON.stringify(obj); 283 // var s = JSON.stringify(obj); 284 // string.push(s); 285 } 286 }; 287 288 // Create Element.remove() function if not exists 289 if (!("remove" in Element.prototype)) { 290 Element.prototype.remove = function () { 291 if (this.parentNode) { 292 this.parentNode.removeChild(this); 293 } 294 }; 295 } 296 297 Math.hypot = 298 Math.hypot || 299 function () { 300 var y = 0; 301 var length = arguments.length; 302 303 for (var i = 0; i < length; i++) { 304 if (arguments[i] === Infinity || arguments[i] === -Infinity) { 305 return Infinity; 306 } 307 y += arguments[i] * arguments[i]; 308 } 309 return Math.sqrt(y); 310 }; 311 SVGElement.prototype.getTransformToElement = 312 SVGElement.prototype.getTransformToElement || 313 function (toElement) { 314 return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM()); 315 }; 316 317 Map.prototype.toArray = function () { 318 return Array.from(this, ([name, value]) => value); 319 }; 320 321 MapSVG.ResizeSensor = class ResizeSensor { 322 constructor(element, callback) { 323 var _this = this; 324 _this.element = element; 325 _this.callback = callback; 326 var style = getComputedStyle(element); 327 var zIndex = parseInt(style.zIndex); 328 if (isNaN(zIndex)) { 329 zIndex = 0; 330 } 331 zIndex--; 332 _this.expand = document.createElement("div"); 333 _this.expand.style.position = "absolute";
334 _this.expand.style.left = "0px"; 335 _this.expand.style.top = "0px"; 336 _this.expand.style.right = "0px"; 337 _this.expand.style.bottom = "0px"; 338 _this.expand.style.overflow = "hidden"; 339 _this.expand.style.zIndex = zIndex.toString(); 340 _this.expand.style.visibility = "hidden"; 341 var expandChild = document.createElement("div"); 342 expandChild.style.position = "absolute"; 343 expandChild.style.left = "0px"; 344 expandChild.style.top = "0px"; 345 expandChild.style.width = "10000000px"; 346 expandChild.style.height = "10000000px"; 347 _this.expand.appendChild(expandChild); 348 _this.shrink = document.createElement("div"); 349 _this.shrink.style.position = "absolute"; 350 _this.shrink.style.left = "0px"; 351 _this.shrink.style.top = "0px"; 352 _this.shrink.style.right = "0px"; 353 _this.shrink.style.bottom = "0px"; 354 _this.shrink.style.overflow = "hidden"; 355 _this.shrink.style.zIndex = zIndex.toString(); 356 _this.shrink.style.visibility = "hidden"; 357 var shrinkChild = document.createElement("div"); 358 shrinkChild.style.position = "absolute"; 359 shrinkChild.style.left = "0px"; 360 shrinkChild.style.top = "0px"; 361 shrinkChild.style.width = "200%"; 362 shrinkChild.style.height = "200%"; 363 _this.shrink.appendChild(shrinkChild); 364 _this.element.appendChild(_this.expand); 365 _this.element.appendChild(_this.shrink); 366 var size = element.getBoundingClientRect(); 367 _this.currentWidth = size.width; 368 _this.currentHeight = size.height; 369 _this.setScroll(); 370 _this.expand.addEventListener("scroll", function () { 371 _this.onScroll(); 372 }); 373 _this.shrink.addEventListener("scroll", function () { 374 _this.onScroll(); 375 }); 376 } 377 onScroll() { 378 var _this = this; 379 var size = _this.element.getBoundingClientRect(); 380 var newWidth = size.width; 381 var newHeight = size.height; 382 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 383 _this.currentWidth = newWidth; 384 _this.currentHeight = newHeight; 385 _this.callback(); 386 } 387 this.setScroll(); 388 } 389 setScroll() { 390 this.expand.scrollLeft = 10000000; 391 this.expand.scrollTop = 10000000; 392 this.shrink.scrollLeft = 10000000; 393 this.shrink.scrollTop = 10000000; 394 } 395 destroy() { 396 this.expand.remove(); 397 this.shrink.remove(); 398 } 399 }; 400 401 MapSVG.nonce = function () { 402 return mapsvg_runtime_vars.nonce; 403 }; 404 405 /** 406 * Adds # hash at the beginning of HEX color value 407 * @param {String} color 408 * @returns {String} 409 * @private 410 */ 411 MapSVG.fixColorHash = (color) => { 412 const hexColorNoHash = new RegExp(/^([0-9a-f]{3}|[0-9a-f]{6})$/i); 413 if (color && color.match(hexColorNoHash) !== null) { 414 color = "#" + color; 415 } 416 return color; 417 }; 418 419 if (!Object.values) { 420 Object.values = function (object) { 421 return Object.keys(object).map(function (k) { 422 return object[k]; 423 }); 424 }; 425 } 426 427 window.MapSVG = MapSVG; 428 429 const defRegionTemplate = "<div>\n" + 430 " <p>This is the demo content of the <strong>Region %templateType%</strong>.</p>\n" + 431 ' <p>Click on the following link to edit the content of this window: <a href="#" class="mapsvg-template-link" data-template="%templateTypeSnake%Region">Menu > Templates > Region %templateType%</a>.</p>\n' + 432 ' <p>More information about templates: <a href="https://mapsvg.com/docs/map-editor/templates" target="_blank">mapsvg.com/docs/map-editor/templates</a></p>\n' + 433 "</div>\n" + 434 "<hr />\n\n" + 435 "<!-- Region fields are available in this template -->\n" + 436 "<h5>{{#if title}} {{title}} {{else}} {{id}} {{/if}}</h5>\n" + 437 "<p>Status: {{status_text}}</p>\n\n" + 438 "<!-- Show all linked Database Objects: -->\n" + 439 "{{#each objects}}\n\n" + 440 " <!-- DB Object are available inside of this block -->\n\n" + 441 " <h5>{{title}}</h5>\n" + 442 " <!-- When you need to render a field as HTML, use 3 curly braces instead of 2:-->\n" + 443 " <p>{{{description}}}</p>\n" + 444 " <p><em>{{location.address.formatted}}</em></p>\n\n" + 445 " <!-- Show all images: -->\n" + 446 " {{#each images}}\n" + 447 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 448 " <!-- are available in this block -->\n" + 449 ' <img src="{{thumbnail}}" />\n' + 450 " {{/each}}\n\n" + 451 "{{/each}}"; 452 const defDBTemplate = "<div>\n" + 453 " <p>This is the demo content of the <strong>DB Object %templateType%</strong>.</p>\n" + 454 ' <p>Click on the following link to edit the content of this window: <a href="#" class="mapsvg-template-link" data-template="%templateTypeSnake%Region">Menu > Templates > Region %templateType%</a>.</p>\n' + 455 ' <p>More information about templates: <a href="https://mapsvg.com/docs/map-editor/templates" target="_blank">mapsvg.com/docs/map-editor/templates</a></p>\n' + 456 "</div>\n" + 457 "<hr />\n\n" + 458 "<!-- DB Object fields are available in this template. -->\n" + 459 "<h5>{{title}}</h5>\n" + 460 "<!-- When you need to render a fields as HTML, use 3 curly braces instead of 2:-->\n" + 461 "<p>{{{description}}}</p>\n" + 462 "<p><em>{{location.address.formatted}}</em></p>\n\n" + 463 "<!-- Show all images: -->\n" + 464 "{{#each images}}\n" + 465 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 466 " <!-- are available in this block -->\n" + 467 ' <img src="{{thumbnail}}" />\n' + 468 "{{/each}}\n\n" + 469 "<!-- Show all linked Regions, comma-separated: -->\n" + 470 "<p> Regions: \n" + 471 " {{#each regions}}\n" + 472 " <!-- Region fields are available in this block -->\n" + 473 " {{#if title}}\n" + 474 " {{title}}\n" + 475 " {{else}}\n" + 476 " {{id}}\n" + 477 " {{/if}}{{#unless @last}}, {{/unless}}\n" + 478 " {{/each}}\n" + 479 "</p>"; 480 const dirItemItemTemplate = "<!-- If Directory Source = Database: DB Object fields are available in this template -->\n" + 481 "<!-- If Directory Source = Regions: Region fields are available in this template -->\n" + 482 "{{title}}"; 483 const DefaultOptions = { 484 source: "", 485 markerLastID: 0, 486 regionLastID: 0, 487 dataLastID: 1, 488 disableAll: false, 489 width: null, 490 height: null, 491 lockAspectRatio: false, 492 padding: { top: 0, left: 0, right: 0, bottom: 0 }, 493 maxWidth: null, 494 maxHeight: null, 495 minWidth: null, 496 minHeight: null, 497 loadingText: "Loading map...", 498 colorsIgnore: false, 499 colors: { 500 baseDefault: "#000000", 501 background: "#eeeeee", 502 selected: 40, 503 hover: 20, 504 directory: "#fafafa", 505 detailsView: "", 506 status: {},
507 clusters: "", 508 clustersBorders: "", 509 clustersText: "", 510 clustersHover: "", 511 clustersHoverBorders: "", 512 clustersHoverText: "", 513 markers: { 514 base: { opacity: 100, saturation: 100 }, 515 hovered: { opacity: 100, saturation: 100 }, 516 unhovered: { opacity: 40, saturation: 100 }, 517 active: { opacity: 100, saturation: 100 }, 518 inactive: { opacity: 40, saturation: 100 }, 519 }, 520 }, 521 regions: {}, 522 clustering: { on: false }, 523 viewBox: [], 524 cursor: "default", 525 manualRegions: false, 526 onClick: null, 527 mouseOver: null, 528 mouseOut: null, 529 menuOnClick: null, 530 beforeLoad: null, 531 afterLoad: null, 532 zoom: { 533 on: true, 534 limit: [0, 22], 535 delta: 2, 536 buttons: { on: true, location: "right" }, 537 mousewheel: true, 538 fingers: true, 539 hideSvg: false, 540 hideSvgZoomLevel: 7, 541 }, 542 scroll: { on: true, limit: false, background: false, spacebar: false }, 543 responsive: true, 544 tooltips: { on: false, position: "bottom-right", template: "", maxWidth: "", minWidth: 100 }, 545 popovers: { 546 on: false, 547 position: "top", 548 template: "", 549 centerOn: true, 550 width: 300, 551 maxWidth: 50, 552 maxHeight: 50, 553 }, 554 multiSelect: false, 555 regionStatuses: { 556 "1": { label: "Enabled", value: "1", color: "", disabled: false }, 557 "0": { label: "Disabled", value: "0", color: "", disabled: true }, 558 }, 559 events: { 560 afterLoad: "function(){\n" + 561 " // var mapsvg = this;\n" + 562 " // var regions = mapsvg.regions;\n" + 563 " // var dbObjects = mapsvg.database.getLoaded();\n" + 564 "}", 565 beforeLoad: "function(){\n" + 566 " // var mapsvg = this;\n" + 567 " // var settings = mapsvg.options;\n" + 568 " // console.log(settings);\n" + 569 "}", 570 databaseLoaded: "function (){\n" + 571 " // var mapsvg = this;\n" + 572 " // var dbObjects = mapsvg.database.getLoaded();\n" + 573 "}", 574 "click.region": "function (e, mapsvg){\n" + 575 " // var region = this;\n" + 576 " // console.log(region);\n" + 577 "}", 578 "mouseover.region": "function (e, mapsvg){\n" + 579 " // var region = this;\n" + 580 " // console.log(region);\n" + 581 "}", 582 "mouseout.region": "function (e, mapsvg){\n" + 583 " // var region = this;\n" + 584 " // console.log(region);\n" + 585 "}", 586 "click.marker": "function (e, mapsvg){\n" + 587 " // var marker = this;\n" + 588 " // console.log(marker);\n" + 589 "}", 590 "mouseover.marker": "function (e, mapsvg){\n" + 591 " // var marker = this;\n" + 592 " // console.log(marker);\n" + 593 "}", 594 "mouseout.marker": "function (e, mapsvg){\n" + 595 " // var marker = this;\n" + 596 " // console.log(marker);\n" + 597 "}", 598 "click.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 599 "mouseover.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 600 "mouseout.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 601 "shown.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 602 "closed.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 603 "closed.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 604 "shown.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 605 }, 606 css: "#mapsvg-map-%id% .mapsvg-tooltip {\n\n}\n" + 607 "#mapsvg-map-%id% .mapsvg-popover {\n\n}\n" + 608 "#mapsvg-map-%id% .mapsvg-details-container {\n\n}\n" + 609 "#mapsvg-map-%id% .mapsvg-directory-item {\n\n}\n" + 610 "#mapsvg-map-%id% .mapsvg-region-label {\n" + 611 " /* background-color: rgba(255,255,255,.6); */\n" + 612 " font-size: 11px;\n" + 613 " padding: 3px 5px;\n" + 614 " border-radius: 4px;\n" + 615 "}\n" + 616 "#mapsvg-map-%id% .mapsvg-marker-label {\n" + 617 " padding: 3px 5px;\n" + 618 " /*\n" + 619 " border-radius: 4px;\n" + 620 " background-color: white;\n" + 621 " margin-top: -4px;\n" + 622 " */\n}\n" + 623 "#mapsvg-map-%id% .mapsvg-filters-wrap {\n\n}\n" + 624 "\n\n\n\n\n\n", 625 templates: { 626 popoverRegion: defRegionTemplate 627 .replace(/%templateType%/g, "Popover") 628 .replace(/%templateTypeSnake%/g, "popover"), 629 popoverMarker: defDBTemplate 630 .replace(/%templateType%/g, "Popover") 631 .replace(/%templateTypeSnake%/g, "popover"), 632 tooltipRegion: "<!-- Region fields are available in this template -->\n{{id}} - {{title}}", 633 tooltipMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 634 directoryItem: dirItemItemTemplate, 635 directoryCategoryItem: '<!-- Available fields: "label", "value", "counter" -->\n<span class="mapsvg-category-label">{{label}}</span>\n<span class="mapsvg-category-counter">{{counter}}</span>\n<span class="mapsvg-chevron"></span>', 636 detailsView: defDBTemplate 637 .replace(/%templateType%/g, "Details View") 638 .replace(/%templateTypeSnake%/g, "detailsView"), 639 detailsViewRegion: defRegionTemplate 640 .replace(/%templateType%/g, "Details View") 641 .replace(/%templateTypeSnake%/g, "detailsView"), 642 labelMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 643 labelRegion: "<!-- Region fields are available in this template -->\n{{title}}", 644 labelLocation: "You are here!", 645 }, 646 choropleth: { 647 on: false, 648 source: "regions", 649 sourceFieldSelect: { 650 on: false, 651 variants: [], 652 }, 653 bubbleMode: false, 654 bubbleSize: { 655 min: 20, 656 max: 40, 657 }, 658 labels: { low: "low", high: "high" }, 659 colors: { lowRGB: null, highRGB: null, low: "#550000", high: "#ee0000", noData: "#333333" }, 660 min: 0, 661 max: 0, 662 coloring: { 663 mode: "gradient", 664 noData: { 665 color: "#999999", 666 description: "No data", 667 }, 668 gradient: { 669 colors: { 670 lowRGB: null, 671 highRGB: null, 672 diffRGB: null, 673 low: "#550000", 674 high: "#ee0000", 675 }, 676 labels: { 677 low: "low", 678 high: "high", 679 }, 680 values: { 681 min: null, 682 max: null, 683 maxAdjusted: null, 684 }, 685 }, 686 palette: { 687 outOfRange: { 688 color: "#ececec", 689 description: "Out of range", 690 }, 691 colors: [ 692 { 693 color: "#550000", 694 valueFrom: 0, 695 valueTo: 50, 696 description: "", 697 }, 698 ], 699 }, 700 legend: { 701 on: true, 702 layout: "vertical", 703 container: "bottom-left", 704 title: "Choropleth map", 705 text: "", 706 description: "", 707 width: "20%", 708 height: "20%", 709 }, 710 }, 711 }, 712 filters: { 713 on: true, 714 source: "database", 715 location: "header", 716 modalLocation: "map", 717 width: "100%", 718 hide: false, 719 showButtonText: "Filters", 720 clearButtonText: "Clear all",
721 clearButton: false, 722 searchButton: false, 723 searchButtonText: "Search", 724 padding: "", 725 }, 726 menu: { 727 on: false, 728 hideOnMobile: true, 729 location: "leftSidebar", 730 locationMobile: "leftSidebar", 731 search: false, 732 containerId: "", 733 searchPlaceholder: "Search...", 734 searchFallback: false, 735 source: "database", 736 showFirst: "map", 737 showMapOnClick: true, 738 minHeight: "400", 739 sortBy: "id", 740 sortDirection: "desc", 741 categories: { 742 on: false, 743 groupBy: "", 744 hideEmpty: true, 745 collapse: true, 746 collapseOther: true, 747 }, 748 clickActions: { 749 region: "default", 750 marker: "default", 751 directoryItem: { 752 triggerClick: true, 753 showPopover: false, 754 showDetails: true, 755 }, 756 }, 757 detailsViewLocation: "overDirectory", 758 noResultsText: "No results found", 759 filterout: { field: "", cond: "=", val: "" }, 760 }, 761 database: { 762 pagination: { 763 on: true, 764 perpage: 30, 765 next: "Next", 766 prev: "Prev.", 767 showIn: "directory", 768 }, 769 loadOnStart: true, 770 table: "", 771 }, 772 actions: { 773 map: { 774 afterLoad: { 775 selectRegion: false, 776 }, 777 }, 778 region: { 779 mouseover: { 780 showTooltip: false, 781 }, 782 click: { 783 addIdToUrl: false, 784 showDetails: true, 785 showDetailsFor: "region", 786 filterDirectory: false, 787 loadObjects: false, 788 showPopover: false, 789 showPopoverFor: "region", 790 goToLink: false, 791 linkField: "Region.link", 792 }, 793 touch: { 794 showPopover: false, 795 }, 796 }, 797 marker: { 798 mouseover: { 799 showTooltip: false, 800 }, 801 click: { 802 showDetails: true, 803 showPopover: false, 804 goToLink: false, 805 linkField: "Object.link", 806 }, 807 touch: { 808 showPopover: false, 809 }, 810 }, 811 directoryItem: { 812 click: { 813 showDetails: true, 814 showPopover: false, 815 goToLink: false, 816 selectRegion: true, 817 fireRegionOnClick: true, 818 linkField: "Object.link", 819 }, 820 hover: { 821 centerOnMarker: false, 822 }, 823 }, 824 }, 825 detailsView: { 826 location: "map", 827 containerId: "", 828 width: "100%", 829 mobileFullscreen: true, 830 }, 831 mobileView: { 832 labelMap: "Map", 833 labelList: "List", 834 labelClose: "Close", 835 }, 836 googleMaps: { 837 on: false, 838 apiKey: "", 839 loaded: false, 840 center: "auto", 841 type: "roadmap", 842 minZoom: 1, 843 style: "default", 844 styleJSON: [], 845 }, 846 groups: [], 847 floors: [], 848 layersControl: { 849 on: false, 850 position: "top-left", 851 label: "Show on map", 852 expanded: true, 853 maxHeight: "100%", 854 }, 855 floorsControl: { 856 on: false, 857 position: "top-left", 858 label: "Floors", 859 expanded: false, 860 maxHeight: "100%", 861 }, 862 containers: { 863 leftSidebar: { on: false, width: "250px" }, 864 rightSidebar: { on: false, width: "250px" }, 865 header: { on: true, height: "auto" }, 866 footer: { on: false, height: "auto" }, 867 }, 868 labelsMarkers: { on: false }, 869 labelsRegions: { on: false }, 870 svgFileVersion: 1, 871 fitMarkers: false, 872 fitMarkersOnStart: false, 873 fitSingleMarkerZoom: 20, 874 controls: { 875 location: "right", 876 zoom: true, 877 zoomReset: false, 878 userLocation: false, 879 previousMap: false, 880 }, 881 previousMapsIds: [], 882 }; 883 884 // TinyColor v1.4.1 885 // https://github.com/bgrins/TinyColor 886 // Brian Grinstead, MIT License 887 888 //(function(Math) { 889 890 var trimLeft = /^\s+/, 891 trimRight = /\s+$/, 892 tinyCounter = 0, 893 mathRound = Math.round, 894 mathMin = Math.min, 895 mathMax = Math.max, 896 mathRandom = Math.random; 897 898 function tinycolor(color, opts) { 899 color = color ? color : ""; 900 opts = opts || {}; 901 902 // If input is already a tinycolor, return itself 903 if (color instanceof tinycolor) { 904 return color; 905 } 906 // If we are called as a function, call using new instead 907 if (!(this instanceof tinycolor)) { 908 return new tinycolor(color, opts); 909 } 910 911 var rgb = inputToRGB(color); 912 (this._originalInput = color), 913 (this._r = rgb.r), 914 (this._g = rgb.g), 915 (this._b = rgb.b), 916 (this._a = rgb.a), 917 (this._roundA = mathRound(100 * this._a) / 100), 918 (this._format = opts.format || rgb.format); 919 this._gradientType = opts.gradientType; 920 921 // Don't let the range of [0,255] come back in [0,1]. 922 // Potentially lose a little bit of precision here, but will fix issues where 923 // .5 gets interpreted as half of the total, instead of half of 1 924 // If it was supposed to be 128, this was already taken care of b
vendor: 11,167 bytes, lines 924-1242
924y `inputToRgb` 925 if (this._r < 1) { 926 this._r = mathRound(this._r); 927 } 928 if (this._g < 1) { 929 this._g = mathRound(this._g); 930 } 931 if (this._b < 1) { 932 this._b = mathRound(this._b); 933 } 934 935 this._ok = rgb.ok; 936 this._tc_id = tinyCounter++; 937 } 938 939 tinycolor.prototype = { 940 isDark: function () { 941 return this.getBrightness() < 128; 942 }, 943 isLight: function () { 944 return !this.isDark(); 945 }, 946 isValid: function () { 947 return this._ok; 948 }, 949 getOriginalInput: function () { 950 return this._originalInput; 951 }, 952 getFormat: function () { 953 return this._format; 954 }, 955 getAlpha: function () { 956 return this._a; 957 }, 958 getBrightness: function () { 959 //http://www.w3.org/TR/AERT#color-contrast 960 var rgb = this.toRgb(); 961 return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; 962 }, 963 getLuminance: function () { 964 //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef 965 var rgb = this.toRgb(); 966 var RsRGB, GsRGB, BsRGB, R, G, B; 967 RsRGB = rgb.r / 255; 968 GsRGB = rgb.g / 255; 969 BsRGB = rgb.b / 255; 970 971 if (RsRGB <= 0.03928) { 972 R = RsRGB / 12.92; 973 } else { 974 R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); 975 } 976 if (GsRGB <= 0.03928) { 977 G = GsRGB / 12.92; 978 } else { 979 G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); 980 } 981 if (BsRGB <= 0.03928) { 982 B = BsRGB / 12.92; 983 } else { 984 B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); 985 } 986 return 0.2126 * R + 0.7152 * G + 0.0722 * B; 987 }, 988 setAlpha: function (value) { 989 this._a = boundAlpha(value); 990 this._roundA = mathRound(100 * this._a) / 100; 991 return this; 992 }, 993 toHsv: function () { 994 var hsv = rgbToHsv(this._r, this._g, this._b); 995 return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; 996 }, 997 toHsvString: function () { 998 var hsv = rgbToHsv(this._r, this._g, this._b); 999 var h = mathRound(hsv.h * 360), 1000 s = mathRound(hsv.s * 100), 1001 v = mathRound(hsv.v * 100); 1002 return this._a == 1 1003 ? "hsv(" + h + ", " + s + "%, " + v + "%)" 1004 : "hsva(" + h + ", " + s + "%, " + v + "%, " + this._roundA + ")"; 1005 }, 1006 toHsl: function () { 1007 var hsl = rgbToHsl(this._r, this._g, this._b); 1008 return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; 1009 }, 1010 toHslString: function () { 1011 var hsl = rgbToHsl(this._r, this._g, this._b); 1012 var h = mathRound(hsl.h * 360), 1013 s = mathRound(hsl.s * 100), 1014 l = mathRound(hsl.l * 100); 1015 return this._a == 1 1016 ? "hsl(" + h + ", " + s + "%, " + l + "%)" 1017 : "hsla(" + h + ", " + s + "%, " + l + "%, " + this._roundA + ")"; 1018 }, 1019 toHex: function (allow3Char) { 1020 return rgbToHex(this._r, this._g, this._b, allow3Char); 1021 }, 1022 toHexString: function (allow3Char) { 1023 return "#" + this.toHex(allow3Char); 1024 }, 1025 toHex8: function (allow4Char) { 1026 return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char); 1027 }, 1028 toHex8String: function (allow4Char) { 1029 return "#" + this.toHex8(allow4Char); 1030 }, 1031 toRgb: function () { 1032 return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a }; 1033 }, 1034 toRgbString: function () { 1035 return this._a == 1 1036 ? "rgb(" + 1037 mathRound(this._r) + 1038 ", " + 1039 mathRound(this._g) + 1040 ", " + 1041 mathRound(this._b) + 1042 ")" 1043 : "rgba(" + 1044 mathRound(this._r) + 1045 ", " + 1046 mathRound(this._g) + 1047 ", " + 1048 mathRound(this._b) + 1049 ", " + 1050 this._roundA + 1051 ")"; 1052 }, 1053 toPercentageRgb: function () { 1054 return { 1055 r: mathRound(bound01(this._r, 255) * 100) + "%", 1056 g: mathRound(bound01(this._g, 255) * 100) + "%", 1057 b: mathRound(bound01(this._b, 255) * 100) + "%", 1058 a: this._a, 1059 }; 1060 }, 1061 toPercentageRgbString: function () { 1062 return this._a == 1 1063 ? "rgb(" + 1064 mathRound(bound01(this._r, 255) * 100) + 1065 "%, " + 1066 mathRound(bound01(this._g, 255) * 100) + 1067 "%, " + 1068 mathRound(bound01(this._b, 255) * 100) + 1069 "%)" 1070 : "rgba(" + 1071 mathRound(bound01(this._r, 255) * 100) + 1072 "%, " + 1073 mathRound(bound01(this._g, 255) * 100) + 1074 "%, " + 1075 mathRound(bound01(this._b, 255) * 100) + 1076 "%, " + 1077 this._roundA + 1078 ")"; 1079 }, 1080 toName: function () { 1081 if (this._a === 0) { 1082 return "transparent"; 1083 } 1084 1085 if (this._a < 1) { 1086 return false; 1087 } 1088 1089 return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; 1090 }, 1091 toFilter: function (secondColor) { 1092 var hex8String = "#" + rgbaToArgbHex(this._r, this._g, this._b, this._a); 1093 var secondHex8String = hex8String; 1094 var gradientType = this._gradientType ? "GradientType = 1, " : ""; 1095 1096 if (secondColor) { 1097 var s = tinycolor(secondColor); 1098 secondHex8String = "#" + rgbaToArgbHex(s._r, s._g, s._b, s._a); 1099 } 1100 1101 return ( 1102 "progid:DXImageTransform.Microsoft.gradient(" + 1103 gradientType + 1104 "startColorstr=" + 1105 hex8String + 1106 ",endColorstr=" + 1107 secondHex8String + 1108 ")" 1109 ); 1110 }, 1111 toString: function (format) { 1112 var formatSet = !!format; 1113 format = format || this._format; 1114 1115 var formattedString = false; 1116 var hasAlpha = this._a < 1 && this._a >= 0; 1117 var needsAlphaFormat = 1118 !formatSet && 1119 hasAlpha && 1120 (format === "hex" || 1121 format === "hex6" || 1122 format === "hex3" || 1123 format === "hex4" || 1124 format === "hex8" || 1125 format === "name"); 1126 1127 if (needsAlphaFormat) { 1128 // Special case for "transparent", all other non-alpha formats 1129 // will return rgba when there is transparency. 1130 if (format === "name" && this._a === 0) { 1131 return this.toName(); 1132 } 1133 return this.toRgbString(); 1134 } 1135 if (format === "rgb") { 1136 formattedString = this.toRgbString(); 1137 } 1138 if (format === "prgb") { 1139 formattedString = this.toPercentageRgbString(); 1140 } 1141 if (format === "hex" || format === "hex6") { 1142 formattedString = this.toHexString(); 1143 } 1144 if (format === "hex3") { 1145 formattedString = this.toHexString(true); 1146 } 1147 if (format === "hex4") { 1148 formattedString = this.toHex8String(true); 1149 } 1150 if (format === "hex8") { 1151 formattedString = this.toHex8String(); 1152 } 1153 if (format === "name") { 1154 formattedString = this.toName(); 1155 } 1156 if (format === "hsl") { 1157 formattedString = this.toHslString(); 1158 } 1159 if (format === "hsv") { 1160 formattedString = this.toHsvString(); 1161 } 1162 1163 return formattedString || this.toHexString(); 1164 }, 1165 clone: function () { 1166 return tinycolor(this.toString()); 1167 }, 1168 1169 _applyModification: function (fn, args) { 1170 var color = fn.apply(null, [this].concat([].slice.call(args))); 1171 this._r = color._r; 1172 this._g = color._g; 1173 this._b = color._b; 1174 this.setAlpha(color._a); 1175 return this; 1176 }, 1177 lighten: function () { 1178 return this._applyModification(lighten, arguments); 1179 }, 1180 brighten: function () { 1181 return this._applyModification(brighten, arguments); 1182 }, 1183 darken: function () { 1184 return this._applyModification(darken, arguments); 1185 }, 1186 desaturate: function () { 1187 return this._applyModification(desaturate, arguments); 1188 }, 1189 saturate: function () { 1190 return this._applyModification(saturate, arguments); 1191 }, 1192 greyscale: function () { 1193 return this._applyModification(greyscale, arguments); 1194 }, 1195 spin: function () { 1196 return this._applyModification(spin, arguments); 1197 }, 1198 1199 _applyCombination: function (fn, args) { 1200 return fn.apply(null, [this].concat([].slice.call(args))); 1201 }, 1202 analogous: function () { 1203 return this._applyCombination(analogous, arguments); 1204 }, 1205 complement: function () { 1206 return this._applyCombination(complement, arguments); 1207 }, 1208 monochromatic: function () { 1209 return this._applyCombination(monochromatic, arguments); 1210 }, 1211 splitcomplement: function () { 1212 return this._applyCombination(splitcomplement, arguments); 1213 }, 1214 triad: function () { 1215 return this._applyCombination(triad, arguments); 1216 }, 1217 tetrad: function () { 1218 return this._applyCombination(tetrad, arguments); 1219 }, 1220 }; 1221 1222 // If input is an object, force 1 into "1.0" to handle ratios properly 1223 // String input requires "1.0" as input, so 1 will be treated as 1 1224 tinycolor.fromRatio = function (color, opts) { 1225 if (typeof color == "object") { 1226 var newColor = {}; 1227 for (var i in color) { 1228 if (color.hasOwnProperty(i)) { 1229 if (i === "a") { 1230 newColor[i] = color[i]; 1231 } else { 1232 newColor[i] = convertToPercentage(color[i]); 1233 } 1234 } 1235 } 1236 color = newColor; 1237 } 1238 1239 return tinycolor(color, opts); 1240 }; 1241 1242 // Given a string or object, convert that input to RGB
vendor: 8,705 bytes, lines 1243-1523
1243 // Possible string inputs: 1244 // 1245 // "red" 1246 // "#f00" or "f00" 1247 // "#ff0000" or "ff0000" 1248 // "#ff000000" or "ff000000" 1249 // "rgb 255 0 0" or "rgb (255, 0, 0)" 1250 // "rgb 1.0 0 0" or "rgb (1, 0, 0)" 1251 // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" 1252 // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" 1253 // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" 1254 // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" 1255 // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" 1256 // 1257 function inputToRGB(color) { 1258 var rgb = { r: 0, g: 0, b: 0 }; 1259 var a = 1; 1260 var s = null; 1261 var v = null; 1262 var l = null; 1263 var ok = false; 1264 var format = false; 1265 1266 if (typeof color == "string") { 1267 color = stringInputToObject(color); 1268 } 1269 1270 if (typeof color == "object") { 1271 if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) { 1272 rgb = rgbToRgb(color.r, color.g, color.b); 1273 ok = true; 1274 format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; 1275 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) { 1276 s = convertToPercentage(color.s); 1277 v = convertToPercentage(color.v); 1278 rgb = hsvToRgb(color.h, s, v); 1279 ok = true; 1280 format = "hsv"; 1281 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) { 1282 s = convertToPercentage(color.s); 1283 l = convertToPercentage(color.l); 1284 rgb = hslToRgb(color.h, s, l); 1285 ok = true; 1286 format = "hsl"; 1287 } 1288 1289 if (color.hasOwnProperty("a")) { 1290 a = color.a; 1291 } 1292 } 1293 1294 a = boundAlpha(a); 1295 1296 return { 1297 ok: ok, 1298 format: color.format || format, 1299 r: mathMin(255, mathMax(rgb.r, 0)), 1300 g: mathMin(255, mathMax(rgb.g, 0)), 1301 b: mathMin(255, mathMax(rgb.b, 0)), 1302 a: a, 1303 }; 1304 } 1305 1306 // Conversion Functions 1307 // -------------------- 1308 1309 // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: 1310 // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript> 1311 1312 // `rgbToRgb` 1313 // Handle bounds / percentage checking to conform to CSS color spec 1314 // <http://www.w3.org/TR/css3-color/> 1315 // *Assumes:* r, g, b in [0, 255] or [0, 1] 1316 // *Returns:* { r, g, b } in [0, 255] 1317 function rgbToRgb(r, g, b) { 1318 return { 1319 r: bound01(r, 255) * 255, 1320 g: bound01(g, 255) * 255, 1321 b: bound01(b, 255) * 255, 1322 }; 1323 } 1324 1325 // `rgbToHsl` 1326 // Converts an RGB color value to HSL. 1327 // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] 1328 // *Returns:* { h, s, l } in [0,1] 1329 function rgbToHsl(r, g, b) { 1330 r = bound01(r, 255); 1331 g = bound01(g, 255); 1332 b = bound01(b, 255); 1333 1334 var max = mathMax(r, g, b), 1335 min = mathMin(r, g, b); 1336 var h, 1337 s, 1338 l = (max + min) / 2; 1339 1340 if (max == min) { 1341 h = s = 0; // achromatic 1342 } else { 1343 var d = max - min; 1344 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 1345 switch (max) { 1346 case r: 1347 h = (g - b) / d + (g < b ? 6 : 0); 1348 break; 1349 case g: 1350 h = (b - r) / d + 2; 1351 break; 1352 case b: 1353 h = (r - g) / d + 4; 1354 break; 1355 } 1356 1357 h /= 6; 1358 } 1359 1360 return { h: h, s: s, l: l }; 1361 } 1362 1363 // `hslToRgb` 1364 // Converts an HSL color value to RGB. 1365 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] 1366 // *Returns:* { r, g, b } in the set [0, 255] 1367 function hslToRgb(h, s, l) { 1368 var r, g, b; 1369 1370 h = bound01(h, 360); 1371 s = bound01(s, 100); 1372 l = bound01(l, 100); 1373 1374 function hue2rgb(p, q, t) { 1375 if (t < 0) t += 1; 1376 if (t > 1) t -= 1; 1377 if (t < 1 / 6) return p + (q - p) * 6 * t; 1378 if (t < 1 / 2) return q; 1379 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; 1380 return p; 1381 } 1382 1383 if (s === 0) { 1384 r = g = b = l; // achromatic 1385 } else { 1386 var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 1387 var p = 2 * l - q; 1388 r = hue2rgb(p, q, h + 1 / 3); 1389 g = hue2rgb(p, q, h); 1390 b = hue2rgb(p, q, h - 1 / 3); 1391 } 1392 1393 return { r: r * 255, g: g * 255, b: b * 255 }; 1394 } 1395 1396 // `rgbToHsv` 1397 // Converts an RGB color value to HSV 1398 // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] 1399 // *Returns:* { h, s, v } in [0,1] 1400 function rgbToHsv(r, g, b) { 1401 r = bound01(r, 255); 1402 g = bound01(g, 255); 1403 b = bound01(b, 255); 1404 1405 var max = mathMax(r, g, b), 1406 min = mathMin(r, g, b); 1407 var h, 1408 s, 1409 v = max; 1410 1411 var d = max - min; 1412 s = max === 0 ? 0 : d / max; 1413 1414 if (max == min) { 1415 h = 0; // achromatic 1416 } else { 1417 switch (max) { 1418 case r: 1419 h = (g - b) / d + (g < b ? 6 : 0); 1420 break; 1421 case g: 1422 h = (b - r) / d + 2; 1423 break; 1424 case b: 1425 h = (r - g) / d + 4; 1426 break; 1427 } 1428 h /= 6; 1429 } 1430 return { h: h, s: s, v: v }; 1431 } 1432 1433 // `hsvToRgb` 1434 // Converts an HSV color value to RGB. 1435 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] 1436 // *Returns:* { r, g, b } in the set [0, 255] 1437 function hsvToRgb(h, s, v) { 1438 h = bound01(h, 360) * 6; 1439 s = bound01(s, 100); 1440 v = bound01(v, 100); 1441 1442 var i = Math.floor(h), 1443 f = h - i, 1444 p = v * (1 - s), 1445 q = v * (1 - f * s), 1446 t = v * (1 - (1 - f) * s), 1447 mod = i % 6, 1448 r = [v, q, p, p, t, v][mod], 1449 g = [t, v, v, q, p, p][mod], 1450 b = [p, p, t, v, v, q][mod]; 1451 1452 return { r: r * 255, g: g * 255, b: b * 255 }; 1453 } 1454 1455 // `rgbToHex` 1456 // Converts an RGB color to hex 1457 // Assumes r, g, and b are contained in the set [0, 255] 1458 // Returns a 3 or 6 character hex 1459 function rgbToHex(r, g, b, allow3Char) { 1460 var hex = [ 1461 pad2(mathRound(r).toString(16)), 1462 pad2(mathRound(g).toString(16)), 1463 pad2(mathRound(b).toString(16)), 1464 ]; 1465 1466 // Return a 3 character hex if possible 1467 if ( 1468 allow3Char && 1469 hex[0].charAt(0) == hex[0].charAt(1) && 1470 hex[1].charAt(0) == hex[1].charAt(1) && 1471 hex[2].charAt(0) == hex[2].charAt(1) 1472 ) { 1473 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); 1474 } 1475 1476 return hex.join(""); 1477 } 1478 1479 // `rgbaToHex` 1480 // Converts an RGBA color plus alpha transparency to hex 1481 // Assumes r, g, b are contained in the set [0, 255] and 1482 // a in [0, 1]. Returns a 4 or 8 character rgba hex 1483 function rgbaToHex(r, g, b, a, allow4Char) { 1484 var hex = [ 1485 pad2(mathRound(r).toString(16)), 1486 pad2(mathRound(g).toString(16)), 1487 pad2(mathRound(b).toString(16)), 1488 pad2(convertDecimalToHex(a)), 1489 ]; 1490 1491 // Return a 4 character hex if possible 1492 if ( 1493 allow4Char && 1494 hex[0].charAt(0) == hex[0].charAt(1) && 1495 hex[1].charAt(0) == hex[1].charAt(1) && 1496 hex[2].charAt(0) == hex[2].charAt(1) && 1497 hex[3].charAt(0) == hex[3].charAt(1) 1498 ) { 1499 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0); 1500 } 1501 1502 return hex.join(""); 1503 } 1504 1505 // `rgbaToArgbHex` 1506 // Converts an RGBA color to an ARGB Hex8 string 1507 // Rarely used, but required for "toFilter()" 1508 function rgbaToArgbHex(r, g, b, a) { 1509 var hex = [ 1510 pad2(convertDecimalToHex(a)), 1511 pad2(mathRound(r).toString(16)), 1512 pad2(mathRound(g).toString(16)), 1513 pad2(mathRound(b).toString(16)), 1514 ]; 1515 1516 return hex.join(""); 1517 } 1518 1519 // `equals` 1520 // Can be called with any tinycolor input 1521 tinycolor.equals = function (color1, color2) { 1522 if (!color1 || !color2) { 1523 return false;
vendor: 4,315 bytes, lines 1524-1661
1524 } 1525 return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); 1526 }; 1527 1528 tinycolor.random = function () { 1529 return tinycolor.fromRatio({ 1530 r: mathRandom(), 1531 g: mathRandom(), 1532 b: mathRandom(), 1533 }); 1534 }; 1535 1536 // Modification Functions 1537 // ---------------------- 1538 // Thanks to less.js for some of the basics here 1539 // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js> 1540 1541 function desaturate(color, amount) { 1542 amount = amount === 0 ? 0 : amount || 10; 1543 var hsl = tinycolor(color).toHsl(); 1544 hsl.s -= amount / 100; 1545 hsl.s = clamp01(hsl.s); 1546 return tinycolor(hsl); 1547 } 1548 1549 function saturate(color, amount) { 1550 amount = amount === 0 ? 0 : amount || 10; 1551 var hsl = tinycolor(color).toHsl(); 1552 hsl.s += amount / 100; 1553 hsl.s = clamp01(hsl.s); 1554 return tinycolor(hsl); 1555 } 1556 1557 function greyscale(color) { 1558 return tinycolor(color).desaturate(100); 1559 } 1560 1561 function lighten(color, amount) { 1562 amount = amount === 0 ? 0 : amount || 10; 1563 var hsl = tinycolor(color).toHsl(); 1564 hsl.l += amount / 100; 1565 hsl.l = clamp01(hsl.l); 1566 return tinycolor(hsl); 1567 } 1568 1569 function brighten(color, amount) { 1570 amount = amount === 0 ? 0 : amount || 10; 1571 var rgb = tinycolor(color).toRgb(); 1572 rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * -(amount / 100)))); 1573 rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * -(amount / 100)))); 1574 rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * -(amount / 100)))); 1575 return tinycolor(rgb); 1576 } 1577 1578 function darken(color, amount) { 1579 amount = amount === 0 ? 0 : amount || 10; 1580 var hsl = tinycolor(color).toHsl(); 1581 hsl.l -= amount / 100; 1582 hsl.l = clamp01(hsl.l); 1583 return tinycolor(hsl); 1584 } 1585 1586 // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. 1587 // Values outside of this range will be wrapped into this range. 1588 function spin(color, amount) { 1589 var hsl = tinycolor(color).toHsl(); 1590 var hue = (hsl.h + amount) % 360; 1591 hsl.h = hue < 0 ? 360 + hue : hue; 1592 return tinycolor(hsl); 1593 } 1594 1595 // Combination Functions 1596 // --------------------- 1597 // Thanks to jQuery xColor for some of the ideas behind these 1598 // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js> 1599 1600 function complement(color) { 1601 var hsl = tinycolor(color).toHsl(); 1602 hsl.h = (hsl.h + 180) % 360; 1603 return tinycolor(hsl); 1604 } 1605 1606 function triad(color) { 1607 var hsl = tinycolor(color).toHsl(); 1608 var h = hsl.h; 1609 return [ 1610 tinycolor(color), 1611 tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), 1612 tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }), 1613 ]; 1614 } 1615 1616 function tetrad(color) { 1617 var hsl = tinycolor(color).toHsl(); 1618 var h = hsl.h; 1619 return [ 1620 tinycolor(color), 1621 tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), 1622 tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), 1623 tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }), 1624 ]; 1625 } 1626 1627 function splitcomplement(color) { 1628 var hsl = tinycolor(color).toHsl(); 1629 var h = hsl.h; 1630 return [ 1631 tinycolor(color), 1632 tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }), 1633 tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l }), 1634 ]; 1635 } 1636 1637 function analogous(color, results, slices) { 1638 results = results || 6; 1639 slices = slices || 30; 1640 1641 var hsl = tinycolor(color).toHsl(); 1642 var part = 360 / slices; 1643 var ret = [tinycolor(color)]; 1644 1645 for (hsl.h = (hsl.h - ((part * results) >> 1) + 720) % 360; --results; ) { 1646 hsl.h = (hsl.h + part) % 360; 1647 ret.push(tinycolor(hsl)); 1648 } 1649 return ret; 1650 } 1651 1652 function monochromatic(color, results) { 1653 results = results || 6; 1654 var hsv = tinycolor(color).toHsv(); 1655 var h = hsv.h, 1656 s = hsv.s, 1657 v = hsv.v; 1658 var ret = []; 1659 var modification = 1 / results; 1660 1661 while (results--) {
vendor: 4,157 bytes, lines 1662-1770
1662 ret.push(tinycolor({ h: h, s: s, v: v })); 1663 v = (v + modification) % 1; 1664 } 1665 1666 return ret; 1667 } 1668 1669 // Utility Functions 1670 // --------------------- 1671 1672 tinycolor.mix = function (color1, color2, amount) { 1673 amount = amount === 0 ? 0 : amount || 50; 1674 1675 var rgb1 = tinycolor(color1).toRgb(); 1676 var rgb2 = tinycolor(color2).toRgb(); 1677 1678 var p = amount / 100; 1679 1680 var rgba = { 1681 r: (rgb2.r - rgb1.r) * p + rgb1.r, 1682 g: (rgb2.g - rgb1.g) * p + rgb1.g, 1683 b: (rgb2.b - rgb1.b) * p + rgb1.b, 1684 a: (rgb2.a - rgb1.a) * p + rgb1.a, 1685 }; 1686 1687 return tinycolor(rgba); 1688 }; 1689 1690 // Readability Functions 1691 // --------------------- 1692 // <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2) 1693 1694 // `contrast` 1695 // Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) 1696 tinycolor.readability = function (color1, color2) { 1697 var c1 = tinycolor(color1); 1698 var c2 = tinycolor(color2); 1699 return ( 1700 (Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / 1701 (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05) 1702 ); 1703 }; 1704 1705 // `isReadable` 1706 // Ensure that foreground and background color combinations meet WCAG2 guidelines. 1707 // The third argument is an optional Object. 1708 // the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA'; 1709 // the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'. 1710 // If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}. 1711 1712 // *Example* 1713 // tinycolor.isReadable("#000", "#111") => false 1714 // tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false 1715 tinycolor.isReadable = function (color1, color2, wcag2) { 1716 var readability = tinycolor.readability(color1, color2); 1717 var wcag2Parms, out; 1718 1719 out = false; 1720 1721 wcag2Parms = validateWCAG2Parms(wcag2); 1722 switch (wcag2Parms.level + wcag2Parms.size) { 1723 case "AAsmall": 1724 case "AAAlarge": 1725 out = readability >= 4.5; 1726 break; 1727 case "AAlarge": 1728 out = readability >= 3; 1729 break; 1730 case "AAAsmall": 1731 out = readability >= 7; 1732 break; 1733 } 1734 return out; 1735 }; 1736 1737 // `mostReadable` 1738 // Given a base color and a list of possible foreground or background 1739 // colors for that base, returns the most readable color. 1740 // Optionally returns Black or White if the most readable color is unreadable. 1741 // *Example* 1742 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" 1743 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" 1744 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" 1745 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" 1746 tinycolor.mostReadable = function (baseColor, colorList, args) { 1747 var bestColor = null; 1748 var bestScore = 0; 1749 var readability; 1750 var includeFallbackColors, level, size; 1751 args = args || {}; 1752 includeFallbackColors = args.includeFallbackColors; 1753 level = args.level; 1754 size = args.size; 1755 1756 for (var i = 0; i < colorList.length; i++) { 1757 readability = tinycolor.readability(baseColor, colorList[i]); 1758 if (readability > bestScore) { 1759 bestScore = readability; 1760 bestColor = tinycolor(colorList[i]); 1761 } 1762 } 1763 1764 if ( 1765 tinycolor.isReadable(baseColor, bestColor, { level: level, size: size }) || 1766 !includeFallbackColors 1767 ) { 1768 return bestColor; 1769 } else { 1770 args.includeFallbackColors = false;
vendor: 12,185 bytes, lines 1771-2144
1771 return tinycolor.mostReadable(baseColor, ["#fff", "#000"], args); 1772 } 1773 }; 1774 1775 // Big List of Colors 1776 // ------------------ 1777 // <http://www.w3.org/TR/css3-color/#svg-color> 1778 var names = (tinycolor.names = { 1779 aliceblue: "f0f8ff", 1780 antiquewhite: "faebd7", 1781 aqua: "0ff", 1782 aquamarine: "7fffd4", 1783 azure: "f0ffff", 1784 beige: "f5f5dc", 1785 bisque: "ffe4c4", 1786 black: "000", 1787 blanchedalmond: "ffebcd", 1788 blue: "00f", 1789 blueviolet: "8a2be2", 1790 brown: "a52a2a", 1791 burlywood: "deb887", 1792 burntsienna: "ea7e5d", 1793 cadetblue: "5f9ea0", 1794 chartreuse: "7fff00", 1795 chocolate: "d2691e", 1796 coral: "ff7f50", 1797 cornflowerblue: "6495ed", 1798 cornsilk: "fff8dc", 1799 crimson: "dc143c", 1800 cyan: "0ff", 1801 darkblue: "00008b", 1802 darkcyan: "008b8b", 1803 darkgoldenrod: "b8860b", 1804 darkgray: "a9a9a9", 1805 darkgreen: "006400", 1806 darkgrey: "a9a9a9", 1807 darkkhaki: "bdb76b", 1808 darkmagenta: "8b008b", 1809 darkolivegreen: "556b2f", 1810 darkorange: "ff8c00", 1811 darkorchid: "9932cc", 1812 darkred: "8b0000", 1813 darksalmon: "e9967a", 1814 darkseagreen: "8fbc8f", 1815 darkslateblue: "483d8b", 1816 darkslategray: "2f4f4f", 1817 darkslategrey: "2f4f4f", 1818 darkturquoise: "00ced1", 1819 darkviolet: "9400d3", 1820 deeppink: "ff1493", 1821 deepskyblue: "00bfff", 1822 dimgray: "696969", 1823 dimgrey: "696969", 1824 dodgerblue: "1e90ff", 1825 firebrick: "b22222", 1826 floralwhite: "fffaf0", 1827 forestgreen: "228b22", 1828 fuchsia: "f0f", 1829 gainsboro: "dcdcdc", 1830 ghostwhite: "f8f8ff", 1831 gold: "ffd700", 1832 goldenrod: "daa520", 1833 gray: "808080", 1834 green: "008000", 1835 greenyellow: "adff2f", 1836 grey: "808080", 1837 honeydew: "f0fff0", 1838 hotpink: "ff69b4", 1839 indianred: "cd5c5c", 1840 indigo: "4b0082", 1841 ivory: "fffff0", 1842 khaki: "f0e68c", 1843 lavender: "e6e6fa", 1844 lavenderblush: "fff0f5", 1845 lawngreen: "7cfc00", 1846 lemonchiffon: "fffacd", 1847 lightblue: "add8e6", 1848 lightcoral: "f08080", 1849 lightcyan: "e0ffff", 1850 lightgoldenrodyellow: "fafad2", 1851 lightgray: "d3d3d3", 1852 lightgreen: "90ee90", 1853 lightgrey: "d3d3d3", 1854 lightpink: "ffb6c1", 1855 lightsalmon: "ffa07a", 1856 lightseagreen: "20b2aa", 1857 lightskyblue: "87cefa", 1858 lightslategray: "789", 1859 lightslategrey: "789", 1860 lightsteelblue: "b0c4de", 1861 lightyellow: "ffffe0", 1862 lime: "0f0", 1863 limegreen: "32cd32", 1864 linen: "faf0e6", 1865 magenta: "f0f", 1866 maroon: "800000", 1867 mediumaquamarine: "66cdaa", 1868 mediumblue: "0000cd", 1869 mediumorchid: "ba55d3", 1870 mediumpurple: "9370db", 1871 mediumseagreen: "3cb371", 1872 mediumslateblue: "7b68ee", 1873 mediumspringgreen: "00fa9a", 1874 mediumturquoise: "48d1cc", 1875 mediumvioletred: "c71585", 1876 midnightblue: "191970", 1877 mintcream: "f5fffa", 1878 mistyrose: "ffe4e1", 1879 moccasin: "ffe4b5", 1880 navajowhite: "ffdead", 1881 navy: "000080", 1882 oldlace: "fdf5e6", 1883 olive: "808000", 1884 olivedrab: "6b8e23", 1885 orange: "ffa500", 1886 orangered: "ff4500", 1887 orchid: "da70d6", 1888 palegoldenrod: "eee8aa", 1889 palegreen: "98fb98", 1890 paleturquoise: "afeeee", 1891 palevioletred: "db7093", 1892 papayawhip: "ffefd5", 1893 peachpuff: "ffdab9", 1894 peru: "cd853f", 1895 pink: "ffc0cb", 1896 plum: "dda0dd", 1897 powderblue: "b0e0e6", 1898 purple: "800080", 1899 rebeccapurple: "663399", 1900 red: "f00", 1901 rosybrown: "bc8f8f", 1902 royalblue: "4169e1", 1903 saddlebrown: "8b4513", 1904 salmon: "fa8072", 1905 sandybrown: "f4a460", 1906 seagreen: "2e8b57", 1907 seashell: "fff5ee", 1908 sienna: "a0522d", 1909 silver: "c0c0c0", 1910 skyblue: "87ceeb", 1911 slateblue: "6a5acd", 1912 slategray: "708090", 1913 slategrey: "708090", 1914 snow: "fffafa", 1915 springgreen: "00ff7f", 1916 steelblue: "4682b4", 1917 tan: "d2b48c", 1918 teal: "008080", 1919 thistle: "d8bfd8", 1920 tomato: "ff6347", 1921 turquoise: "40e0d0", 1922 violet: "ee82ee", 1923 wheat: "f5deb3", 1924 white: "fff", 1925 whitesmoke: "f5f5f5", 1926 yellow: "ff0", 1927 yellowgreen: "9acd32", 1928 }); 1929 1930 // Make it easy to access colors via `hexNames[hex]` 1931 var hexNames = (tinycolor.hexNames = flip(names)); 1932 1933 // Utilities 1934 // --------- 1935 1936 // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` 1937 function flip(o) { 1938 var flipped = {}; 1939 for (var i in o) { 1940 if (o.hasOwnProperty(i)) { 1941 flipped[o[i]] = i; 1942 } 1943 } 1944 return flipped; 1945 } 1946 1947 // Return a valid alpha value [0,1] with all invalid values being set to 1 1948 function boundAlpha(a) { 1949 a = parseFloat(a); 1950 1951 if (isNaN(a) || a < 0 || a > 1) { 1952 a = 1; 1953 } 1954 1955 return a; 1956 } 1957 1958 // Take input from [0, n] and return it as [0, 1] 1959 function bound01(n, max) { 1960 if (isOnePointZero(n)) { 1961 n = "100%"; 1962 } 1963 1964 var processPercent = isPercentage(n); 1965 n = mathMin(max, mathMax(0, parseFloat(n))); 1966 1967 // Automatically convert percentage into number 1968 if (processPercent) { 1969 n = parseInt(n * max, 10) / 100; 1970 } 1971 1972 // Handle floating point rounding errors 1973 if (Math.abs(n - max) < 0.000001) { 1974 return 1; 1975 } 1976 1977 // Convert into [0, 1] range if it isn't already 1978 return (n % max) / parseFloat(max); 1979 } 1980 1981 // Force a number between 0 and 1 1982 function clamp01(val) { 1983 return mathMin(1, mathMax(0, val)); 1984 } 1985 1986 // Parse a base-16 hex value into a base-10 integer 1987 function parseIntFromHex(val) { 1988 return parseInt(val, 16); 1989 } 1990 1991 // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 1992 // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0> 1993 function isOnePointZero(n) { 1994 return typeof n == "string" && n.indexOf(".") != -1 && parseFloat(n) === 1; 1995 } 1996 1997 // Check to see if string passed in is a percentage 1998 function isPercentage(n) { 1999 return typeof n === "string" && n.indexOf("%") != -1; 2000 } 2001 2002 // Force a hex value to have 2 characters 2003 function pad2(c) { 2004 return c.length == 1 ? "0" + c : "" + c; 2005 } 2006 2007 // Replace a decimal with it's percentage value 2008 function convertToPercentage(n) { 2009 if (n <= 1) { 2010 n = n * 100 + "%"; 2011 } 2012 2013 return n; 2014 } 2015 2016 // Converts a decimal to a hex value 2017 function convertDecimalToHex(d) { 2018 return Math.round(parseFloat(d) * 255).toString(16); 2019 } 2020 // Converts a hex value to a decimal 2021 function convertHexToDecimal(h) { 2022 return parseIntFromHex(h) / 255; 2023 } 2024 2025 var matchers = (function () { 2026 // <http://www.w3.org/TR/css3-values/#integers> 2027 var CSS_INTEGER = "[-\\+]?\\d+%?"; 2028 2029 // <http://www.w3.org/TR/css3-values/#number-value> 2030 var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; 2031 2032 // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. 2033 var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; 2034 2035 // Actual matching. 2036 // Parentheses and commas are optional, but not required. 2037 // Whitespace can take the place of commas or opening paren 2038 var PERMISSIVE_MATCH3 = 2039 "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; 2040 var PERMISSIVE_MATCH4 = 2041 "[\\s|\\(]+(" + 2042 CSS_UNIT + 2043 ")[,|\\s]+(" + 2044 CSS_UNIT + 2045 ")[,|\\s]+(" + 2046 CSS_UNIT + 2047 ")[,|\\s]+(" + 2048 CSS_UNIT + 2049 ")\\s*\\)?"; 2050 2051 return { 2052 CSS_UNIT: new RegExp(CSS_UNIT), 2053 rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), 2054 rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), 2055 hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), 2056 hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), 2057 hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), 2058 hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), 2059 hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2060 hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2061 hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2062 hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2063 }; 2064 })(); 2065 2066 // `isValidCSSUnit` 2067 // Take in a single string / number and check to see if it looks like a CSS unit 2068 // (see `matchers` above for definition). 2069 function isValidCSSUnit(color) { 2070 return !!matchers.CSS_UNIT.exec(color); 2071 } 2072 2073 // `stringInputToObject` 2074 // Permissive string parsing. Take in a number of formats, and output an object 2075 // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` 2076 function stringInputToObject(color) { 2077 color = color.replace(trimLeft, "").replace(trimRight, "").toLowerCase(); 2078 var named = false; 2079 if (names[color]) { 2080 color = names[color]; 2081 named = true; 2082 } else if (color == "transparent") { 2083 return { r: 0, g: 0, b: 0, a: 0, format: "name" }; 2084 } 2085 2086 // Try to match string input using regular expressions. 2087 // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] 2088 // Just return an object and let the conversion functions handle that. 2089 // This way the result will be the same whether the tinycolor is initialized with string or object. 2090 var match; 2091 if ((match = matchers.rgb.exec(color))) { 2092 return { r: match[1], g: match[2], b: match[3] }; 2093 } 2094 if ((match = matchers.rgba.exec(color))) { 2095 return { r: match[1], g: match[2], b: match[3], a: match[4] }; 2096 } 2097 if ((match = matchers.hsl.exec(color))) { 2098 return { h: match[1], s: match[2], l: match[3] }; 2099 } 2100 if ((match = matchers.hsla.exec(color))) { 2101 return { h: match[1], s: match[2], l: match[3], a: match[4] }; 2102 } 2103 if ((match = matchers.hsv.exec(color))) { 2104 return { h: match[1], s: match[2], v: match[3] }; 2105 } 2106 if ((match = matchers.hsva.exec(color))) { 2107 return { h: match[1], s: match[2], v: match[3], a: match[4] }; 2108 } 2109 if ((match = matchers.hex8.exec(color))) { 2110 return { 2111 r: parseIntFromHex(match[1]), 2112 g: parseIntFromHex(match[2]), 2113 b: parseIntFromHex(match[3]), 2114 a: convertHexToDecimal(match[4]), 2115 format: named ? "name" : "hex8", 2116 }; 2117 } 2118 if ((match = matchers.hex6.exec(color))) { 2119 return { 2120 r: parseIntFromHex(match[1]), 2121 g: parseIntFromHex(match[2]), 2122 b: parseIntFromHex(match[3]), 2123 format: named ? "name" : "hex", 2124 }; 2125 } 2126 if ((match = matchers.hex4.exec(color))) { 2127 return { 2128 r: parseIntFromHex(match[1] + "" + match[1]), 2129 g: parseIntFromHex(match[2] + "" + match[2]), 2130 b: parseIntFromHex(match[3] + "" + match[3]), 2131 a: convertHexToDecimal(match[4] + "" + match[4]), 2132 format: named ? "name" : "hex8", 2133 }; 2134 } 2135 if ((match = matchers.hex3.exec(color))) { 2136 return { 2137 r: parseIntFromHex(match[1] + "" + match[1]), 2138 g: parseIntFromHex(match[2] + "" + match[2]), 2139 b: parseIntFromHex(match[3] + "" + match[3]), 2140 format: named ? "name" : "hex", 2141 }; 2142 } 2143 2144 return false;
2145 } 2146 2147 function validateWCAG2Parms(parms) { 2148 // return valid WCAG2 parms for isReadable. 2149 // If input parms are invalid, return {"level":"AA", "size":"small"} 2150 var level, size; 2151 parms = parms || { level: "AA", size: "small" }; 2152 level = (parms.level || "AA").toUpperCase(); 2153 size = (parms.size || "small").toLowerCase(); 2154 if (level !== "AA" && level !== "AAA") { 2155 level = "AA"; 2156 } 2157 if (size !== "small" && size !== "large") { 2158 size = "small"; 2159 } 2160 return { level: level, size: size }; 2161 } 2162 2163 const $$1 = jQuery; 2164 class Server { 2165 constructor() { 2166 this.apiUrl = "/wp-json/mapsvg/v1/"; 2167 } 2168 getUrl(path) { 2169 return this.apiUrl + path; 2170 } 2171 get(path, data) { 2172 return $$1.ajax({ 2173 url: this.apiUrl + path, 2174 type: "GET", 2175 data: data, 2176 beforeSend: function (xhr) { 2177 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2178 }, 2179 }); 2180 } 2181 post(path, data) { 2182 const ajaxParams = { 2183 url: this.apiUrl + path, 2184 type: "POST", 2185 data: data, 2186 beforeSend: function (xhr) { 2187 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2188 } 2189 }; 2190 if (data instanceof FormData) { 2191 ajaxParams["processData"] = false; 2192 ajaxParams["contentType"] = false; 2193 } 2194 return $$1.ajax(ajaxParams); 2195 } 2196 put(path, data) { 2197 const ajaxParams = { 2198 url: this.apiUrl + path, 2199 type: "PUT", 2200 data: data, 2201 beforeSend: function (xhr) { 2202 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2203 } 2204 }; 2205 if (data instanceof FormData) { 2206 ajaxParams["processData"] = false; 2207 ajaxParams["contentType"] = false; 2208 } 2209 return $$1.ajax(ajaxParams); 2210 } 2211 delete(path, data) { 2212 return $$1.ajax({ 2213 url: this.apiUrl + path, 2214 type: "DELETE", 2215 data: data, 2216 beforeSend: function (xhr) { 2217 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2218 }, 2219 }); 2220 } 2221 ajax(path, data) { 2222 data.url = this.getUrl(path); 2223 data.beforeSend = function (xhr) { 2224 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2225 }; 2226 return $$1.ajax(data); 2227 } 2228 } 2229 2230 class Events { 2231 constructor(context) { 2232 this.events = {}; 2233 this.context = context; 2234 } 2235 on(event, callbackOrObjectType, callback) { 2236 if (!this.events[event]) 2237 this.events[event] = []; 2238 let callbackFunction; 2239 if (typeof callbackOrObjectType === "string") { 2240 callbackFunction = callback; 2241 } 2242 else { 2243 callbackFunction = callbackOrObjectType; 2244 } 2245 let duplicatedEvent = false; 2246 this.events[event].forEach(function (existingCallback) { 2247 if (existingCallback.toString() === callbackFunction.toString()) { 2248 duplicatedEvent = true; 2249 } 2250 }); 2251 if (duplicatedEvent === false) { 2252 this.events[event].push(callbackFunction); 2253 } 2254 return this; 2255 } 2256 off(event, callback) { 2257 const _this = this; 2258 if (this.events[event] && this.events[event].length) { 2259 this.events[event].forEach(function (_callback, index) { 2260 if (typeof callback === "undefined") { 2261 _this.events[event].splice(index, 1); 2262 } 2263 else if (_callback === callback) { 2264 _this.events[event].splice(index, 1); 2265 } 2266 }); 2267 } 2268 return this; 2269 } 2270 trigger(event, thisArg, args) { 2271 if (this.events[event] && this.events[event].length) 2272 this.events[event].forEach((callback) => { 2273 try { 2274 callback && callback.apply(thisArg || this.context, args || [this.context]); 2275 } 2276 catch (err) { 2277 console.error(err); 2278 } 2279 }); 2280 return this; 2281 } 2282 } 2283 2284 class ArrayIndexed extends Array { 2285 constructor(indexKey, items, options) { 2286 if (items) { 2287 super(...items); 2288 } 2289 else { 2290 super(); 2291 } 2292 this.key = indexKey; 2293 this.dict = {}; 2294 this.nextId = 1; 2295 if (options) { 2296 this.options = options; 2297 } 2298 else { 2299 this.options = { autoId: false, unique: false }; 2300 } 2301 if (this.length > 0) { 2302 let i = 0; 2303 const _this = this; 2304 if (this.options.autoId) { 2305 let maxId = 0; 2306 let missingIds = false;
2307 this.forEach(function (item) { 2308 if (item[_this.key] != null) { 2309 if (item[_this.key] > maxId) { 2310 maxId = item[_this.key]; 2311 } 2312 } 2313 else { 2314 missingIds = true; 2315 } 2316 }); 2317 this.nextId = ++maxId; 2318 if (missingIds) { 2319 this.forEach(function (item) { 2320 if (item[_this.key] == null) { 2321 item[_this.key] = _this.nextId; 2322 _this.nextId++; 2323 } 2324 }); 2325 } 2326 } 2327 this.forEach(function (item) { 2328 _this.dict[item[_this.key]] = i; 2329 i++; 2330 }); 2331 } 2332 } 2333 push(item) { 2334 const length = super.push(item); 2335 if (this.options.autoId === true) { 2336 item[this.key] = this.nextId; 2337 this.nextId++; 2338 } 2339 this.dict[item[this.key]] = length - 1; 2340 return length; 2341 } 2342 pop() { 2343 const item = this[this.length - 1]; 2344 const id = item[this.key]; 2345 const length = super.pop(); 2346 delete this.dict[id]; 2347 this.reindex(); 2348 return super.pop(); 2349 } 2350 update(data) { 2351 if (data[this.key] != null) { 2352 const obj = this.get(data[this.key]); 2353 for (const i in data) { 2354 obj[i] = data[i]; 2355 } 2356 return obj; 2357 } 2358 return false; 2359 } 2360 get(id) { 2361 return this.findById(id); 2362 } 2363 findById(id) { 2364 return this[this.dict[id]]; 2365 } 2366 deleteById(id) { 2367 const index = this.dict[id]; 2368 if (typeof index !== "undefined") { 2369 delete this.dict[id]; 2370 this.splice(index, 1); 2371 } 2372 } 2373 delete(id) { 2374 this.deleteById(id); 2375 } 2376 clear() { 2377 this.length = 0; 2378 this.reindex(); 2379 } 2380 reindex() { 2381 const _this = this; 2382 this.dict = {}; 2383 this.forEach(function (item, index) { 2384 _this.dict[item[_this.key]] = index; 2385 }); 2386 } 2387 sort(compareFn) { 2388 super.sort(compareFn); 2389 this.reindex(); 2390 return this; 2391 } 2392 splice(start, deleteCount) { 2393 const res = super.splice(start, deleteCount); 2394 this.reindex(); 2395 return res; 2396 } 2397 } 2398 2399 class SchemaField { 2400 constructor(field) { 2401 const booleans = ["visible", "searchable", "readonly", "protected"]; 2402 for (const key in field) { 2403 this[key] = field[key]; 2404 } 2405 booleans.forEach((paramName) => { 2406 if (typeof this[paramName] !== "undefined") { 2407 this[paramName] = MapSVG.parseBoolean(this[paramName]); 2408 } 2409 else { 2410 this[paramName] = false; 2411 } 2412 }); 2413 if (typeof this.options !== "undefined") { 2414 if (!(this.options instanceof ArrayIndexed)) { 2415 this.options = new ArrayIndexed("value", this.options); 2416 } 2417 } 2418 } 2419 } 2420 2421 class Schema { 2422 constructor(options) { 2423 this.fields = new ArrayIndexed("name"); 2424 this.build(options); 2425 this.lastChangeTime = Date.now(); 2426 this.events = new Events(this); 2427 } 2428 build(options) { 2429 const allowedParams = ["id", "title", "type", "name", "fields"]; 2430 allowedParams.forEach((paramName) => { 2431 const setter = "set" + MapSVG.ucfirst(paramName); 2432 if (typeof options[paramName] !== "undefined" && typeof this[setter] == "function") { 2433 this[setter](options[paramName]); 2434 } 2435 }); 2436 } 2437 update(options) { 2438 this.build(options); 2439 } 2440 setId(id) { 2441 this.id = id; 2442 } 2443 setTitle(title) { 2444 this.title = title; 2445 } 2446 setName(name) { 2447 this.name = name; 2448 } 2449 loaded() { 2450 return this.fields.length !== 0; 2451 } 2452 setFields(fields) { 2453 if (fields) { 2454 this.fields.clear(); 2455 fields.forEach((fieldParams) => { 2456 this.fields.push(new SchemaField(fieldParams)); 2457 }); 2458 } 2459 } 2460 getFields() { 2461 return this.fields; 2462 } 2463 getFieldsAsArray() { 2464 return this.fields; 2465 } 2466 getFieldNames() { 2467 return this.fields.map((f) => f.name); 2468 } 2469 getField(field) { 2470 return this.fields.findById(field); 2471 } 2472 getFieldByType(type) { 2473 let f = null; 2474 this.fields.forEach(function (field) { 2475 if (field.type === type) 2476 f = field; 2477 }); 2478 return f; 2479 } 2480 getColumns(filters) { 2481 filters = filters || {}; 2482 const columns = this.fields; 2483 const needfilters = Object.keys(filters).length !== 0; 2484 let results = []; 2485 if (needfilters) { 2486 let filterpass; 2487 columns.forEach(function (obj) { 2488 filterpass = true; 2489 for (const param in filters) { 2490 filterpass = obj[param] == filters[param]; 2491 } 2492 filterpass && results.push(obj); 2493 }); 2494 } 2495 else { 2496 results = columns; 2497 } 2498 return results; 2499 } 2500 getData() { 2501 const data = { 2502 id: this.id, 2503 title: this.title, 2504 name: this.name, 2505 fields: this.fields, 2506 type: this.type, 2507 }; 2508 return data; 2509 } 2510 } 2511 2512 class Query { 2513 constructor(options) { 2514 this.filters = {}; 2515 this.filterout = {}; 2516 this.page = 1; 2517 if (options) { 2518 for (const i in options) { 2519 if (typeof options[i] !== "undefined") { 2520 this[i] = options[i]; 2521 } 2522 } 2523 } 2524 } 2525 setFields(fields) { 2526 const _this = this; 2527 for (const key in fields) { 2528 if (key == "filters") { 2529 _this.setFilters(fields[key]); 2530 } 2531 else { 2532 _this[key] = fields[key]; 2533 } 2534 } 2535 } 2536 update(query) { 2537 for (const i in query) { 2538 if (typeof query[i] !== "undefined") { 2539 if (i === "filters") { 2540 this.setFilters(query[i]); 2541 } 2542 else { 2543 this[i] = query[i]; 2544 } 2545 } 2546 } 2547 } 2548 get() { 2549 return { 2550 search: this.search, 2551 searchField: this.searchField, 2552 searchFallback: this.searchFallback, 2553 filters: this.filters, 2554 filterout: this.filterout, 2555 page: this.page, 2556 sort: this.sort, 2557 perpage: this.perpage, 2558 lastpage: this.lastpage, 2559 }; 2560 } 2561 clearFilters() { 2562 this.resetFilters(); 2563 } 2564 setFilters(fields) { 2565 const _this = this; 2566 for (const key in fields) { 2567 if (fields[key] === null || fields[key] === "" || fields[key] === undefined) { 2568 if (_this.filters[key]) { 2569 delete _this.filters[key]; 2570 } 2571 } 2572 else { 2573 _this.filters[key] = fields[key]; 2574 } 2575 } 2576 } 2577 setSearch(search) { 2578 this.search = search; 2579 } 2580 setFilterOut(fields) {
2581 this.filterout = fields; 2582 } 2583 resetFilters(fields) { 2584 this.filters = {}; 2585 this.setSearch(""); 2586 } 2587 setFilterField(field, value) { 2588 this.filters[field] = value; 2589 } 2590 hasFilters() { 2591 return Object.keys(this.filters).length > 0; 2592 } 2593 removeFilter(fieldName) { 2594 this.filters[fieldName] = null; 2595 delete this.filters[fieldName]; 2596 } 2597 requestSchema(requestSchema) { 2598 this.withSchema = requestSchema ? requestSchema : true; 2599 } 2600 } 2601 2602 class LocationAddress { 2603 constructor(fields) { 2604 for (const i in fields) { 2605 this[i] = fields[i]; 2606 } 2607 } 2608 getData() { 2609 const copy = {}; 2610 [ 2611 "route", 2612 "address_formatted", 2613 "administrative_area_level_1", 2614 "administrative_area_level_1_short", 2615 "administrative_area_level_2", 2616 "administrative_area_level_2_short", 2617 "country", 2618 "country_short", 2619 "postal_code", 2620 ].forEach((field) => { 2621 if (this[field]) { 2622 copy[field] = this[field]; 2623 } 2624 }); 2625 return copy; 2626 } 2627 get state() { 2628 return this.country_short === "US" ? this.administrative_area_level_1 : null; 2629 } 2630 get state_short() { 2631 return this.country_short === "US" ? this.administrative_area_level_1_short : null; 2632 } 2633 get county() { 2634 return this.country_short === "US" ? this.administrative_area_level_2 : null; 2635 } 2636 get zip() { 2637 return this.postal_code; 2638 } 2639 } 2640 2641 class ScreenPoint { 2642 constructor(x, y) { 2643 this.x = x; 2644 this.y = y; 2645 } 2646 } 2647 class SVGPoint { 2648 constructor(x, y) { 2649 let _x, _y; 2650 if (typeof x === "object") { 2651 if (x.x && x.y) { 2652 _x = parseFloat(x.x + ""); 2653 _y = parseFloat(x.y + ""); 2654 } 2655 else { 2656 console.error("MapSVG: incorrect format of {x, y} object for SVGPoint."); 2657 _x = 0; 2658 _y = 0; 2659 } 2660 } 2661 else { 2662 _x = parseFloat(x + ""); 2663 _y = parseFloat(y + ""); 2664 } 2665 this.x = _x; 2666 this.y = _y; 2667 } 2668 } 2669 class GeoPoint { 2670 constructor(lat, lng) { 2671 let _lat, _lng; 2672 if (typeof lat === "object") { 2673 if (lat.lat && lat.lng) { 2674 _lat = parseFloat(lat.lat + ""); 2675 _lng = parseFloat(lat.lng + ""); 2676 } 2677 else { 2678 console.error("MapSVG: incorrect format of {lat, lng} object for GeoPoint."); 2679 _lat = 0; 2680 _lng = 0; 2681 } 2682 } 2683 else { 2684 _lat = parseFloat(lat + ""); 2685 _lng = parseFloat(lng + ""); 2686 } 2687 this.lat = _lat; 2688 this.lng = _lng; 2689 } 2690 } 2691 class Location { 2692 constructor(options) { 2693 this.update(options); 2694 } 2695 update(options) { 2696 if (options.img) { 2697 this.setImage(options.img); 2698 } 2699 if (options.address) { 2700 this.setAddress(options.address); 2701 } 2702 if (options.svgPoint) { 2703 this.setSvgPoint(options.svgPoint); 2704 } 2705 if (options.geoPoint) { 2706 this.setGeoPoint(options.geoPoint); 2707 } 2708 } 2709 setImage(imgUrl) { 2710 if (typeof imgUrl !== "string") { 2711 return; 2712 } 2713 let src = imgUrl.split("/").pop(); 2714 if (imgUrl.indexOf("uploads") !== -1) { 2715 src = "uploads/" + src; 2716 } 2717 this.img = src; 2718 this.imagePath = this.getImageUrl(); 2719 if (this.marker && this.marker.src !== this.imagePath) { 2720 this.marker.setImage(this.imagePath); 2721 } 2722 } 2723 getImageUrl() { 2724 if (this.img && this.img.indexOf("uploads/") === 0) { 2725 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2726 } 2727 else { 2728 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2729 } 2730 } 2731 setAddress(address) { 2732 this.address = new LocationAddress(address); 2733 } 2734 setSvgPoint(svgPoint) { 2735 this.svgPoint = svgPoint instanceof SVGPoint ? svgPoint : new SVGPoint(svgPoint); 2736 if (this.marker) { 2737 this.marker.setSvgPointFromLocation(); 2738 } 2739 } 2740 setGeoPoint(geoPoint) { 2741 this.geoPoint = geoPoint instanceof GeoPoint ? geoPoint : new GeoPoint(geoPoint); 2742 if (this.marker) { 2743 this.marker.setSvgPointFromLocation(); 2744 } 2745 } 2746 getMarkerImageUrl() { 2747 if (this.img && this.img.indexOf("uploads/") === 0) { 2748 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2749 } 2750 else { 2751 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2752 } 2753 } 2754 getData() { 2755 const data = { 2756 img: this.img, 2757 imagePath: this.imagePath, 2758 address: this.address, 2759 }; 2760 if (this.geoPoint) { 2761 data.geoPoint = { lat: this.geoPoint.lat, lng: this.geoPoint.lng }; 2762 } 2763 if (this.svgPoint) { 2764 data.svgPoint = { x: this.svgPoint.x, y: this.svgPoint.y }; 2765 } 2766 return data; 2767 } 2768 } 2769 2770 class CustomObject { 2771 constructor(params, schema) { 2772 this.initialLoad = true; 2773 this.schema = schema; 2774 this.fields = schema.getFieldNames(); 2775 this.dirtyFields = []; 2776 this.regions = []; 2777 this._regions = {}; 2778 if (params.id !== undefined) { 2779 this.id = params.id; 2780 } 2781 this.initialLoad = true; 2782 this.build(params); 2783 this.initialLoad = false;
2784 if (this.id) { 2785 this.clearDirtyFields(); 2786 } 2787 } 2788 build(params) { 2789 for (const fieldName in params) { 2790 const field = this.schema.getField(fieldName); 2791 if (field) { 2792 if (!this.initialLoad) { 2793 this.dirtyFields.push(fieldName); 2794 } 2795 switch (field.type) { 2796 case "region": 2797 this.regions = params[fieldName]; 2798 break; 2799 case "location": 2800 if (params[fieldName] != null && 2801 params[fieldName] != "" && 2802 Object.keys(params[fieldName]).length !== 0) { 2803 const data = { 2804 img: params[fieldName].img, 2805 address: new LocationAddress(params[fieldName].address), 2806 }; 2807 if (params[fieldName].geoPoint && 2808 params[fieldName].geoPoint.lat && 2809 params[fieldName].geoPoint.lng) { 2810 data.geoPoint = new GeoPoint(params[fieldName].geoPoint); 2811 } 2812 else if (params[fieldName].svgPoint && 2813 params[fieldName].svgPoint.x && 2814 params[fieldName].svgPoint.y) { 2815 data.svgPoint = new SVGPoint(params[fieldName].svgPoint); 2816 } 2817 if (this.location != null) { 2818 this.location.update(data); 2819 } 2820 else { 2821 this.location = new Location(data); 2822 } 2823 } 2824 else { 2825 this.location = null; 2826 } 2827 break; 2828 case "post": 2829 if (params.post) { 2830 this.post = params.post; 2831 } 2832 break; 2833 case "select": 2834 this[fieldName] = params[fieldName]; 2835 if (!field.multiselect) { 2836 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2837 } 2838 break; 2839 case "radio": 2840 this[fieldName] = params[fieldName]; 2841 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2842 break; 2843 default: 2844 this[fieldName] = params[fieldName]; 2845 break; 2846 } 2847 } 2848 } 2849 } 2850 getEnumLabel(field, params, fieldName) { 2851 const value = field.options.get(params[fieldName]); 2852 if (typeof value !== "undefined") { 2853 return value.label; 2854 } 2855 else { 2856 return ""; 2857 } 2858 } 2859 update(params) { 2860 this.build(params); 2861 } 2862 getDirtyFields() { 2863 const data = {}; 2864 this.dirtyFields.forEach((field) => { 2865 data[field] = this[field]; 2866 }); 2867 data.id = this.id; 2868 if (data.location != null) { 2869 data.location = data.location.getData(); 2870 } 2871 if (this.schema.getFieldByType("region")) { 2872 data.regions = this.regions; 2873 } 2874 return data; 2875 } 2876 clearDirtyFields() { 2877 this.dirtyFields = []; 2878 } 2879 getData() { 2880 const data = {}; 2881 const fields = this.schema.getFields(); 2882 fields.forEach((field) => { 2883 switch (field.type) { 2884 case "region": 2885 data[field.name] = this[field.name]; 2886 break; 2887 case "select": 2888 data[field.name] = this[field.name]; 2889 if (!field.multiselect) { 2890 data[field.name + "_text"] = this[field.name + "_text"]; 2891 } 2892 break; 2893 case "post": 2894 data[field.name] = this[field.name]; 2895 data["post"] = this.post; 2896 case "radio": 2897 data[field.name] = this[field.name]; 2898 data[field.name + "_text"] = this[field.name + "_text"]; 2899 break; 2900 case "location": 2901 data[field.name] = this[field.name] ? this[field.name].getData() : null; 2902 break; 2903 default: 2904 data[field.name] = this[field.name]; 2905 break; 2906 } 2907 }); 2908 return data; 2909 } 2910 getRegions(regionsTableName) { 2911 return this.regions; 2912 } 2913 getRegionsForTable(regionsTableName) { 2914 return this.regions 2915 ? this.regions.filter((region) => !region.tableName || region.tableName === regionsTableName) 2916 : []; 2917 } 2918 } 2919 2920 const $$2 = jQuery; 2921 class Repository { 2922 constructor(objectName, path) { 2923 this.server = new Server(); 2924 this.query = new Query(); 2925 this.events = new Events(this); 2926 this.className = ""; 2927 this.objectNameSingle = objectName; 2928 this.objectNameMany = objectName + "s"; 2929 this.setPath(path); 2930 this.objects = new ArrayIndexed("id"); 2931 this.completeChunks = 0; 2932 } 2933 setDataSource(path) { 2934 this.setPath(path); 2935 this.query = new Query({ withSchema: true }); 2936 return this.find().done(() => { 2937 this.query.update({ withSchema: false }); 2938 }); 2939 } 2940 setPath(path) { 2941 this.path = path.replace(/\/+$/, "") + "/"; 2942 } 2943 setSchema(schema) { 2944 this.schema = schema; 2945 } 2946 getSchema() { 2947 return this.schema; 2948 }
2949 loadDataFromResponse(response) { 2950 let data; 2951 data = this.decodeData(response); 2952 this.objects.clear(); 2953 if (data[this.objectNameMany] && data[this.objectNameMany].length) { 2954 this.hasMoreRecords = 2955 this.query.perpage && data[this.objectNameMany].length > this.query.perpage; 2956 if (this.hasMoreRecords) { 2957 data[this.objectNameMany].pop(); 2958 } 2959 data[this.objectNameMany].forEach((obj) => { 2960 this.objects.push(obj); 2961 }); 2962 } 2963 else { 2964 this.hasMoreRecords = false; 2965 } 2966 this.loaded = true; 2967 this.events.trigger("loaded"); 2968 } 2969 reload() { 2970 return this.find(); 2971 } 2972 create(object) { 2973 const defer = jQuery.Deferred(); 2974 defer.promise(); 2975 const data = {}; 2976 data[this.objectNameSingle] = this.encodeData(object); 2977 this.server 2978 .post(this.path, data) 2979 .done((response) => { 2980 const data = this.decodeData(response); 2981 const object = data[this.objectNameSingle]; 2982 this.objects.push(object); 2983 defer.resolve(object); 2984 this.events.trigger("created", this, [object]); 2985 }) 2986 .fail(() => { 2987 defer.reject(); 2988 }); 2989 return defer; 2990 } 2991 findById(id, nocache = false) { 2992 const defer = jQuery.Deferred(); 2993 defer.promise(); 2994 let object; 2995 if (!nocache) { 2996 object = this.objects.findById(id.toString()); 2997 } 2998 if (!nocache && object) { 2999 defer.resolve(object); 3000 } 3001 else { 3002 this.server 3003 .get(this.path + id) 3004 .done((response) => { 3005 const data = this.decodeData(response); 3006 defer.resolve(data[this.objectNameSingle]); 3007 }) 3008 .fail(() => { 3009 defer.reject(); 3010 }); 3011 } 3012 return defer; 3013 } 3014 find(query) { 3015 this.events.trigger("load"); 3016 const defer = jQuery.Deferred(); 3017 defer.promise(); 3018 if (typeof query !== "undefined") { 3019 this.query.update(query); 3020 } 3021 this.server 3022 .get(this.path, this.query) 3023 .done((response) => { 3024 this.loadDataFromResponse(response); 3025 defer.resolve(this.getLoaded()); 3026 }) 3027 .fail(() => { 3028 defer.reject(); 3029 }); 3030 return defer; 3031 } 3032 getLoaded() { 3033 return this.objects; 3034 } 3035 getLoadedObject(id) { 3036 return this.objects.findById(id.toString()); 3037 } 3038 getLoadedAsArray() { 3039 return this.objects; 3040 } 3041 update(object) { 3042 const defer = jQuery.Deferred(); 3043 defer.promise(); 3044 const data = {}; 3045 const objectUpdatedFields = "getDirtyFields" in object ? object.getDirtyFields() : object; 3046 data[this.objectNameSingle] = this.encodeData(objectUpdatedFields); 3047 this.server 3048 .put(this.path + objectUpdatedFields.id, data) 3049 .done((response) => { 3050 if ("clearDirtyFields" in object) { 3051 object.clearDirtyFields(); 3052 } 3053 defer.resolve(object); 3054 this.events.trigger("updated", this, object); 3055 }) 3056 .fail(() => { 3057 defer.reject(); 3058 }); 3059 return defer; 3060 } 3061 delete(id) { 3062 const defer = jQuery.Deferred(); 3063 defer.promise(); 3064 this.server 3065 .delete(this.path + id) 3066 .done((response) => { 3067 this.objects.delete(id.toString()); 3068 this.events.trigger("deleted"); 3069 defer.resolve(); 3070 }) 3071 .fail(() => { 3072 defer.reject(); 3073 }); 3074 return defer; 3075 } 3076 clear() { 3077 const defer = jQuery.Deferred(); 3078 defer.promise(); 3079 this.server 3080 .delete(this.path) 3081 .done((response) => { 3082 this.objects.clear(); 3083 this.events.trigger("loaded"); 3084 this.events.trigger("cleared"); 3085 defer.resolve(); 3086 }) 3087 .fail(() => { 3088 defer.reject(); 3089 }); 3090 return defer; 3091 } 3092 onFirstPage() { 3093 return this.query.page === 1; 3094 } 3095 onLastPage() { 3096 return this.hasMoreRecords === false; 3097 } 3098 encodeData(params) { 3099 return params; 3100 } 3101 decodeData(dataJSON) { 3102 let data; 3103 if (typeof dataJSON === "string") { 3104 data = JSON.parse(dataJSON); 3105 } 3106 else { 3107 data = dataJSON; 3108 } 3109 if ((data.object || data.region || data.regions || data.objects) && data.schema) { 3110 this.setSchema(new Schema(data.schema)); 3111 } 3112 const dataFormatted = {}; 3113 for (const key in data) { 3114 switch (key) { 3115 case "object": 3116 case "region": 3117 dataFormatted[key] = new CustomObject(data[key], this.schema); 3118 break; 3119 case "objects": 3120 case "regions": 3121 dataFormatted[key] = data[key].map((obj) => new CustomObject(obj, this.schema)); 3122 break; 3123 case "schema": 3124 dataFormatted[key] = this.schema || new Schema(data[key]); 3125 break; 3126 case "schemas": 3127 dataFormatted[key] = data[key].map((obj) => new Schema(obj)); 3128 break; 3129 } 3130 } 3131 return dataFormatted; 3132 } 3133 import(data, convertLatlngToAddress, mapsvg) { 3134 const _this = this; 3135 const locationField = _this.schema.getFieldByType("location"); 3136 let language = "en"; 3137 if (locationField && locationField.language) { 3138 language = locationField.language; 3139 } 3140 data = this.formatCSV(data, mapsvg); 3141 return this.importByChunks(data, language, convertLatlngToAddress).done(function () { 3142 _this.find(); 3143 }); 3144 } 3145 importByChunks(data, language, convertLatlngToAddress) { 3146 const _this = this; 3147 let i, j, temparray, chunk = 50; 3148 const chunks = []; 3149 for (i = 0, j = data.length; i < j; i += chunk) { 3150 temparray = data.slice(i, i + chunk); 3151 chunks.push(temparray); 3152 } 3153 if (chunks.length > 0) { 3154 let delay = 0; 3155 const delayPlus = chunks[0][0] && chunks[0][0].location ? 1000 : 0; 3156 var defer = $$2.Deferred(); 3157 defer.promise(); 3158 _this.completeChunks = 0; 3159 chunks.forEach(function (chunk) { 3160 delay += delayPlus; 3161 setTimeout(function () { 3162 const data = { 3163 language: language, 3164 convertLatlngToAddress: convertLatlngToAddress, 3165 }; 3166 data[_this.objectNameMany] = JSON.stringify(chunk); 3167 _this.server.post(_this.path + "import", data).done(function (_data) { 3168 _this.completeChunk(chunks, defer); 3169 }); 3170 }, delay); 3171 }); 3172 } 3173 return defer; 3174 } 3175 completeChunk(chunks, defer) { 3176 const _this = this; 3177 _this.completeChunks++; 3178 if (_this.completeChunks === chunks.length) { 3179 defer.resolve(); 3180 } 3181 } 3182 formatCSV(data, mapsvg) { 3183 const _this = this; 3184 const latLngRegex = /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/g; 3185 const regionsTable = mapsvg.regionsRepository.getSchema().name; 3186 data.forEach(function (object, index) { 3187 const newObject = {}; 3188 for (const key in object) { 3189 let field = _this.schema.getField(key); 3190 if (key === 'post') { 3191 field = { type: "post" }; 3192 } 3193 if (field !== undefined) { 3194 switch (field.type) { 3195 case "region":
3196 newObject[key] = {}; 3197 newObject[key][regionsTable] = object[key] 3198 .split(",") 3199 .map(function (regionId) { 3200 return regionId.trim(); 3201 }) 3202 .filter(function (rId) { 3203 return (mapsvg.getRegion(rId) !== undefined || 3204 mapsvg.regions.find(function (item) { 3205 return item.title === rId; 3206 }) !== undefined); 3207 }) 3208 .map(function (rId) { 3209 let r = mapsvg.getRegion(rId); 3210 if (typeof r === "undefined") { 3211 r = mapsvg.regions.find(function (item) { 3212 return item.title === rId; 3213 }); 3214 } 3215 return { id: r.id, title: r.title }; 3216 }); 3217 break; 3218 case "location": 3219 if (object[key].match(latLngRegex)) { 3220 const coords = object[key].split(",").map(function (n) { 3221 return parseFloat(n); 3222 }); 3223 if (coords.length == 2 && 3224 coords[0] > -90 && 3225 coords[0] < 90 && 3226 coords[1] > -180 && 3227 coords[1] < 180) { 3228 newObject[key] = { 3229 geoPoint: { lat: coords[0], lng: coords[1] }, 3230 }; 3231 } 3232 else { 3233 newObject[key] = ""; 3234 } 3235 } 3236 else if (object[key]) { 3237 newObject[key] = { address: object[key] }; 3238 } 3239 if (typeof newObject[key] == "object") { 3240 newObject[key].img = mapsvg.options.defaultMarkerImage; 3241 } 3242 break; 3243 case "select": 3244 const field = _this.schema.getField(key); 3245 if (field.multiselect) { 3246 const labels = _this.schema.getField(key).options.map(function (f) { 3247 return f.label; 3248 }); 3249 newObject[key] = object[key] 3250 .split(",") 3251 .map(function (label) { 3252 return label.trim(); 3253 }) 3254 .filter(function (label) { 3255 return labels.indexOf(label) !== -1; 3256 }) 3257 .map(function (label) { 3258 return _this.schema 3259 .getField(key) 3260 .options.filter(function (option) { 3261 return option.label == label; 3262 })[0]; 3263 }); 3264 } 3265 else {
3266 newObject[key] = object[key]; 3267 } 3268 break; 3269 case "radio": 3270 case "text": 3271 case "textarea": 3272 case "status": 3273 default: 3274 newObject[key] = object[key]; 3275 break; 3276 } 3277 } 3278 } 3279 data[index] = newObject; 3280 }); 3281 return data; 3282 } 3283 } 3284 3285 class MapsRepository extends Repository { 3286 constructor() { 3287 super("map", "maps"); 3288 this.path = "maps/"; 3289 } 3290 encodeData(params) { 3291 const data = {}; 3292 if (typeof params.options !== "undefined") { 3293 data.options = JSON.stringify(params.options); 3294 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3295 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3296 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3297 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3298 } 3299 if (typeof params.title !== "undefined") { 3300 data.title = params.title; 3301 } 3302 if (typeof params.id !== "undefined") { 3303 data.id = params.id; 3304 } 3305 if (typeof params.status !== "undefined") { 3306 data.status = params.status; 3307 } 3308 return data; 3309 } 3310 decodeData(dataJSON) { 3311 let data; 3312 if (typeof dataJSON === "string") { 3313 data = JSON.parse(dataJSON); 3314 } 3315 else { 3316 data = dataJSON; 3317 } 3318 return data; 3319 } 3320 copy(id, title) { 3321 const defer = jQuery.Deferred(); 3322 defer.promise(); 3323 const data = { options: { title: title } }; 3324 this.server 3325 .post(this.path + id + "/copy", this.encodeData(data)) 3326 .done((response) => { 3327 const data = this.decodeData(response); 3328 this.objects.clear(); 3329 this.events.trigger("loaded"); 3330 this.events.trigger("cleared"); 3331 defer.resolve(data.map); 3332 }) 3333 .fail(() => { 3334 defer.reject(); 3335 }); 3336 return defer; 3337 } 3338 createFromV2(object) { 3339 const defer = jQuery.Deferred(); 3340 defer.promise(); 3341 const data = {}; 3342 data[this.objectNameSingle] = this.encodeData(object); 3343 this.server 3344 .post(this.path + "/createFromV2", data) 3345 .done((response) => { 3346 const data = this.decodeData(response); 3347 const object = data[this.objectNameSingle]; 3348 this.objects.push(object); 3349 defer.resolve(object); 3350 this.events.trigger("created", this, [object]); 3351 }) 3352 .fail(() => { 3353 defer.reject(); 3354 }); 3355 return defer; 3356 } 3357 delete(id) { 3358 const defer = jQuery.Deferred(); 3359 defer.promise(); 3360 this.server 3361 .delete(this.path + id) 3362 .done((response) => { 3363 this.objects.delete(id.toString()); 3364 this.events.trigger("deleted"); 3365 defer.resolve(); 3366 }) 3367 .fail(() => { 3368 defer.reject(); 3369 }); 3370 return defer; 3371 } 3372 } 3373 3374 class MapsV2Repository extends Repository { 3375 constructor() { 3376 super("map", "maps"); 3377 this.path = "maps-v2/"; 3378 } 3379 encodeData(params) { 3380 const data = {}; 3381 data.options = JSON.stringify(params.options); 3382 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3383 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3384 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3385 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3386 data.id = params.id; 3387 data.title = params.title; 3388 return data; 3389 } 3390 decodeData(dataJSON) { 3391 let data; 3392 if (typeof dataJSON === "string") { 3393 data = JSON.parse(dataJSON); 3394 } 3395 else { 3396 data = dataJSON; 3397 } 3398 return data; 3399 } 3400 } 3401 3402 class Converter {
3403 constructor(mapElement, defViewBox, viewBox, geoViewBox) { 3404 this.mapElement = mapElement; 3405 this.defViewBox = defViewBox; 3406 this.viewBox = viewBox; 3407 this.yShift = 0; 3408 if (geoViewBox) { 3409 this.setGeoViewBox(geoViewBox); 3410 } 3411 } 3412 setYShift() { 3413 if (this.defViewBox.width === 20426) { 3414 this.yShift = 0; 3415 return; 3416 } 3417 if (this.geoViewBox) { 3418 const topLeftPoint = this.convertGeoToSVG(this.geoViewBox.ne); 3419 this.yShift = topLeftPoint.y - this.defViewBox.y; 3420 } 3421 } 3422 setGeoViewBox(geoViewBox) { 3423 this.geoViewBox = geoViewBox; 3424 this.mapLonDelta = this.geoViewBox.ne.lng - this.geoViewBox.sw.lng; 3425 this.mapLatBottomDegree = (this.geoViewBox.sw.lat * Math.PI) / 180; 3426 this.worldMapWidth = (this.defViewBox.width / this.mapLonDelta) * 360; 3427 this.worldMapRadius = ((this.defViewBox.width / this.mapLonDelta) * 360) / (2 * Math.PI); 3428 this.setYShift(); 3429 } 3430 setWorldShift(on) { 3431 this.worldShift = on; 3432 } 3433 getScale() { 3434 return this.mapElement.clientWidth / this.viewBox.width; 3435 } 3436 convertSVGToPixel(svgPoint) { 3437 const scale = this.getScale(); 3438 let shiftXByGM = 0; 3439 const shiftYByGM = 0; 3440 if (this.worldShift) { 3441 if (this.viewBox.x - this.defViewBox.x > this.defViewBox.width) { 3442 shiftXByGM = 3443 this.worldMapWidth * 3444 Math.floor((this.viewBox.x - this.defViewBox.x) / this.defViewBox.width); 3445 } 3446 } 3447 return new ScreenPoint((svgPoint.x - this.viewBox.x + shiftXByGM) * scale, (svgPoint.y - this.viewBox.y + shiftYByGM) * scale); 3448 } 3449 convertPixelToSVG(screenPoint) { 3450 const scale = this.getScale(); 3451 return new SVGPoint(screenPoint.x / scale + this.viewBox.x, screenPoint.y / scale + this.viewBox.y); 3452 } 3453 convertGeoToSVG(geoPoint) { 3454 if (!this.geoViewBox) { 3455 throw new Error("Can't do convertGeoToSVG() - geoViewBox is not provided."); 3456 } 3457 let x = (geoPoint.lng - this.geoViewBox.sw.lng) * (this.defViewBox.width / this.mapLonDelta); 3458 const lat = (geoPoint.lat * Math.PI) / 180; 3459 const mapOffsetY = (this.worldMapRadius / 2) * 3460 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3461 let y = this.defViewBox.height - 3462 ((this.worldMapRadius / 2) * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat))) - 3463 mapOffsetY); 3464 x += this.defViewBox.x; 3465 y += this.defViewBox.y; 3466 y -= this.yShift; 3467 return new SVGPoint(x, y); 3468 } 3469 convertSVGToGeo(svgPoint) { 3470 if (!this.geoViewBox) { 3471 throw new Error("Can't do convertSVGToGeo() - geoViewBox is not provided."); 3472 } 3473 const tx = svgPoint.x - this.defViewBox.x; 3474 const ty = svgPoint.y - this.defViewBox.y; 3475 const mapOffsetY = (this.worldMapRadius / 2) * 3476 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3477 const equatorY = this.defViewBox.height + mapOffsetY; 3478 const a = (equatorY - ty) / this.worldMapRadius; 3479 let lat = (180 / Math.PI) * (2 * Math.atan(Math.exp(a)) - Math.PI / 2); 3480 let lng = this.geoViewBox.sw.lng + (tx / this.defViewBox.width) * this.mapLonDelta; 3481 lat = parseFloat(lat.toFixed(6)); 3482 lng = parseFloat(lng.toFixed(6)); 3483 return new GeoPoint(lat, lng); 3484 } 3485 } 3486 3487 const $$3 = jQuery; 3488 class ResizeSensor { 3489 constructor(element, callback) { 3490 const _this = this; 3491 _this.element = element; 3492 _this.callback = callback; 3493 const style = getComputedStyle(element); 3494 let zIndex = parseInt(style.zIndex); 3495 if (isNaN(zIndex)) { 3496 zIndex = 0; 3497 } 3498 zIndex--; 3499 _this.expand = document.createElement("div"); 3500 _this.expand.style.position = "absolute";
3501 _this.expand.style.left = "0px"; 3502 _this.expand.style.top = "0px"; 3503 _this.expand.style.right = "0px"; 3504 _this.expand.style.bottom = "0px"; 3505 _this.expand.style.overflow = "hidden"; 3506 _this.expand.style.zIndex = zIndex.toString(); 3507 _this.expand.style.visibility = "hidden"; 3508 const expandChild = document.createElement("div"); 3509 expandChild.style.position = "absolute"; 3510 expandChild.style.left = "0px"; 3511 expandChild.style.top = "0px"; 3512 expandChild.style.width = "10000000px"; 3513 expandChild.style.height = "10000000px"; 3514 _this.expand.appendChild(expandChild); 3515 _this.shrink = document.createElement("div"); 3516 _this.shrink.style.position = "absolute"; 3517 _this.shrink.style.left = "0px"; 3518 _this.shrink.style.top = "0px"; 3519 _this.shrink.style.right = "0px"; 3520 _this.shrink.style.bottom = "0px"; 3521 _this.shrink.style.overflow = "hidden"; 3522 _this.shrink.style.zIndex = zIndex.toString(); 3523 _this.shrink.style.visibility = "hidden"; 3524 const shrinkChild = document.createElement("div"); 3525 shrinkChild.style.position = "absolute"; 3526 shrinkChild.style.left = "0px"; 3527 shrinkChild.style.top = "0px"; 3528 shrinkChild.style.width = "200%"; 3529 shrinkChild.style.height = "200%"; 3530 _this.shrink.appendChild(shrinkChild); 3531 _this.element.appendChild(_this.expand); 3532 _this.element.appendChild(_this.shrink); 3533 const size = element.getBoundingClientRect(); 3534 _this.currentWidth = size.width; 3535 _this.currentHeight = size.height; 3536 _this.setScroll(); 3537 _this.expand.addEventListener("scroll", function () { 3538 _this.onScroll(); 3539 }); 3540 _this.shrink.addEventListener("scroll", function () { 3541 _this.onScroll(); 3542 }); 3543 } 3544 onScroll() { 3545 const _this = this; 3546 const size = _this.element.getBoundingClientRect(); 3547 const newWidth = size.width; 3548 const newHeight = size.height; 3549 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 3550 _this.currentWidth = newWidth; 3551 _this.currentHeight = newHeight; 3552 _this.callback(); 3553 } 3554 this.setScroll(); 3555 } 3556 setScroll() { 3557 this.expand.scrollLeft = 10000000; 3558 this.expand.scrollTop = 10000000; 3559 this.shrink.scrollLeft = 10000000; 3560 this.shrink.scrollTop = 10000000; 3561 } 3562 destroy() { 3563 this.expand.remove(); 3564 this.shrink.remove(); 3565 } 3566 } 3567 3568 class ViewBox { 3569 constructor(x, y, width, height) { 3570 if (typeof x === "object") { 3571 if (x.hasOwnProperty("x") && 3572 x.hasOwnProperty("y") && 3573 x.hasOwnProperty("width") && 3574 x.hasOwnProperty("height")) { 3575 this.x = typeof x.x === "string" ? parseFloat(x.x) : x.x; 3576 this.y = typeof x.y === "string" ? parseFloat(x.y) : x.y; 3577 this.width = typeof x.width === "string" ? parseFloat(x.width) : x.width; 3578 this.height = typeof x.height === "string" ? parseFloat(x.height) : x.height; 3579 } 3580 else if (typeof x === "object" && x.length && x.length === 4) { 3581 this.x = typeof x[0] === "string" ? parseFloat(x[0]) : x[0]; 3582 this.y = typeof x[1] === "string" ? parseFloat(x[1]) : x[1]; 3583 this.width = typeof x[2] === "string" ? parseFloat(x[2]) : x[2]; 3584 this.height = typeof x[3] === "string" ? parseFloat(x[3]) : x[3]; 3585 } 3586 } 3587 else { 3588 this.x = typeof x === "string" ? parseFloat(x) : x; 3589 this.y = typeof y === "string" ? parseFloat(y) : y; 3590 this.width = typeof width === "string" ? parseFloat(width) : width; 3591 this.height = typeof height === "string" ? parseFloat(height) : height; 3592 } 3593 } 3594 update(newViewBox) { 3595 this.x = newViewBox.x; 3596 this.y = newViewBox.y; 3597 this.width = newViewBox.width; 3598 this.height = newViewBox.height; 3599 } 3600 toString() { 3601 return this.x + " " + this.y + " " + this.width + " " + this.height; 3602 } 3603 toArray() { 3604 return [this.x, this.y, this.width, this.height]; 3605 } 3606 fitsInViewBox(viewBox, atLeastByOneDimension) { 3607 if (atLeastByOneDimension === true) { 3608 return viewBox.width >
3608 this.width || viewBox.height > this.height; 3609 } 3610 else { 3611 return viewBox.width > this.width && viewBox.height > this.height; 3612 } 3613 } 3614 addPadding(padding) { 3615 if (padding.top) { 3616 this.y -= padding.top; 3617 this.height += padding.top; 3618 } 3619 if (padding.right) { 3620 this.width += padding.right; 3621 } 3622 if (padding.bottom) { 3623 this.height += padding.bottom; 3624 } 3625 if (padding.left) { 3626 this.x -= padding.left; 3627 this.width += padding.left; 3628 } 3629 } 3630 } 3631 class GeoViewBox { 3632 constructor(sw, ne) { 3633 this.sw = sw; 3634 this.ne = ne; 3635 } 3636 } 3637 3638 const $$4 = jQuery; 3639 class MapObject { 3640 constructor(element, mapsvg) { 3641 this.id = ""; 3642 this.objects = []; 3643 this.events = new Events(this); 3644 this.element = element; 3645 this.mapsvg = mapsvg; 3646 } 3647 getBBox() { 3648 return new ViewBox(1, 2, 3, 4); 3649 } 3650 getGeoBounds() { 3651 const bbox = this.getBBox(); 3652 const pointSW = new SVGPoint(bbox.x, bbox.y + bbox.height); 3653 const pointNE = new SVGPoint(bbox.x + bbox.width, bbox.y); 3654 const sw = this.mapsvg.converter.convertSVGToGeo(pointSW); 3655 const ne = this.mapsvg.converter.convertSVGToGeo(pointNE); 3656 return { sw: sw, ne: ne }; 3657 } 3658 getComputedStyle(prop, elem) { 3659 elem = elem || this.element; 3660 const _p1 = elem.getAttribute(prop); 3661 if (_p1) { 3662 return _p1; 3663 } 3664 const _p2 = elem.getAttribute("style"); 3665 if (_p2) { 3666 const s = _p2.split(";"); 3667 const z = s.filter(function (e) { 3668 e = e.trim(); 3669 const attr = e.split(":"); 3670 if (attr[0] == prop) 3671 return true; 3672 }); 3673 if (z.length) { 3674 return z[0].split(":").pop().trim(); 3675 } 3676 } 3677 const parent = elem.parentElement; 3678 const elemType = parent ? parent.tagName : null; 3679 if (elemType && elemType != "svg") 3680 return this.getComputedStyle(prop, parent); 3681 else 3682 return undefined; 3683 } 3684 getStyle(prop) { 3685 const _p1 = this.attr(prop); 3686 if (_p1) { 3687 return _p1; 3688 } 3689 const _p2 = this.attr("style"); 3690 if (_p2) { 3691 const s = _p2.split(";"); 3692 const z = s.filter(function (e) { 3693 var e = e.trim(); 3694 if (e.indexOf(prop) === 0) 3695 return e; 3696 }); 3697 return z.length ? z[0].split(":").pop().trim() : undefined; 3698 } 3699 return ""; 3700 } 3701 getCenter() { 3702 const x = this.element.getBoundingClientRect().left; 3703 const y = this.element.getBoundingClientRect().top; 3704 const w = this.element.getBoundingClientRect().width; 3705 const h = this.element.getBoundingClientRect().height; 3706 const point = new ScreenPoint(x + w / 2, y + h / 2); 3707 return point; 3708 } 3709 getCenterSVG() { 3710 const bbox = this.getBBox(); 3711 const point = new SVGPoint(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2); 3712 return point; 3713 } 3714 getCenterLatLng(yShift) { 3715 yShift = yShift ? yShift : 0; 3716 const bbox = this.getBBox(); 3717 const x = bbox.x + bbox.width / 2; 3718 const y = bbox.y + bbox.height / 2 - yShift; 3719 const point = new SVGPoint(x, y); 3720 return this.mapsvg.converter.convertSVGToGeo(point); 3721 } 3722 attr(v1, v2 = null) { 3723 const svgDom = this.element; 3724 if (typeof v1 == "object") { 3725 for (const key in v1) { 3726 const item = v1[key]; 3727 if (typeof item === "string" || typeof item === "number") { 3728 svgDom.setAttribute(key, "" + item); 3729 } 3730 } 3731 } 3732 else if (typeof v1 == "string" && (typeof v2 == "string" || typeof v2 == "number")) { 3733 svgDom.setAttribute(v1, "" + v2); 3734 } 3735 else if (v2 == undefined) { 3736 return svgDom.getAttribute(v1); 3737 } 3738 } 3739 setId(id) { 3740 if (id !== undefined) { 3741 this.id = id; 3742 this.element.setAttribute("id", id); 3743 } 3744 } 3745 } 3746 3747 const $$5 = jQuery; 3748 class Marker extends MapObject { 3749 constructor(params) { 3750 super(null, params.mapsvg); 3751 this.src = params.location.getMarkerImageUrl(); 3752 this.element = $$5("<div />").addClass("mapsvg-marker")[0]; 3753 this.image = $$5('<img src="' + this.src + '" />').addClass("mapsvg-marker-image")[0]; 3754 $$5(this.element).append(this.image); 3755 this.location = params.location; 3756 this.location.marker = this; 3757 this.mapsvg = params.mapsvg; 3758 params.object && this.setObject(params.object); 3759 if (params.width && params.height) { 3760 this.setSize(params.width, params.height); 3761 } 3762 else { 3763 this.setSize(15, 24); 3764 } 3765 this.setId(this.mapsvg.markerId()); 3766 this.setSvgPointFromLocation(); 3767 this.setImage(this.src); 3768 this.setAltAttr(); 3769 } 3770 setSize(width, height) { 3771 this.width = width; 3772 this.height = height; 3773 this.setCentered(this.width === this.height); 3774 } 3775 setSvgPointFromLocation() { 3776 this.setSvgPoint(this.location.geoPoint && 3777 this.location.geoPoint.lat !== 0 && 3778 this.location.geoPoint.lng !== 0 3779 ? this.mapsvg.converter.convertGeoToSVG(this.location.geoPoint) 3780 : this.location.svgPoint); 3781 } 3782 setId(id) { 3783 MapObject.prototype.setId.call(this, id); 3784 this.mapsvg.markers.reindex(); 3785 } 3786 getBBox() { 3787 if (this.centered) { 3788 return new ViewBox(this.svgPoint.x - this.width / 2 / this.mapsvg.scale, this.svgPoint.y - this.height / 2 / this.mapsvg.scale, this.width / this.mapsvg.scale, this.height / this.mapsvg.scale); 3789 } 3790 else { 3791 return new ViewBox(this.svgPoint.x - this.width / 2 / this.mapsvg.scale, this.svgPoint.y - this.height / this.mapsvg.scale, this.width / this.mapsvg.scale, this.height / this.mapsvg.scale); 3792 } 3793 } 3794 getOptions() { 3795 const o = { 3796 id: this.id, 3797 src: this.src, 3798 svgPoint: this.svgPoint, 3799 geoPoint: this.geoPoint, 3800 }; 3801 $$5.each(o, function (key, val) { 3802 if (val == undefined) { 3803 delete o[key]; 3804 } 3805 }); 3806 return o; 3807 } 3808 update(data) { 3809 for (const key in data) { 3810 const setter = "set" + MapSVG.ucfirst(key); 3811 if (setter in this) 3812 this[setter](data[key]); 3813 } 3814 } 3815 setImage(src) { 3816 if (!src) 3817 return; 3818 src = MapSVG.safeURL(src); 3819 const img = new Image(); 3820 const marker = this; 3821 this.src = src; 3822 if (marker.image.getAttribute("src") !== "src") { 3823 marker.image.setAttribute("src", src); 3824 } 3825 img.onload = function () { 3826 marker.setSize(this.width, this.height); 3827 marker.adjustScreenPosition(); 3828 }; 3829 img.src = src; 3830 if (this.location && this.location.imagePath !== src) { 3831 this.location.setImage(src); 3832 } 3833 this.events.trigger("change"); 3834 } 3835 setAltAttr() { 3836 const marker = this; 3837 marker.altAttr = 3838 typeof marker.object != "undefined" && 3839 typeof marker.object.title != "undefined" && 3840 marker.object.title !== "" 3841 ? marker.object.title 3842 : marker.id; 3843 marker.element.setAttribute("alt", marker.altAttr); 3844 } 3845 setSvgPoint(svgPoint) { 3846 this.svgPoint = svgPoint; 3847 this.adjustScreenPosition(); 3848 this.events.trigger("change"); 3849 } 3850 adjustScreenPosition() { 3851 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 3852 pos.x -= this.width / 2; 3853 pos.y -= !this.centered ? this.height : this.height / 2; 3854 this.setScreenPosition(pos.x, pos.y); 3855 } 3856 moveSrceenPositionBy(deltaX, deltaY) { 3857 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 3858 this.setScreenPosition(x, y); 3859 } 3860 setScreenPosition(x, y) { 3861 if (this.screenPoint instanceof ScreenPoint) { 3862 this.screenPoint.x = x; 3863 this.screenPoint.y = y; 3864 } 3865 else { 3866 this.screenPoint = new ScreenPoint(x, y); 3867 } 3868 this.updateVisibility(); 3869 if (this.visible === true) { 3870 this.element.style.transform = "translate(" + x + "px," + y + "px)"; 3871 this.adjustLabelScreenPosition(); 3872 } 3873 } 3874 adjustLabelScreenPosition() { 3875 if (this.label) { 3876 const markerPos = this.screenPoint, x = Math.round(markerPos.x + this.width / 2 - $$5(this.label).outerWidth() / 2), y = Math.round(markerPos.y - $$5(this.label).outerHeight()); 3877 } 3878 } 3879 inViewBox() { 3880 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 3881 return (x - this.width / 2 < 2 * mapFullWidth && 3882 x + this.width / 2 > -mapFullWidth && 3883 y - this.height / 2 < 2 * mapFullHeight && 3884 y + this.height / 2 > -mapFullHeight); 3885 } 3886 updateVisibility() { 3887 if (this.inViewBox() === true) { 3888 this.visible = true; 3889 this.element.classList.remove("mapsvg-out-of-sight"); 3890 if (this.label) { 3891 this.label.classList.remove("mapsvg-out-of-sight"); 3892 } 3893 } 3894 else { 3895 this.visible = false;
3896 this.element.classList.add("mapsvg-out-of-sight"); 3897 if (this.label) { 3898 this.label.classList.add("mapsvg-out-of-sight"); 3899 } 3900 } 3901 return this.visible; 3902 } 3903 isMoving() { 3904 return this.moving; 3905 } 3906 setMoving(value) { 3907 this.moving = value; 3908 } 3909 drag(startCoords, scale, endCallback, clickCallback) { 3910 const _this = this; 3911 this.svgPointBeforeDrag = new SVGPoint(this.svgPoint.x, this.svgPoint.y); 3912 this.setMoving(true); 3913 $$5("body").on("mousemove.drag.mapsvg", function (e) { 3914 e.preventDefault(); 3915 $$5(_this.mapsvg.containers.map).addClass("no-transitions"); 3916 const mouseNew = MapSVG.mouseCoords(e); 3917 const dx = mouseNew.x - startCoords.x; 3918 const dy = mouseNew.y - startCoords.y; 3919 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 3920 _this.setSvgPoint(newSvgPoint); 3921 }); 3922 $$5("body").on("mouseup.drag.mapsvg", function (e) { 3923 e.preventDefault(); 3924 _this.undrag(); 3925 const mouseNew = MapSVG.mouseCoords(e); 3926 const dx = mouseNew.x - startCoords.x; 3927 const dy = mouseNew.y - startCoords.y; 3928 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 3929 _this.setSvgPoint(newSvgPoint); 3930 if (_this.mapsvg.isGeo()) { 3931 _this.geoPoint = _this.mapsvg.converter.convertSVGToGeo(newSvgPoint); 3932 } 3933 endCallback && endCallback.call(_this); 3934 if (_this.svgPointBeforeDrag.x == _this.svgPoint.x && 3935 _this.svgPointBeforeDrag.y == _this.svgPoint.y) 3936 clickCallback && clickCallback.call(_this); 3937 }); 3938 } 3939 undrag() { 3940 this.setMoving(false); 3941 $$5("body").off(".drag.mapsvg"); 3942 $$5(this.mapsvg.containers.map).removeClass("no-transitions"); 3943 } 3944 delete() { 3945 if (this.label) { 3946 this.label.remove(); 3947 this.label = null; 3948 } 3949 $$5(this.element).empty().remove(); 3950 } 3951 setObject(obj) { 3952 this.object = obj; 3953 $$5(this.element).attr("data-object-id", this.object.id); 3954 } 3955 hide() { 3956 $$5(this.element).addClass("mapsvg-marker-hidden"); 3957 if (this.label) { 3958 $$5(this.label).hide(); 3959 } 3960 } 3961 show() { 3962 $$5(this.element).removeClass("mapsvg-marker-hidden"); 3963 if (this.label) { 3964 $$5(this.label).show(); 3965 } 3966 } 3967 highlight() { 3968 $$5(this.element).addClass("mapsvg-marker-hover"); 3969 } 3970 unhighlight() { 3971 $$5(this.element).removeClass("mapsvg-marker-hover"); 3972 } 3973 select() { 3974 this.selected = true; 3975 $$5(this.element).addClass("mapsvg-marker-active"); 3976 } 3977 deselect() { 3978 this.selected = false; 3979 $$5(this.element).removeClass("mapsvg-marker-active"); 3980 } 3981 getData() { 3982 return this.object; 3983 } 3984 getChoroplethColor() { 3985 const markerValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 3986 let color; 3987 if (!markerValue) { 3988 color = this.mapsvg.options.choropleth.coloring.noData.color; 3989 } 3990 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 3991 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 3992 ? 0 3993 : (markerValue - gradient.values.min) / gradient.values.maxAdjusted, r = Math.round(gradient.colors.diffRGB.r * w + gradient.colors.lowRGB.r), g = Math.round(gradient.colors.diffRGB.g * w + gradient.colors.lowRGB.g), b = Math.round(gradient.colors.diffRGB.b * w + gradient.colors.lowRGB.b), a = (gradient.colors.diffRGB.a * w + gradient.colors.lowRGB.a).toFixed(2); 3994 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 3995 } 3996 else { 3997 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 3998 if (!paletteColors[0].valueFrom && markerValue < paletteColors[0].valueTo) { 3999 color = paletteColors[0].color; 4000 } 4001 else if (!paletteColors[paletteColors.length - 1].valueTo && 4002 markerValue > paletteColors[paletteColors.length - 1].valueFrom) { 4003 color = paletteColors[paletteColors.length - 1].color; 4004 } 4005 else {
4006 paletteColors.forEach(function (paletteColor) { 4007 if (markerValue >= paletteColor.valueFrom && 4008 markerValue < paletteColor.valueTo) { 4009 color = paletteColor.color; 4010 } 4011 }); 4012 color = color 4013 ? color 4014 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4015 } 4016 } 4017 return color; 4018 } 4019 getBubbleSize() { 4020 let bubbleSize; 4021 if (this.object[this.mapsvg.options.choropleth.sourceField]) { 4022 const maxBubbleSize = Number(this.mapsvg.options.choropleth.bubbleSize.max), minBubbleSize = Number(this.mapsvg.options.choropleth.bubbleSize.min), maxSourceFieldvalue = this.mapsvg.options.choropleth.coloring.gradient.values.max, minSourceFieldvalue = this.mapsvg.options.choropleth.coloring.gradient.values.min, sourceFieldvalue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4023 bubbleSize = 4024 ((sourceFieldvalue - minSourceFieldvalue) / 4025 (maxSourceFieldvalue - minSourceFieldvalue)) * 4026 (maxBubbleSize - minBubbleSize) + 4027 Number(minBubbleSize); 4028 } 4029 else { 4030 bubbleSize = false; 4031 } 4032 return bubbleSize; 4033 } 4034 getBubbleScreenPosition() { 4035 const bubbleSize = Number(this.getBubbleSize()); 4036 return { 4037 x: this.width / 2 - bubbleSize / 2, 4038 y: this.height - bubbleSize / 2, 4039 }; 4040 } 4041 drawBubble() { 4042 const bubbleId = "mapsvg-bubble-" + this.object.id; 4043 const bubbleValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4044 if (bubbleValue) { 4045 if (!this.bubble) { 4046 this.bubble = $$5('<div id="' + 4047 bubbleId + 4048 '" data-marker-id="' + 4049 this.element.id + 4050 '" class="mapsvg-bubble mapsvg-marker-bubble"></div>')[0]; 4051 $$5(this.element).append(this.bubble); 4052 } 4053 const color = this.getChoroplethColor(), bubbleSize = Number(this.getBubbleSize()); 4054 $$5(this.bubble) 4055 .css("background-color", color) 4056 .css("width", bubbleSize + "px") 4057 .css("height", bubbleSize + "px") 4058 .css("lineHeight", bubbleSize - 2 + "px"); 4059 } 4060 else { 4061 $$5("#" + bubbleId).remove(); 4062 delete this.bubble; 4063 } 4064 } 4065 setBubbleMode(bubbleMode) { 4066 this.bubbleMode = bubbleMode; 4067 if (bubbleMode) { 4068 this.setCentered(true); 4069 this.drawBubble(); 4070 if (this.bubble) { 4071 this.width = this.bubble.offsetWidth; 4072 this.height = this.bubble.offsetHeight; 4073 this.adjustScreenPosition(); 4074 } 4075 } 4076 else { 4077 this.setImage(this.src); 4078 } 4079 } 4080 setLabel(html) { 4081 if (!this.label) { 4082 this.label = $$5("<div />").addClass("mapsvg-marker-label")[0]; 4083 $$5(this.element).append(this.label); 4084 } 4085 $$5(this.label).html(html); 4086 } 4087 setCentered(on) { 4088 this.centered = on; 4089 } 4090 } 4091 4092 const $$6 = jQuery; 4093 class MarkerCluster extends MapObject { 4094 constructor(options, mapsvg) { 4095 super(null, mapsvg); 4096 this.svgPoint = options.svgPoint; 4097 this.cellX = options.cellX; 4098 this.cellY = options.cellY; 4099 this.markers = options.markers || []; 4100 this.cellSize = 50; 4101 this.width = 30; 4102 this.elem = $$6('<div class="mapsvg-marker-cluster">' + this.markers.length + "</div>")[0]; 4103 $$6(this.elem).data("cluster", this); 4104 if (this.markers.length < 2) { 4105 $$6(this.elem).hide(); 4106 } 4107 this.adjustScreenPosition(); 4108 } 4109 addMarker(marker) { 4110 this.markers.push(marker); 4111 if (this.markers.length > 1) { 4112 if (this.markers.length === 2) { 4113 $$6(this.elem).show(); 4114 } 4115 if (this.markers.length === 2) { 4116 const x = this.markers.map(function (m) { 4117 return m.svgPoint.x; 4118 }); 4119 this.min_x = Math.min.apply(null, x); 4120 this.max_x = Math.max.apply(null, x); 4121 const y = this.markers.map(function (m) { 4122 return m.svgPoint.y; 4123 }); 4124 this.min_y = Math.min.apply(null, y); 4125 this.max_y = Math.max.apply(null, y); 4126 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4127 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4128 } 4129 if (this.markers.length > 2) { 4130 if (marker.svgPoint.x < this.min_x) { 4131 this.min_x = marker.svgPoint.x; 4132 } 4133 else if (marker.svgPoint.x > this.max_x) { 4134 this.max_x = marker.svgPoint.x; 4135 } 4136 if (marker.svgPoint.y < this.min_y) { 4137 this.min_y = marker.svgPoint.y; 4138 } 4139 else if (marker.svgPoint.x > this.max_x) { 4140 this.max_y = marker.svgPoint.y; 4141 } 4142 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4143 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4144 } 4145 } 4146 else { 4147 this.svgPoint.x = marker.svgPoint.x; 4148 this.svgPoint.y = marker.svgPoint.y; 4149 } 4150 $$6(this.elem).text(this.markers.length); 4151 this.adjustScreenPosition(); 4152 } 4153 canTakeMarker(marker) { 4154 const _this = this; 4155 const screenPoint = _this.mapsvg.converter.convertSVGToPixel(marker.svgPoint); 4156 return (this.cellX === Math.ceil(screenPoint.x / this.cellSize) && 4157 this.cellY === Math.ceil(screenPoint.y / this.cellSize)); 4158 } 4159 destroy() { 4160 this.markers = null; 4161 $$6(this.elem).remove(); 4162 } 4163 adjustScreenPosition() { 4164 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 4165 pos.x -= this.width / 2; 4166 pos.y -= this.width / 2; 4167 this.setScreenPosition(pos.x, pos.y); 4168 } 4169 moveSrceenPositionBy(deltaX, deltaY) { 4170 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 4171 this.setScreenPosition(x, y); 4172 } 4173 setScreenPosition(x, y) { 4174 if (this.screenPoint instanceof ScreenPoint) { 4175 this.screenPoint.x = x; 4176 this.screenPoint.y = y; 4177 } 4178 else { 4179 this.screenPoint = new ScreenPoint(x, y); 4180 } 4181 this.updateVisibility(); 4182 if (this.visible === true) { 4183 this.elem.style.transform = "translate(" + x + "px," + y + "px)"; 4184 } 4185 } 4186 inViewBox() { 4187 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 4188 return (x - this.width / 2 < mapFullWidth && 4189 x + this.width / 2 > 0 && 4190 y - this.width / 2 < mapFullHeight && 4191 y + this.width / 2 > 0); 4192 } 4193 updateVisibility() { 4194 if (this.inViewBox() === true) { 4195 this.visible = true; 4196 this.elem.classList.remove("mapsvg-out-of-sight"); 4197 } 4198 else { 4199 this.visible = false;
4200 this.elem.classList.add("mapsvg-out-of-sight"); 4201 } 4202 return this.visible; 4203 } 4204 getBBox() { 4205 let bbox = { 4206 x: this.svgPoint.x, 4207 y: this.svgPoint.y, 4208 width: this.cellSize / this.mapsvg.getScale(), 4209 height: this.cellSize / this.mapsvg.getScale(), 4210 }; 4211 bbox = $$6.extend(true, {}, bbox); 4212 return new ViewBox(bbox.x, bbox.y, bbox.width, bbox.height); 4213 } 4214 getData() { 4215 return this.markers.map((m) => m.object); 4216 } 4217 } 4218 4219 const $$7 = jQuery; 4220 class Region extends MapObject { 4221 constructor(element, mapsvg) { 4222 super(element, mapsvg); 4223 this.id = this.element.getAttribute("id"); 4224 if (this.id && this.mapsvg.options.regionPrefix) { 4225 this.setId(this.id.replace(this.mapsvg.options.regionPrefix, "")); 4226 } 4227 this.id_no_spaces = this.id.replace(/\s/g, "_"); 4228 this.element.setAttribute("class", (this.element.className || "") + " mapsvg-region"); 4229 this.setStyleInitial(); 4230 const regionOptions = this.mapsvg.options.regions && this.mapsvg.options.regions[this.id] 4231 ? this.mapsvg.options.regions[this.id] 4232 : null; 4233 this.disabled = this.getDisabledState(); 4234 this.disabled && this.attr("class", this.attr("class") + " mapsvg-disabled"); 4235 this.default_attr = {}; 4236 this.selected_attr = {}; 4237 this.hover_attr = {}; 4238 let selected = false; 4239 if (regionOptions && regionOptions.selected) { 4240 selected = true; 4241 delete regionOptions.selected; 4242 } 4243 regionOptions && this.update(regionOptions); 4244 this.setFill(); 4245 if (selected) { 4246 this.setSelected(); 4247 } 4248 this.saveState(); 4249 } 4250 adjustStroke(scale) { 4251 $$7(this.element).css({ "stroke-width": this.style["stroke-width"] / scale }); 4252 } 4253 setStyleInitial() { 4254 this.style = { fill: this.getComputedStyle("fill") }; 4255 this.style.stroke = this.getComputedStyle("stroke") || ""; 4256 let w; 4257 w = this.getComputedStyle("stroke-width"); 4258 w = w ? w.replace("px", "") : "1"; 4259 w = w == "1" ? 1.2 : parseFloat(w); 4260 this.style["stroke-width"] = w; 4261 } 4262 saveState() { 4263 this.initialState = JSON.stringify(this.getOptions()); 4264 } 4265 getBBox() { 4266 const _bbox = this.element.getBBox(); 4267 const bbox = new ViewBox(_bbox.x, _bbox.y, _bbox.width, _bbox.height); 4268 const matrix = this.element.getTransformToElement(this.mapsvg.containers.svg); 4269 const x2 = bbox.x + bbox.width; 4270 const y2 = bbox.y + bbox.height; 4271 let position = this.mapsvg.containers.svg.createSVGPoint(); 4272 position.x = bbox.x; 4273 position.y = bbox.y; 4274 position = position.matrixTransform(matrix); 4275 bbox.x = position.x; 4276 bbox.y = position.y; 4277 position.x = x2; 4278 position.y = y2; 4279 position = position.matrixTransform(matrix); 4280 bbox.width = position.x - bbox.x; 4281 bbox.height = position.y - bbox.y; 4282 return bbox; 4283 } 4284 changed() { 4285 return JSON.stringify(this.getOptions()) != this.initialState; 4286 } 4287 edit() { 4288 this.elemOriginal = $$7(this.element).clone()[0]; 4289 } 4290 editCommit() { 4291 this.elemOriginal = null; 4292 } 4293 editCancel() { 4294 this.mapsvg.containers.svg.appendChild(this.elemOriginal); 4295 this.element = this.elemOriginal; 4296 this.elemOriginal = null; 4297 } 4298 getOptions(forTemplate) { 4299 let o; 4300 o = { 4301 id: this.id, 4302 id_no_spaces: this.id_no_spaces, 4303 title: this.title, 4304 fill: this.mapsvg.options.regions[this.id] && this.mapsvg.options.regions[this.id].fill, 4305 data: this.data, 4306 choroplethValue: this.choroplethValue, 4307 }; 4308 if (forTemplate) { 4309 o.disabled = this.disabled; 4310 o.dataCounter = (this.data && this.data.length) || 0; 4311 } 4312 for (const key in o) {
4313 if (typeof o[key] === "undefined") { 4314 delete o[key]; 4315 } 4316 } 4317 if (this.customAttrs) { 4318 const that = this; 4319 this.customAttrs.forEach(function (attr) { 4320 o[attr] = that[attr]; 4321 }); 4322 } 4323 return o; 4324 } 4325 forTemplate() { 4326 const data = { 4327 id: this.id, 4328 title: this.title, 4329 objects: this.objects, 4330 data: this.data, 4331 }; 4332 for (const key in this.data) { 4333 if (key != "title" && key != "id") 4334 data[key] = this.data[key]; 4335 } 4336 return data; 4337 } 4338 getData() { 4339 return this.forTemplate(); 4340 } 4341 update(options) { 4342 for (const key in options) { 4343 const setter = "set" + MapSVG.ucfirst(key); 4344 if (setter in this) 4345 this[setter](options[key]); 4346 else { 4347 this[key] = options[key]; 4348 this.customAttrs = this.customAttrs || []; 4349 this.customAttrs.push(key); 4350 } 4351 } 4352 } 4353 setTitle(title) { 4354 if (title) { 4355 this.title = title; 4356 } 4357 this.element.setAttribute("title", this.title); 4358 } 4359 setStyle(style) { 4360 $$7.extend(true, this.style, style); 4361 this.setFill(); 4362 } 4363 getChoroplethColor() { 4364 const o = this.mapsvg.options.choropleth; 4365 let color = ""; 4366 if (this.data && 4367 (this.data[this.mapsvg.options.regionChoroplethField] || 4368 this.data[this.mapsvg.options.regionChoroplethField] === 0)) { 4369 const w = o.maxAdjusted === 0 4370 ? 0 4371 : (parseFloat(this.data[this.mapsvg.options.regionChoroplethField]) - o.min) / 4372 o.maxAdjusted; 4373 const c = { 4374 r: Math.round(o.colors.diffRGB.r * w + o.colors.lowRGB.r), 4375 g: Math.round(o.colors.diffRGB.g * w + o.colors.lowRGB.g), 4376 b: Math.round(o.colors.diffRGB.b * w + o.colors.lowRGB.b), 4377 a: (o.colors.diffRGB.a * w + o.colors.lowRGB.a).toFixed(2), 4378 }; 4379 color = "rgba(" + c.r + "," + c.g + "," + c.b + "," + c.a + ")"; 4380 } 4381 else { 4382 color = o.colors.noData; 4383 } 4384 return color; 4385 } 4386 _new_getChoroplethColor() { 4387 let regionValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]), color; 4388 if (!regionValue) { 4389 color = this.mapsvg.options.choropleth.coloring.noData.color; 4390 } 4391 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 4392 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 4393 ? 0 4394 : (regionValue - gradient.values.min) / gradient.values.maxAdjusted, r = Math.round(gradient.colors.diffRGB.r * w + gradient.colors.lowRGB.r), g = Math.round(gradient.colors.diffRGB.g * w + gradient.colors.lowRGB.g), b = Math.round(gradient.colors.diffRGB.b * w + gradient.colors.lowRGB.b), a = (gradient.colors.diffRGB.a * w + gradient.colors.lowRGB.a).toFixed(2); 4395 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 4396 } 4397 else { 4398 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 4399 if (!paletteColors[0].valueFrom && regionValue < paletteColors[0].valueTo) { 4400 color = paletteColors[0].color; 4401 } 4402 else if (!paletteColors[paletteColors.length - 1].valueTo && 4403 regionValue > paletteColors[paletteColors.length - 1].valueFrom) { 4404 color = paletteColors[paletteColors.length - 1].color; 4405 } 4406 else {
4407 paletteColors.forEach(function (paletteColor) { 4408 if (regionValue >= paletteColor.valueFrom && 4409 regionValue < paletteColor.valueTo) { 4410 color = paletteColor.color; 4411 } 4412 }); 4413 color = color 4414 ? color 4415 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4416 } 4417 } 4418 return color; 4419 } 4420 getBubbleSize() { 4421 let bubbleSize; 4422 if (this.data[this.mapsvg.options.choropleth.sourceField]) { 4423 const maxBubbleSize = Number(this.mapsvg.options.choropleth.bubbleSize.max), minBubbleSize = Number(this.mapsvg.options.choropleth.bubbleSize.min), maxSourceFieldvalue = this.mapsvg.options.choropleth.coloring.gradient.values.max, minSourceFieldvalue = this.mapsvg.options.choropleth.coloring.gradient.values.min, sourceFieldvalue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]); 4424 bubbleSize = 4425 ((sourceFieldvalue - minSourceFieldvalue) / 4426 (maxSourceFieldvalue - minSourceFieldvalue)) * 4427 (maxBubbleSize - minBubbleSize) + 4428 minBubbleSize; 4429 } 4430 else { 4431 bubbleSize = false; 4432 } 4433 return bubbleSize; 4434 } 4435 setFill(fill) { 4436 if (this.mapsvg.options.colorsIgnore) { 4437 $$7(this.element).css(this.style); 4438 return; 4439 } 4440 if (fill) { 4441 const regions = {}; 4442 regions[this.id] = { fill: fill }; 4443 $$7.extend(true, this.mapsvg.options, { regions: regions }); 4444 } 4445 else if (!fill && 4446 fill !== undefined && 4447 this.mapsvg.options.regions && 4448 this.mapsvg.options.regions[this.id] && 4449 this.mapsvg.options.regions[this.id].fill) { 4450 delete this.mapsvg.options.regions[this.id].fill; 4451 } 4452 if (this.mapsvg.options.choropleth.on) { 4453 this.default_attr["fill"] = this.getChoroplethColor(); 4454 } 4455 else if (this.status !== undefined && 4456 this.mapsvg.regions && 4457 this.mapsvg.regionsRepository.getSchema().getFieldByType("status") && 4458 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict && 4459 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status] && 4460 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status].color) { 4461 this.default_attr["fill"] = this.mapsvg.regionsRepository 4462 .getSchema() 4463 .getFieldByType("status").optionsDict[this.status].color; 4464 } 4465 else if (this.mapsvg.options.regions[this.id] && 4466 this.mapsvg.options.regions[this.id].fill) { 4467 this.default_attr["fill"] = this.mapsvg.options.regions[this.id].fill; 4468 } 4469 else if (this.mapsvg.options.colors.base) { 4470 this.default_attr["fill"] = this.mapsvg.options.colors.base; 4471 } 4472 else if (this.style.fill != "none") { 4473 this.default_attr["fill"] = this.style.fill 4474 ? this.style.fill 4475 : this.mapsvg.options.colors.baseDefault; 4476 } 4477 else { 4478 this.default_attr["fill"] = "none"; 4479 } 4480 if (MapSVG.isNumber(this.mapsvg.options.colors.selected)) 4481 this.selected_attr["fill"] = tinycolor(this.default_attr.fill) 4482 .lighten(parseFloat("" + this.mapsvg.options.colors.selected)) 4483 .toRgbString(); 4484 else 4485 this.selected_attr["fill"] = this.mapsvg.options.colors.selected; 4486 if (MapSVG.isNumber(this.mapsvg.options.colors.hover)) 4487 this.hover_attr["fill"] = tinycolor(this.default_attr.fill) 4488 .lighten(parseFloat("" + this.mapsvg.options.colors.hover)) 4489 .toRgbString(); 4490 else 4491 this.hover_attr["fill"] = this.mapsvg.options.colors.hover; 4492 $$7(this.element).css("fill", this.default_attr["fill"]); 4493 this.fill = this.default_attr["fill"]; 4494 if (this.style.stroke != "none" && this.mapsvg.options.colors.stroke != undefined) { 4495 $$7(this.element).css("stroke", this.mapsvg.options.colors.stroke); 4496 } 4497 else { 4498 const s = this.style.stroke == undefined ? "" : this.style.stroke; 4499 $$7(this.element).css("stroke", s); 4500 } 4501 if (this.selected) 4502 this.setSelected(); 4503 } 4504 setDisabled(on, skipSetFill) { 4505 on = on !== undefined ? MapSVG.parseBoolean(on) : this.getDisabledState(); 4506 const prevDisabled = this.disabled; 4507 this.disabled = on; 4508 this.attr("class", this.attr("class").replace("mapsvg-disabled", "")); 4509 if (on) { 4510 this.attr("class", this.attr("class") + " mapsvg-disabled"); 4511 } 4512 if (this.disabled != prevDisabled) 4513 this.mapsvg.deselectRegion(this); 4514 !skipSetFill && this.setFill(); 4515 } 4516 setStatus(status) { 4517 const statusOptions = this.mapsvg.options.regionStatuses && this.mapsvg.options.regionStatuses[status]; 4518 if (statusOptions) { 4519 this.status = status; 4520 this.data.status = status; 4521 this.data.status_text = statusOptions.label; 4522 this.setDisabled(statusOptions.disabled, true); 4523 } 4524 else { 4525 this.status = undefined; 4526 this.data.status = undefined; 4527 this.data.status_text = undefined; 4528 this.setDisabled(false, true); 4529 } 4530 this.setFill(); 4531 } 4532 setSelected() { 4533 this.mapsvg.selectRegion(this); 4534 } 4535 setchoroplethValue(val) { 4536 if ($$7.isNumeric(val)) { 4537 if (typeof val === "string") { 4538 val = parseFloat(val); 4539 } 4540 this.choroplethValue = val; 4541 } 4542 else { 4543 this.choroplethValue = undefined; 4544 } 4545 } 4546 getDisabledState(asDefault) { 4547 const opts = this.mapsvg.options.regions[this.id]; 4548 if (!asDefault && opts && opts.disabled !== undefined) { 4549 return opts.disabled; 4550 } 4551 else { 4552 return (this.mapsvg.options.disableAll || 4553 this.style.fill === "none" || 4554 this.id == "labels" || 4555 this.id == "Labels"); 4556 } 4557 } 4558 highlight() { 4559 $$7(this.element).css({ fill: this.hover_attr.fill }); 4560 $$7(this.element).addClass("mapsvg-region-hover"); 4561 } 4562 unhighlight() { 4563 $$7(this.element).css({ fill: this.default_attr.fill }); 4564 $$7(this.element).removeClass("mapsvg-region-hover"); 4565 } 4566 select() { 4567 $$7(this.element).css({ fill: this.selected_attr.fill }); 4568 this.selected = true; 4569 $$7(this.element).addClass("mapsvg-region-active"); 4570 } 4571 deselect() { 4572 $$7(this.element).css({ fill: this.default_attr.fill }); 4573 this.selected = false;
4574 $$7(this.element).removeClass("mapsvg-region-active"); 4575 } 4576 setData(data) { 4577 this.data = data; 4578 this.setTitle(data.title); 4579 } 4580 drawBubble() { 4581 if (this.data) { 4582 const bubbleId = "mapsvg-bubble-" + this.id; 4583 const bubbleValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]); 4584 if (bubbleValue) { 4585 if (!this.center) { 4586 this.center = this.getCenterSVG(); 4587 } 4588 const pos = this.mapsvg.converter.convertSVGToPixel(this.center); 4589 if (!this.bubble) { 4590 this.bubble = $$7('<div id="' + 4591 bubbleId + 4592 '" class="mapsvg-bubble mapsvg-region-bubble"></div>')[0]; 4593 $$7(this.mapsvg.layers.bubbles).append(this.bubble); 4594 } 4595 const color = this.getChoroplethColor(); 4596 const bubbleSize = Number(this.getBubbleSize()); 4597 $$7(this.bubble) 4598 .css("transform", "translate(-50%,-50%) translate(" + pos.x + "px," + pos.y + "px)") 4599 .css("background-color", color) 4600 .css("width", bubbleSize + "px") 4601 .css("height", bubbleSize + "px") 4602 .css("lineHeight", bubbleSize - 2 + "px"); 4603 } 4604 else { 4605 delete this.bubble; 4606 } 4607 } 4608 } 4609 adjustLabelScreenPosition() { 4610 if (this.label) { 4611 if (!this.center) { 4612 this.center = this.getCenterSVG(); 4613 } 4614 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.label.offsetWidth / 2, y = pos.y - this.label.offsetHeight / 2; 4615 this.setLabelScreenPosition(x, y); 4616 } 4617 } 4618 adjustBubbleScreenPosition() { 4619 if (this.bubble) { 4620 if (!this.center) { 4621 this.center = this.getCenterSVG(); 4622 } 4623 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.bubble.offsetWidth / 2, y = pos.y - this.bubble.offsetHeight / 2; 4624 this.setBubbleScreenPosition(x, y); 4625 } 4626 } 4627 moveLabelScreenPositionBy(deltaX, deltaY) { 4628 if (this.label) { 4629 const labelStyle = window.getComputedStyle(this.label), matrix = labelStyle.transform || labelStyle.webkitTransform, matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(", "), x = parseFloat(matrixValues[4]) - deltaX, y = parseFloat(matrixValues[5]) - deltaY; 4630 this.setLabelScreenPosition(x, y); 4631 } 4632 } 4633 moveBubbleScreenPositionBy(deltaX, deltaY) { 4634 if (this.bubble) { 4635 const labelStyle = window.getComputedStyle(this.bubble), matrix = labelStyle.transform || labelStyle.webkitTransform, matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(", "), x = parseFloat(matrixValues[4]) - deltaX, y = parseFloat(matrixValues[5]) - deltaY; 4636 this.setBubbleScreenPosition(x, y); 4637 } 4638 } 4639 setLabelScreenPosition(x, y) { 4640 if (this.label) { 4641 this.label.style.transform = "translate(" + x + "px," + y + "px)"; 4642 } 4643 } 4644 setBubbleScreenPosition(x, y) { 4645 if (this.bubble) { 4646 this.bubble.style.transform = "translate(" + x + "px," + y + "px)"; 4647 } 4648 } 4649 } 4650 4651 class SchemaRepository extends Repository { 4652 constructor() { 4653 const objectName = "schema"; 4654 super(objectName, +objectName + "s"); 4655 this.className = "Schema"; 4656 this.objectNameSingle = objectName; 4657 this.objectNameMany = objectName + "s"; 4658 this.path = objectName + "s/"; 4659 this.events = new Events(this); 4660 } 4661 create(schema) { 4662 const defer = jQuery.Deferred(); 4663 defer.promise(); 4664 const data = {}; 4665 data[this.objectNameSingle] = this.encodeData(schema); 4666 this.server 4667 .post(this.path, data) 4668 .done((response) => { 4669 const data = this.decodeData(response); 4670 schema.id = data[this.objectNameSingle].id; 4671 this.objects.push(schema); 4672 this.events.trigger("created"); 4673 schema.events.trigger("created"); 4674 defer.resolve(schema); 4675 }) 4676 .fail(() => { 4677 defer.reject(); 4678 }); 4679 return defer; 4680 } 4681 update(schema) { 4682 const defer = jQuery.Deferred(); 4683 defer.promise(); 4684 const data = {}; 4685 data[this.objectNameSingle] = this.encodeData(schema); 4686 this.server 4687 .put(this.path + schema.id, data) 4688 .done((response) => { 4689 const data = this.decodeData(response); 4690 this.objects.push(schema); 4691 defer.resolve(schema); 4692 this.events.trigger("changed"); 4693 schema.events.trigger("changed"); 4694 }) 4695 .fail(() => { 4696 defer.reject(); 4697 }); 4698 return defer; 4699 } 4700 encodeData(schema) { 4701 const _schema = schema.getData(); 4702 let fieldsJsonString = JSON.stringify(_schema); 4703 fieldsJsonString = fieldsJsonString.replace(/select/g, "!mapsvg-encoded-slct"); 4704 fieldsJsonString = fieldsJsonString.replace(/table/g, "!mapsvg-encoded-tbl"); 4705 fieldsJsonString = fieldsJsonString.replace(/database/g, "!mapsvg-encoded-db"); 4706 fieldsJsonString = fieldsJsonString.replace(/varchar/g, "!mapsvg-encoded-vc"); 4707 return JSON.parse(fieldsJsonString); 4708 } 4709 } 4710 4711 const $$8 = jQuery; 4712 class Controller { 4713 constructor(options) { 4714 this.containers = { 4715 main: options.container, 4716 }; 4717 this.mapsvg = options.mapsvg; 4718 this.template = options.template || ""; 4719 this.scrollable = options.scrollable === undefined ? true : options.scrollable; 4720 this.withToolbar = options.withToolbar === undefined ? true : options.withToolbar; 4721 this.autoresize = MapSVG.parseBoolean(options.autoresize); 4722 this.templates = { 4723 toolbar: Handlebars.compile(this.getToolbarTemplate()), 4724 main: Handlebars.compile(this.getMainTemplate()), 4725 }; 4726 this.data = options.data; 4727 this.width = options.width; 4728 this.color = options.color; 4729 this.events = new Events(this); 4730 if (options.events) { 4731 for (const eventName in options.events) { 4732 if (typeof options.events[eventName] === "function") { 4733 this.events.on(eventName, options.events[eventName]); 4734 } 4735 } 4736 } 4737 } 4738 viewDidLoad() { 4739 const _this = this; 4740 _this.updateScroll(); 4741 if (this.autoresize) { 4742 _this.adjustHeight(); 4743 this.resizeSensor.setScroll(); 4744 } 4745 } 4746 _viewDidLoad() { 4747 this.updateScroll(); 4748 } 4749 viewDidAppear() { } 4750 viewDidDisappear() { } 4751 updateScroll() { 4752 if (!this.scrollable) 4753 return; 4754 const _this = this; 4755 $$8(this.containers.contentWrap).nanoScroller({ 4756 preventPageScrolling: true, 4757 iOSNativeScrolling: true, 4758 }); 4759 setTimeout(function () { 4760 $$8(_this.containers.contentWrap).nanoScroller({ 4761 preventPageScrolling: true, 4762 iOSNativeScrolling: true, 4763 }); 4764 }, 300); 4765 } 4766 adjustHeight() { 4767 const _this = this; 4768 $$8(_this.containers.main).height($$8(_this.containers.main).find(".mapsvg-auto-height").outerHeight() + 4769 (_this.containers.toolbar ? $$8(_this.containers.toolbar).outerHeight() : 0)); 4770 } 4771 _init() { 4772 const _this = this; 4773 _this.render(); 4774 _this.init(); 4775 } 4776 init() { } 4777 getToolbarTemplate() { 4778 return ""; 4779 } 4780 setMainTemplate(template) { 4781 return (this.templates.main = Handlebars.compile(template)); 4782 } 4783 getMainTemplate() { 4784 return this.template; 4785 } 4786 render() { 4787 const _this = this; 4788 this.containers.view = $$8("<div />") 4789 .attr("id", "mapsvg-controller-" + this.name) 4790 .addClass("mapsvg-controller-view")[0]; 4791 this.containers.contentWrap = $$8("<div />").addClass("mapsvg-controller-view-wrap")[0]; 4792 this.containers.contentWrap2 = $$8("<div />")[0]; 4793 this.containers.sizer = $$8("<div />").addClass("mapsvg-auto-height")[0]; 4794 this.containers.contentView = $$8("<div />").addClass("mapsvg-controller-view-content")[0]; 4795 this.containers.sizer.appendChild(this.containers.contentView); 4796 if (this.scrollable) { 4797 $$8(this.containers.contentWrap).addClass("nano"); 4798 $$8(this.containers.contentWrap2).addClass("nano-content"); 4799 } 4800 this.containers.contentWrap.appendChild(this.containers.contentWrap2); 4801 this.containers.contentWrap2.appendChild(this.containers.sizer); 4802 if (this.withToolbar && this.templates.toolbar) { 4803 this.containers.toolbar = $$8("<div />").addClass("mapsvg-controller-view-toolbar")[0]; 4804 this.containers.view.appendChild(this.containers.toolbar); 4805 } 4806 this.containers.view.append(this.containers.contentWrap); 4807 this.containers.main.appendChild(this.containers.view);
4808 $$8(this.containers.main).data("controller", this); 4809 if (this.width) 4810 this.containers.view.style.width = this.width; 4811 if (this.color) 4812 this.containers.view.style["background-color"] = this.color; 4813 _this.viewReadyToFill(); 4814 this.redraw(); 4815 setTimeout(function () { 4816 _this._viewDidLoad(); 4817 _this.viewDidLoad(); 4818 _this.setEventHandlersCommon(); 4819 _this.setEventHandlers(); 4820 }, 1); 4821 } 4822 viewReadyToFill() { 4823 const _this = this; 4824 if (_this.autoresize) { 4825 _this.resizeSensor = new ResizeSensor(this.containers.sizer[0], function () { 4826 _this.adjustHeight(); 4827 _this.updateScroll(); 4828 _this.events.trigger("resize", this, [this]); 4829 }); 4830 } 4831 } 4832 redraw(data) { 4833 if (data !== undefined) { 4834 this.data = data; 4835 } 4836 try { 4837 $$8(this.containers.contentView).html(this.templates.main(this.data)); 4838 } 4839 catch (err) { 4840 console.error(err); 4841 $$8(this.containers.contentView).html(""); 4842 } 4843 if (this.withToolbar && this.templates.toolbar) 4844 $$8(this.containers.toolbar).html(this.templates.toolbar(this.data)); 4845 this.updateTopShift(); 4846 if (this.noPadding) 4847 this.containers.contentView.style.padding = "0"; 4848 this.updateScroll(); 4849 } 4850 updateTopShift() { 4851 const _this = this; 4852 if (!this.withToolbar) 4853 return; 4854 $$8(_this.containers.contentWrap).css({ 4855 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 4856 }); 4857 setTimeout(function () { 4858 $$8(_this.containers.contentWrap).css({ 4859 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 4860 }); 4861 }, 100); 4862 setTimeout(function () { 4863 $$8(_this.containers.contentWrap).css({ 4864 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 4865 }); 4866 }, 200); 4867 setTimeout(function () { 4868 $$8(_this.containers.contentWrap).css({ 4869 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 4870 }); 4871 _this.updateScroll(); 4872 }, 500); 4873 } 4874 setEventHandlersCommon() { } 4875 setEventHandlers() { } 4876 destroy() { 4877 delete this.resizeSensor; 4878 $$8(this.containers.view).empty().remove(); 4879 } 4880 } 4881 4882 const $$9 = jQuery; 4883 class DirectoryController extends Controller { 4884 constructor(options) { 4885 super(options); 4886 this.repository = options.repository; 4887 this.noPadding = true; 4888 this.position = options.position; 4889 this.search = options.search; 4890 } 4891 getToolbarTemplate() { 4892 let t = '<div class="mapsvg-directory-search-wrap">'; 4893 t += '<div class="mapsvg-directory-filter-wrap filter-wrap"></div>'; 4894 t += "</div>"; 4895 t += "</div>"; 4896 return t; 4897 } 4898 viewDidLoad() { 4899 const _this = this; 4900 this.menuBtn = $$9('<div class="mapsvg-button-menu"><i class="mapsvg-icon-menu"></i> ' + 4901 this.mapsvg.options.mobileView.labelList + 4902 "</div>")[0]; 4903 this.mapBtn = $$9('<div class="mapsvg-button-map"><i class="mapsvg-icon-map"></i> ' + 4904 this.mapsvg.options.mobileView.labelMap + 4905 "</div>")[0]; 4906 if (MapSVG.isPhone && _this.mapsvg.options.menu.hideOnMobile) { 4907 if (this.mapsvg.options.menu.showFirst == "map") { 4908 this.toggle(false); 4909 } 4910 else { 4911 this.toggle(true); 4912 } 4913 } 4914 this.mobileButtons = $$9('<div class="mapsvg-mobile-buttons"></div>')[0]; 4915 this.mobileButtons.append(this.menuBtn, this.mapBtn); 4916 if (this.mapsvg.options.menu.on !== false) { 4917 this.mapsvg.containers.wrapAll.appendChild(this.mobileButtons); 4918 } 4919 this.events.trigger("shown", this.containers.view); 4920 } 4921 setEventHandlers() { 4922 const _this = this; 4923 $$9(window).on("resize", function () { 4924 _this.updateTopShift(); 4925 }); 4926 $$9(this.menuBtn).on("click", function () { 4927 _this.toggle(true); 4928 }); 4929 $$9(this.mapBtn).on("click", function () { 4930 _this.toggle(false); 4931 _this.mapsvg.redraw(); 4932 }); 4933 $$9(this.containers.view) 4934 .on("click.menu.mapsvg", ".mapsvg-directory-item", function (e) { 4935 if (e.target.nodeName == "A") { 4936 return; 4937 } 4938 e.preventDefault(); 4939 const objID = $$9(this).data("object-id"); 4940 let regions; 4941 let marker; 4942 let detailsViewObject; 4943 let eventObject; 4944 _this.deselectItems(); 4945 _this.selectItems(objID); 4946 if (MapSVG.isPhone && _this.mapsvg.options.menu.showMapOnClick) { 4947 _this.toggle(false); 4948 } 4949 if (_this.mapsvg.options.menu.source == "regions") { 4950 regions = [_this.mapsvg.getRegion(objID)]; 4951 eventObject = regions[0]; 4952 detailsViewObject = regions[0]; 4953 } 4954 else { 4955 detailsViewObject = _this.repository.getLoadedObject(objID); 4956 eventObject = detailsViewObject; 4957 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 4958 if (_regions) { 4959 regions = _regions 4960 .map(function (region) { 4961 return _this.mapsvg.getRegion(region.id); 4962 }) 4963 .filter(function (r) { 4964 return r !== undefined; 4965 }); 4966 } 4967 } 4968 if (detailsViewObject.location && detailsViewObject.location.marker) 4969 marker = detailsViewObject.location.marker; 4970 if (_this.mapsvg.options.actions.directoryItem.click.showDetail
4970s) { 4971 _this.mapsvg.loadDetailsView(detailsViewObject); 4972 } 4973 if (regions && regions.length > 0) { 4974 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 4975 _this.mapsvg.zoomTo(regions, _this.mapsvg.options.actions.directoryItem.click.zoomToLevel); 4976 } 4977 if (regions.length > 1) { 4978 _this.mapsvg.setMultiSelect(true); 4979 } 4980 regions.forEach(function (region) { 4981 const center = region.getCenter(); 4982 e.clientX = center[0]; 4983 e.clientY = center[1]; 4984 if (_this.mapsvg.options.actions.directoryItem.click.selectRegion) { 4985 _this.mapsvg.selectRegion(region, true); 4986 } 4987 if (_this.mapsvg.options.actions.directoryItem.click.showRegionPopover) { 4988 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 4989 setTimeout(function () { 4990 _this.mapsvg.showPopover(region); 4991 }, 500); 4992 } 4993 else { 4994 _this.mapsvg.showPopover(region); 4995 } 4996 } 4997 if (_this.mapsvg.options.actions.directoryItem.click.fireRegionOnClick) { 4998 _this.mapsvg.events.trigger("click.region", region, [region]); 4999 } 5000 }); 5001 if (regions.length > 1) { 5002 _this.mapsvg.setMultiSelect(false, false); 5003 } 5004 } 5005 if (marker) { 5006 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5007 _this.mapsvg.zoomTo(marker, _this.mapsvg.options.actions.directoryItem.click.zoomToMarkerLevel); 5008 } 5009 if (_this.mapsvg.options.actions.directoryItem.click.showMarkerPopover) { 5010 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5011 setTimeout(function () { 5012 _this.mapsvg.showPopover(detailsViewObject); 5013 }, 500); 5014 } 5015 else { 5016 _this.mapsvg.showPopover(detailsViewObject); 5017 } 5018 } 5019 if (_this.mapsvg.options.actions.directoryItem.click.fireMarkerOnClick) { 5020 _this.mapsvg.events.trigger("click.marker", marker, [e, _this.mapsvg]); 5021 } 5022 _this.mapsvg.selectMarker(marker); 5023 } 5024 _this.events.trigger("click", this, [e, eventObject, _this.mapsvg]); 5025 const actions = _this.mapsvg.options.actions; 5026 if (actions.directoryItem.click.goToLink) { 5027 const linkParts = actions.directoryItem.click.linkField.split("."); 5028 let url; 5029 if (linkParts.length > 1) { 5030 const obj = linkParts.shift(); 5031 const attr = "." + linkParts.join("."); 5032 if (obj == "Region") { 5033 if (regions[0] && regions[0].data) 5034 url = eval("regions[0].data" + attr); 5035 } 5036 else { 5037 if (detailsViewObject) 5038 url = eval("detailsViewObject" + attr); 5039 } 5040 if (url) { 5041 if (actions.directoryItem.click.newTab) { 5042 const win = window.open(url, "_blank"); 5043 win.focus(); 5044 } 5045 else { 5046 window.location.href = url; 5047 } 5048 } 5049 } 5050 } 5051 if (actions.directoryItem.click.showAnotherMap) { 5052 if (_this.mapsvg.editMode) { 5053 alert('"Show another map" action is disabled in the preview'); 5054 return true; 5055 } 5056 const linkParts2 = actions.directoryItem.click.showAnotherMapField.split("."); 5057 if (linkParts2.length > 1) { 5058 const obj2 = linkParts2.shift(); 5059 const attr2 = "." + linkParts2.join("."); 5060 let map_id; 5061 if (obj2 == "Region") { 5062 if (regions[0] && regions[0].data) 5063 map_id = eval("regions[0].data" + attr2); 5064 } 5065 else { 5066 if (detailsViewObject) 5067 map_id = eval("detailsViewObject" + attr2); 5068 } 5069 if (map_id) { 5070 const container = actions.directoryItem.click.showAnotherMapContainerId 5071 ? $$9("#" + actions.directoryItem.click.showAnotherMapContainerId)[0] 5072 : $$9(_this.mapsvg.containers.map)[0]; 5073 _this.mapsvg.loadMap(map_id, container); 5074 } 5075 } 5076 } 5077 }) 5078 .on("mouseover.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5079 const objID = $$9(this).data("object-id"); 5080 let regions; 5081 let detailsViewObject; 5082 let eventObject; 5083 let marker; 5084 if (_this.mapsvg.options.menu.source == "regions") { 5085 regions = [_this.mapsvg.getRegion(objID)]; 5086 eventObject = regions[0]; 5087 detailsViewObject = regions[0]; 5088 } 5089 else { 5090 detailsViewObject = _this.repository.getLoadedObject(objID); 5091 eventObject = detailsViewObject; 5092 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5093 if (_regions) { 5094 regions = _regions.map(function (region) { 5095 return _this.mapsvg.getRegion(region.id); 5096 }); 5097 } 5098 if (detailsViewObject.location) { 5099 marker = detailsViewObject.location.marker; 5100 } 5101 } 5102 if (regions && regions.length) { 5103 _this.mapsvg.highlightRegions(regions); 5104 } 5105 if (marker) { 5106 _this.mapsvg.highlightMarker(marker); 5107 if (_this.mapsvg.options.actions.directoryItem.hover.centerOnMarker) { 5108 _this.mapsvg.centerOn(marker); 5109 } 5110 } 5111 _this.events.trigger("mouseover", $$9(this), [e, eventObject, _this.mapsvg]); 5112 }) 5113 .on("mouseout.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5114 const objID = $$9(this).data("object-id"); 5115 let regions; 5116 let detailsViewObject; 5117 let eventObject; 5118 let marker; 5119 if (_this.mapsvg.options.menu.source == "regions") { 5120 regions = [_this.mapsvg.getRegion(objID)]; 5121 eventObject = regions[0]; 5122 detailsViewObject = regions[0]; 5123 } 5124 else { 5125 detailsViewObject = _this.repository.getLoadedObject(objID); 5126 eventObject = detailsViewObject; 5127 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5128 if (_regions) { 5129 regions = _regions.map(function (region) { 5130 return _this.mapsvg.getRegion(region.id); 5131 }); 5132 } 5133 if (detailsViewObject.location) { 5134 marker = detailsViewObject.location.marker; 5135 } 5136 } 5137 if (regions && regions.length) { 5138 _this.mapsvg.unhighlightRegions(); 5139 } 5140 if (marker) { 5141 _this.mapsvg.unhighlightMarker(); 5142 } 5143 _this.events.trigger("mouseout", $$9(this), [e, eventObject, _this.mapsvg]); 5144 }); 5145 $$9(this.containers.contentView).on("click", ".mapsvg-category-item", function () { 5146 const panel = $$9(this).next(".mapsvg-category-block"); 5147 if (panel[0].style.maxHeight || panel.hasClass("active")) { 5148 panel[0].style.maxHeight = null; 5149 } 5150 else { 5151 panel[0].style.maxHeight = panel[0].scrollHeight + "px"; 5152 } 5153 if ($$9(this).hasClass("active")) { 5154 $$9(this).toggleClass("active", false); 5155 $$9(this).next(".mapsvg-category-block").addClass("collapsed").removeClass("active"); 5156 } 5157 else { 5158 if (_this.mapsvg.options.menu.categories.collapseOther) { 5159 $$9(this).parent().find(".mapsvg-category-item.active").removeClass("active"); 5160 $$9(this) 5161 .parent() 5162 .find(".mapsvg-category-block.active") 5163 .removeClass("active") 5164 .addClass("collapsed"); 5165 } 5166 $$9(this).toggleClass("active", true); 5167 $$9(this).next(".mapsvg-category-block").removeClass("collapsed").addClass("active"); 5168 } 5169 const panels = $$9(".mapsvg-category-block.collapsed"); 5170 panels.each(function (i, panel) { 5171 panel.style.maxHeight = null; 5172 }); 5173 }); 5174 } 5175 highlightItems(ids) { 5176 const _this = this; 5177 if (typeof ids != "object") 5178 ids = [ids]; 5179 ids.forEach(function (id) { 5180 $$9(_this.containers.view) 5181 .find("#mapsvg-directory-item-" + id) 5182 .addClass("hover"); 5183 }); 5184 } 5185 unhighlightItems() { 5186 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("hover"); 5187 } 5188 selectItems(ids) { 5189 const _this = this; 5190 if (typeof ids != "object") 5191 ids = [ids]; 5192 ids.forEach(function (id) { 5193 $$9(_this.containers.view) 5194 .find("#mapsvg-directory-item-" + id) 5195 .addClass("selected"); 5196 }); 5197 if ($$9("#mapsvg-directory-item-" + ids[0]).length > 0) { 5198 _this.scrollable && 5199 $$9(_this.containers.contentWrap).nanoScroller({ 5200 scrollTo: $$9(_this.containers.view).find("#mapsvg-directory-item-" + ids[0]), 5201 }); 5202 } 5203 } 5204 deselectItems() { 5205 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("selected"); 5206 } 5207 removeItems(ids) { 5208 $$9(this.containers.view) 5209 .find("#mapsvg-directory-item-" + ids) 5210 .remove(); 5211 } 5212 filterOut(items) { 5213 return items; 5214 } 5215 loadItemsToDirectory() { 5216 let items = []; 5217 const _this = this; 5218 if (!_this.repository.loaded) 5219 return false;
5220 if (_this.mapsvg.options.menu.categories && 5221 _this.mapsvg.options.menu.categories.on && 5222 _this.mapsvg.options.menu.categories.groupBy) { 5223 const categoryField = _this.mapsvg.options.menu.categories.groupBy; 5224 if (_this.repository.getSchema().getField(categoryField) === undefined || 5225 _this.repository.getSchema().getField(categoryField).options === undefined) { 5226 return false; 5227 } 5228 const categories = _this.repository.getSchema().getField(categoryField).options; 5229 categories.forEach(function (category) { 5230 let dbItems = _this.repository.getLoaded(); 5231 dbItems = _this.filterOut(dbItems); 5232 const itemArr = []; 5233 dbItems.forEach((item) => { 5234 itemArr.push(item); 5235 }); 5236 const catItems = itemArr.filter(function (object) { 5237 if (categoryField === "regions") { 5238 const objectRegions = typeof object[categoryField] !== "undefined" && 5239 object[categoryField].length 5240 ? object[categoryField] 5241 : []; 5242 const objectRegionIDs = objectRegions.map(function (region) { 5243 return region.id; 5244 }); 5245 return objectRegionIDs.indexOf(category.id) !== -1; 5246 } 5247 else { 5248 return object[categoryField] == category.value; 5249 } 5250 }); 5251 category.counter = catItems.length; 5252 if (categoryField === "regions") { 5253 category.label = category.title; 5254 category.value = category.id; 5255 } 5256 items.push({ category: category, items: catItems }); 5257 }); 5258 if (_this.mapsvg.options.menu.categories.hideEmpty) { 5259 items = items.filter(function (item) { 5260 return item.category.counter > 0; 5261 }); 5262 } 5263 } 5264 else { 5265 if (_this.mapsvg.options.menu.source === "regions") { 5266 items = _this.repository.getLoaded().map((r) => { 5267 const data = r.getData(); 5268 data.objects = _this.mapsvg.getRegion(data.id).objects; 5269 return data; 5270 }); 5271 } 5272 else { 5273 items = _this.repository 5274 .getLoaded() 5275 .map((r) => r.getData(_this.mapsvg.regionsRepository.schema.name)); 5276 } 5277 } 5278 try { 5279 $$9(this.containers.contentView).html(this.templates.main({ items: items })); 5280 } 5281 catch (err) { 5282 console.error('MapSVG: Error in the "Directory item" template'); 5283 console.error(err); 5284 } 5285 if (items.length === 0) { 5286 $$9(this.containers.contentView).html('<div class="mapsvg-no-results">' + 5287 this.mapsvg.options.menu.noResultsText + 5288 "</div>"); 5289 } 5290 if (_this.mapsvg.options.menu.categories.on) { 5291 if (_this.mapsvg.options.menu.categories.collapse && items.length > 1) { 5292 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("collapsed"); 5293 } 5294 else if (_this.mapsvg.options.menu.categories.collapse && items.length === 1) { 5295 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5296 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5297 const panel = $$9(this.containers.contentView).find(".mapsvg-category-block")[0]; 5298 panel.style.maxHeight = panel.scrollHeight + "px"; 5299 } 5300 else if (!_this.mapsvg.options.menu.categories.collapse) { 5301 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5302 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5303 const panels = $$9(this.containers.contentView).find(".mapsvg-category-block"); 5304 panels.each(function (i, panel) { 5305 panel.style.maxHeight = panel.scrollHeight + "px"; 5306 }); 5307 } 5308 } 5309 this.updateTopShift(); 5310 this.updateScroll(); 5311 } 5312 toggle(on) { 5313 const _this = this; 5314 if (on) { 5315 $$9(this.containers.main).parent().show(); 5316 $$9(_this.mapsvg.containers.mapContainer).hide(); 5317 $$9(this.menuBtn).addClass("active"); 5318 $$9(this.mapBtn).removeClass("active"); 5319 } 5320 else { 5321 $$9(this.containers.main).parent().hide(); 5322 $$9(_this.mapsvg.containers.mapContainer).show(); 5323 $$9(this.menuBtn).removeClass("active"); 5324 $$9(this.mapBtn).addClass("active"); 5325 } 5326 if (!$$9(this.containers.main).parent().is(":visible")) { 5327 if (MapSVG.isPhone) { 5328 $$9(_this.mapsvg.containers.wrap).css("height", "auto"); 5329 _this.updateScroll(); 5330 } 5331 } 5332 else { 5333 if (MapSVG.isPhone && 5334 $$9(this.containers.main).height() < parseInt(this.mapsvg.options.menu.minHeight)) { 5335 $$9(_this.mapsvg.containers.wrap).css("height", parseInt(this.mapsvg.options.menu.minHeight) + "px"); 5336 _this.updateScroll(); 5337 } 5338 } 5339 this.updateTopShift(); 5340 } 5341 addPagination(pager) { 5342 $$9(this.containers.contentView).append('<div class="mapsvg-pagination-container"></div>'); 5343 $$9(this.containers.contentView).find(".mapsvg-pagination-container").html(pager); 5344 } 5345 } 5346 5347 const $$a = jQuery; 5348 class DetailsController extends Controller { 5349 constructor(options) { 5350 super(options); 5351 this.modal = options.modal; 5352 } 5353 getToolbarTemplate() { 5354 if (this.withToolbar) 5355 return '<div class="mapsvg-popover-close mapsvg-details-close"></div>'; 5356 else 5357 return ""; 5358 } 5359 viewDidLoad() { 5360 const _this = this; 5361 this.events.trigger("shown", _this, [_this]); 5362 if (this.modal &&
5363 MapSVG.isPhone && 5364 this.mapsvg.options.detailsView.mobileFullscreen && 5365 !this.mobileCloseBtn) { 5366 this.mobileCloseBtn = $$a('<button class="mapsvg-mobile-modal-close mapsvg-btn">' + 5367 _this.mapsvg.options.mobileView.labelClose + 5368 "</button>")[0]; 5369 this.containers.view.appendChild(this.mobileCloseBtn); 5370 } 5371 } 5372 setEventHandlers() { 5373 const _this = this; 5374 $$a(this.containers.toolbar).on("click", ".mapsvg-popover-close, .mapsvg-mobile-modal-close", function (e) { 5375 e.stopPropagation(); 5376 _this.destroy(); 5377 _this.events.trigger("closed", _this, [_this]); 5378 }); 5379 } 5380 } 5381 5382 const $$b = jQuery; 5383 class FormElement { 5384 constructor(options, formBuilder, external) { 5385 this.readonly = typeof options.readonly !== "undefined" ? options.readonly : false; 5386 this.protected = typeof options.protected !== "undefined" ? options.protected : false; 5387 this.auto_increment = 5388 typeof options.auto_increment !== "undefined" ? options.auto_increment : false; 5389 this.not_null = typeof options.not_null !== "undefined" ? options.not_null : false; 5390 this.searchable = typeof options.searchable !== "undefined" ? options.searchable : false; 5391 this.visible = typeof options.visible !== "undefined" ? options.visible : true; 5392 this.formBuilder = formBuilder; 5393 this.events = new Events(this); 5394 this.type = options.type; 5395 this.value = options.value; 5396 this.db_type = options.db_type || "varchar(255)"; 5397 this.label = this.label || (options.label === undefined ? "Label" : options.label); 5398 this.name = this.name || options.name || "label"; 5399 this.help = options.help || ""; 5400 this.placeholder = options.placeholder; 5401 this.setExternal(external); 5402 let t = this.type; 5403 if (t === "marker" && this.mapIsGeo) { 5404 t = "marker-geo"; 5405 } 5406 if (t === "location" && this.mapIsGeo) { 5407 t = "location-geo"; 5408 } 5409 if (this.filtersMode) { 5410 this.parameterName = options.parameterName || ""; 5411 this.parameterNameShort = this.parameterName.split(".")[1]; 5412 this.name = this.parameterNameShort; 5413 this.placeholder = options.placeholder || ""; 5414 this.templates = { 5415 main: Handlebars.compile($$b("#mapsvg-filters-tmpl-" + t + "-view").html()), 5416 }; 5417 } 5418 else { 5419 this.templates = { 5420 main: Handlebars.compile($$b("#mapsvg-data-tmpl-" + t + "-view").html()), 5421 }; 5422 } 5423 this.inputs = {}; 5424 } 5425 init() { 5426 this.setDomElements(); 5427 this.setEventHandlers(); 5428 } 5429 setDomElements() { 5430 this.domElements = { 5431 main: $$b(this.templates.main(this.getDataForTemplate()))[0], 5432 }; 5433 $$b(this.domElements.main).data("formElement", this); 5434 this.addSelect2(); 5435 } 5436 setEventHandlers() { 5437 const _this = this; 5438 if (this.formBuilder.editMode) { 5439 $$b(this.domElements.main).on("click", function () { 5440 _this.events.trigger("click", _this, [_this]); 5441 }); 5442 } 5443 } 5444 addSelect2() { 5445 if ($$b().mselect2) { 5446 $$b(this.domElements.main) 5447 .find("select") 5448 .css({ width: "100%", display: "block" }) 5449 .mselect2() 5450 .on("select2:focus", function () { 5451 $$b(this).mselect2("open"); 5452 }); 5453 $$b(this.domElements.main) 5454 .find(".select2-selection--multiple .select2-search__field") 5455 .css("width", "100%"); 5456 } 5457 } 5458 setEditorEventHandlers() { 5459 const _this = this; 5460 $$b(this.domElements.edit).on("click", "button.mapsvg-remove", function () { 5461 $$b(_this.domElements.main).empty().remove(); 5462 $$b(_this.domElements.edit).empty().remove(); 5463 _this.events.trigger("delete", _this, [_this]); 5464 }); 5465 $$b(this.domElements.edit).on("click", ".mapsvg-filter-insert-options", function () { 5466 const objType = _this.parameterName.split(".")[0]; 5467 const fieldName = _this.parameterName.split(".")[1]; 5468 let field; 5469 if (objType == "Object") { 5470 field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 5471 } 5472 else { 5473 if (fieldName == "id") { 5474 const options = []; 5475 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5476 options.push({ label: r.id, value: r.id }); 5477 }); 5478 field = { 5479 options: options, 5480 }; 5481 } 5482 else if (fieldName == "region_title") { 5483 const options = []; 5484 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5485 options.push({ label: r.title, value: r.title }); 5486 }); 5487 field = { options: options }; 5488 } 5489 else { 5490 field = _this.formBuilder.mapsvg.regionsRepository 5491 .getSchema() 5492 .getField(fieldName); 5493 } 5494 } 5495 if (field && field.options) { 5496 let options; 5497 if (fieldName == "regions") { 5498 if (field.options[0].title && field.options[0].title.length) 5499 field.options.sort(function (a, b) { 5500 if (a.title < b.title) 5501 return -1; 5502 if (a.title > b.title) 5503 return 1; 5504 return 0; 5505 }); 5506 options = field.options.map(function (o) { 5507 return (o.title || o.id) + ":" + o.id; 5508 }); 5509 } 5510 else { 5511 options = field.options.map(function (o) { 5512 return o.label + ":" + o.value; 5513 }); 5514 } 5515 $$b(this) 5516 .closest(".form-group") 5517 .find("textarea") 5518 .val(options.join("\n")) 5519 .trigger("change"); 5520 } 5521 }); 5522 $$b(this.domElements.edit).on("keyup change paste", "input, textarea, select", function () { 5523 const prop = $$b(this).attr("name"); 5524 const array = $$b(this).data("array"); 5525 if (_this.type === "status" && array) { 5526 const param = $$b(this).data("param"); 5527 const index = $$b(this).closest("tr").index(); 5528 _this.options[index] = _this.options[index] || { 5529 label: "", 5530 value: "", 5531 color: "", 5532 disabled: false, 5533 }; 5534 _this.options[index][param] = $$b(this).is(":checkbox") 5535 ? $$b(this).prop("checked") 5536 : $$b(this).val(); 5537 _this.redraw(); 5538 } 5539 else if (_this.type === "distance" && array) { 5540 const param = $$b(this).data("param"); 5541 const index = $$b(this).closest("tr").index(); 5542 if (!_this.options[index]) { 5543 _this.options[index] = { value: "", default: false }; 5544 } 5545 if (param === "default") { 5546 _this.options.forEach(function (option) { 5547 option.default = false;
5548 }); 5549 _this.options[index].default = $$b(this).prop("checked"); 5550 } 5551 else { 5552 _this.options[index].value = $$b(this).val(); 5553 } 5554 _this.redraw(); 5555 } 5556 else if (prop == "label" || prop == "name") { 5557 return false; 5558 } 5559 else { 5560 let value; 5561 value = 5562 $$b(this).attr("type") == "checkbox" ? $$b(this).prop("checked") : $$b(this).val(); 5563 if ($$b(this).attr("type") == "radio") { 5564 const name = $$b(this).attr("name"); 5565 value = $$b('input[name="' + name + '"]:checked').val(); 5566 } 5567 _this.update(prop, value); 5568 } 5569 }); 5570 $$b(this.domElements.edit).on("keyup change paste", 'input[name="label"]', function () { 5571 if (!_this.nameChanged) { 5572 _this.label = $$b(this).val() + ""; 5573 if (_this.type != "region" && _this.type != "location" && _this.type != "title") { 5574 let str = $$b(this).val() + ""; 5575 str = str.toLowerCase().replace(/ /g, "_").replace(/\W/g, ""); 5576 if (str.length < 64) { 5577 $$b(_this.domElements.edit).find('input[name="name"]').val(str); 5578 } 5579 _this.name = str + ""; 5580 } 5581 $$b(_this.domElements.main).find("label").first().html(_this.label); 5582 if (!_this.filtersMode) { 5583 $$b(_this.domElements.main) 5584 .find("label") 5585 .first() 5586 .append('<div class="field-name">' + _this.name + "</div>"); 5587 } 5588 } 5589 }); 5590 $$b(this.domElements.edit).on("keyup change paste", 'input[name="name"]', function (e) { 5591 if (e.target.value) { 5592 if (e.target.value.match(/[^a-zA-Z0-9_]/g)) { 5593 e.target.value = e.target.value.replace(/[^a-zA-Z0-9_]/g, ""); 5594 $$b(e.target).trigger("change"); 5595 } 5596 if (e.target.value[0].match(/[^a-zA-Z_]/g)) { 5597 e.target.value = 5598 e.target.value[0].replace(/[^a-zA-Z_]/g, "") + e.target.value.slice(1); 5599 $$b(e.target).trigger("change"); 5600 } 5601 } 5602 if (_this.type != "region") 5603 _this.name = e.target.value; 5604 $$b(_this.domElements.main) 5605 .find("label") 5606 .html(_this.label + '<div class="field-name">' + _this.name + "</div>"); 5607 _this.nameChanged = true; 5608 }); 5609 $$b(this.domElements.edit).on("keyup change paste", 'textarea[name="help"]', function (e) { 5610 $$b(_this.domElements.main).find(".form-text").text(e.target.value); 5611 }); 5612 } 5613 getEditor() { 5614 if (!this.filtersMode) { 5615 this.templates.edit = 5616 this.templates.edit || 5617 Handlebars.compile($$b("#mapsvg-data-tmpl-" + this.type + "-control").html()); 5618 } 5619 else { 5620 this.templates.edit = 5621 this.templates.edit || 5622 Handlebars.compile($$b("#mapsvg-filters-tmpl-" + this.type + "-control").html()); 5623 } 5624 this.domElements.edit = $$b("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>")[0]; 5625 return this.domElements.edit; 5626 } 5627 destroyEditor() { 5628 $$b(this.domElements.edit).empty().remove(); 5629 } 5630 initEditor() { 5631 $$b(this.domElements.edit).find("input").first().select(); 5632 if ($$b().colorpicker) { 5633 $$b(this.domElements.edit) 5634 .find(".cpicker") 5635 .colorpicker() 5636 .on("changeColor.colorpicker", function (event) { 5637 const input = $$b(this).find("input"); 5638 if (input.val() == "") 5639 $$b(this).find("i").css({ "background-color": "" }); 5640 }); 5641 } 5642 if ($$b().mselect2) {
5643 if (this.type !== "distance") { 5644 $$b(this.domElements.edit) 5645 .find("select") 5646 .css({ width: "100%", display: "block" }) 5647 .mselect2(); 5648 } 5649 } 5650 this.setEditorEventHandlers(); 5651 } 5652 getSchema() { 5653 let data; 5654 data = { 5655 type: this.type, 5656 db_type: this.db_type, 5657 label: this.label, 5658 name: this.name, 5659 value: this.value, 5660 searchable: this.searchable, 5661 help: this.help, 5662 visible: this.visible === undefined ? true : this.visible, 5663 readonly: this.readonly, 5664 placeholder: this.placeholder, 5665 protected: this.protected, 5666 auto_increment: this.auto_increment, 5667 not_null: this.not_null, 5668 }; 5669 if (this.options) { 5670 data.options = this.getSchemaFieldOptionsList(); 5671 } 5672 if (this.filtersMode) { 5673 data.parameterName = this.parameterName; 5674 data.parameterNameShort = this.parameterName.split(".")[1]; 5675 } 5676 return data; 5677 } 5678 getSchemaFieldOptionsList() { 5679 const options = []; 5680 this.options.forEach((option, index) => { 5681 if (this.options[index].value !== "") { 5682 options.push(this.options[index]); 5683 } 5684 }); 5685 return options; 5686 } 5687 getDataForTemplate() { 5688 const data = this.getSchema(); 5689 data._name = data.name; 5690 if (this.namespace) { 5691 data.name = this.name.split("[")[0]; 5692 let suffix = this.name.split("[")[1] || ""; 5693 if (suffix) 5694 suffix = "[" + suffix; 5695 data.name = this.namespace + "[" + data.name + "]" + suffix; 5696 } 5697 data.external = this.external; 5698 return data; 5699 } 5700 update(prop, value) { 5701 const _this = this; 5702 if (prop == "options") { 5703 const options = []; 5704 value = value.split("\n").forEach(function (row) { 5705 row = row.trim().split(":"); 5706 if (_this.type == "checkbox" && row.length == 3) { 5707 options.push({ 5708 label: row[0], 5709 name: row[1], 5710 value: row[2], 5711 }); 5712 } 5713 else if ((_this.type == "radio" || 5714 _this.type == "select" || 5715 _this.type == "checkboxes") && 5716 row.length == 2) { 5717 options.push({ 5718 label: row[0], 5719 value: row[1], 5720 }); 5721 } 5722 }); 5723 this.options = options; 5724 } 5725 else { 5726 this[prop] = value; 5727 } 5728 if (prop == "parameterName") { 5729 $$b(this.domElements.edit).find(".mapsvg-filter-param-name").text(value); 5730 } 5731 } 5732 redraw() { 5733 const _this = this; 5734 const newView = $$b(this.templates.main(this.getDataForTemplate())); 5735 $$b(this.domElements.main).html(newView.html()); 5736 if ($$b().mselect2) { 5737 if (this.type !== "distance") { 5738 $$b(this.domElements.main) 5739 .find("select") 5740 .css({ width: "100%", display: "block" }) 5741 .mselect2() 5742 .on("select2:focus", function () { 5743 $$b(this).mselect2("open"); 5744 }); 5745 } 5746 else { 5747 $$b(this.domElements.main) 5748 .find("select") 5749 .mselect2() 5750 .on("select2:focus", function () { 5751 $$b(this).mselect2("open"); 5752 }); 5753 } 5754 } 5755 if (this.domElements.edit) { 5756 $$b(this.domElements.edit).empty(); 5757 $$b(this.domElements.edit).html("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>"); 5758 _this.initEditor(); 5759 } 5760 } 5761 setOptions(options) { 5762 if (options) { 5763 this.options = []; 5764 this.optionsDict = {}; 5765 options.forEach((value, key) => { 5766 this.options.push(value); 5767 this.optionsDict[key] = value; 5768 }); 5769 return this.options; 5770 } 5771 else { 5772 return this.setOptions([ 5773 { label: "Option one", name: "option_one", value: 1 }, 5774 { label: "Option two", name: "option_two", value: 2 }, 5775 ]); 5776 } 5777 } 5778 getData() { 5779 return { name: this.name, value: this.getValue() }; 5780 } 5781 destroy() { 5782 if ($$b().mselect2) { 5783 const sel = $$b(this.domElements.main).find(".mapsvg-select2"); 5784 if (sel.length) { 5785 sel.mselect2("destroy"); 5786 } 5787 } 5788 } 5789 show() { 5790 $$b(this.domElements.main).show(); 5791 } 5792 hide() { 5793 $$b(this.domElements.main).hide(); 5794 } 5795 setExternal(params) { 5796 this.external = params; 5797 if (typeof this.external.mapIsGeo !== "undefined") { 5798 this.mapIsGeo = this.external.mapIsGeo; 5799 } 5800 if (typeof this.external.editMode !== "undefined") { 5801 this.editMode = this.external.editMode; 5802 } 5803 if (typeof this.external.filtersMode !== "undefined") { 5804 this.filtersMode = this.external.filtersMode; 5805 } 5806 if (typeof this.external.namespace !== "undefined") { 5807 this.namespace = this.external.namespace; 5808 } 5809 } 5810 getValue() { 5811 return this.value; 5812 } 5813 setValue(value, updateInput = true) { 5814 this.value = value; 5815 if (updateInput) { 5816 this.setInputValue(value); 5817 } 5818 } 5819 setInputValue(value) { 5820 return; 5821 } 5822 triggerChanged() { 5823 this.events.trigger("changed", this, [this]); 5824 } 5825 } 5826 5827 const $$c = jQuery; 5828 class CheckboxFormElement extends FormElement { 5829 constructor(options, formBuilder, external) { 5830 super(options, formBuilder, external); 5831 if (typeof options.showAsSwitch === "undefined") { 5832 this.showAsSwitch = true; 5833 } 5834 else { 5835 this.showAsSwitch = options.showAsSwitch; 5836 } 5837 this.db_type = "tinyint(1)"; 5838 this.checkboxLabel = options.checkboxLabel; 5839 this.checkboxValue = options.checkboxValue; 5840 } 5841 setDomElements() { 5842 super.setDomElements(); 5843 this.inputs.checkbox = $$c(this.domElements.main).find("input")[0]; 5844 this.inputs.switch = $$c(this.domElements.main).find("input")[0]; 5845 } 5846 setEventHandlers() { 5847 super.setEventHandlers(); 5848 $$c(this.inputs.checkbox).on("change", (e) => { 5849 this.setValue(e.target.checked, false); 5850 this.triggerChanged(); 5851 }); 5852 } 5853 setEditorEventHandlers() { 5854 super.setEditorEventHandlers(); 5855 $$c(this.domElements.edit).on("change", "[name='showAsSwitch']", (e) => { 5856 if (this.showAsSwitch) { 5857 $$c(this.domElements.main) 5858 .find("[name='checkboxToSwitch']") 5859 .addClass("form-switch form-check form-switch-md"); 5860 } 5861 if (!this.showAsSwitch) { 5862 $$c(this.domElements.main) 5863 .find("[name='checkboxToSwitch']") 5864 .removeClass("form-switch form-check form-switch-md"); 5865 } 5866 }); 5867 $$c(this.domElements.edit).on("keyup change paste", '[name="checkboxLabel"]',
5867(e) => { 5868 $$c(this.domElements.main).find(".form-check-label").text(e.target.value); 5869 }); 5870 } 5871 getSchema() { 5872 const schema = super.getSchema(); 5873 if (this.checkboxLabel) { 5874 schema.checkboxLabel = this.checkboxLabel; 5875 } 5876 if (this.checkboxValue) { 5877 schema.checkboxValue = this.checkboxValue; 5878 } 5879 schema.showAsSwitch = this.showAsSwitch; 5880 return schema; 5881 } 5882 setInputValue(value) { 5883 this.inputs.checkbox.checked = value === true; 5884 } 5885 } 5886 5887 const $$d = jQuery; 5888 class CheckboxesFormElement extends FormElement { 5889 constructor(options, formBuilder, external) { 5890 super(options, formBuilder, external); 5891 this.db_type = "text"; 5892 this.checkboxLabel = options.checkboxLabel; 5893 this.setOptions(options.options); 5894 } 5895 setDomElements() { 5896 super.setDomElements(); 5897 this.$checkboxes = $$d(this.domElements.main).find('input[type="checkbox"]'); 5898 this.setInputValue(this.value || []); 5899 } 5900 setEventHandlers() { 5901 super.setEventHandlers(); 5902 this.$checkboxes.on("change", (e) => { 5903 const values = []; 5904 $$d(this.domElements.main) 5905 .find("input:checked") 5906 .each((i, el) => { 5907 values.push(jQuery(el).attr("value")); 5908 }); 5909 this.setValue(values, false); 5910 this.triggerChanged(); 5911 }); 5912 } 5913 setInputValue(values) { 5914 values.forEach((value) => { 5915 $$d(this.domElements.main).find(`input[value="${value}"]`).prop("checked", true); 5916 }); 5917 } 5918 } 5919 5920 const $$e = jQuery; 5921 class DateFormElement extends FormElement { 5922 constructor(options, formBuilder, external) { 5923 super(options, formBuilder, external); 5924 if (this.formBuilder.admin) { 5925 this.languages = [ 5926 "en-GB", 5927 "ar", 5928 "az", 5929 "bg", 5930 "bs", 5931 "ca", 5932 "cs", 5933 "cy", 5934 "da", 5935 "de", 5936 "el", 5937 "es", 5938 "et", 5939 "eu", 5940 "fa", 5941 "fi", 5942 "fo", 5943 "fr", 5944 "gl", 5945 "he", 5946 "hr", 5947 "hu", 5948 "hy", 5949 "id", 5950 "is", 5951 "it", 5952 "ja", 5953 "ka", 5954 "kh", 5955 "kk", 5956 "kr", 5957 "lt", 5958 "lv", 5959 "mk", 5960 "ms", 5961 "nb", 5962 "nl", 5963 "nl-BE", 5964 "no", 5965 "pl", 5966 "pt-BR", 5967 "pt", 5968 "ro", 5969 "rs", 5970 "rs-latin", 5971 "ru", 5972 "sk", 5973 "sl", 5974 "sq", 5975 "sr", 5976 "sr-latin", 5977 "sv", 5978 "sw", 5979 "th", 5980 "tr", 5981 "uk", 5982 "vi", 5983 "zh-CN", 5984 "zh-TW", 5985 ]; 5986 } 5987 this.db_type = "varchar(50)"; 5988 this.language = options.language; 5989 } 5990 setDomElements() { 5991 super.setDomElements(); 5992 this.inputs.date = $$e(this.domElements.main).find("input")[0]; 5993 } 5994 setEventHandlers() { 5995 super.setEventHandlers(); 5996 $$e(this.inputs.date).on("change", (e) => { 5997 this.setValue(e.target.value, false); 5998 this.triggerChanged(); 5999 }); 6000 } 6001 getSchema() { 6002 const schema = super.getSchema(); 6003 schema.language = this.language; 6004 return schema; 6005 } 6006 getDataForTemplate() { 6007 const data = super.getDataForTemplate(); 6008 if (this.formBuilder.admin) 6009 data.languages = this.languages; 6010 data.language = this.language; 6011 return data; 6012 } 6013 } 6014 6015 const $$f = jQuery; 6016 class DistanceFormElement extends FormElement { 6017 constructor(options, formBuilder, external) { 6018 super(options, formBuilder, external); 6019 this.name = "distance"; 6020 this.label = this.label || (options.label === undefined ? "Search radius" : options.label); 6021 this.distanceControl = options.distanceControl || "select"; 6022 this.distanceUnits = options.distanceUnits || "km"; 6023 this.distanceUnitsLabel = options.distanceUnitsLabel || "km"; 6024 this.fromLabel = options.fromLabel || "from"; 6025 this.placeholder = options.placeholder; 6026 this.userLocationButton = options.userLocationButton || false; 6027 this.type = options.type; 6028 this.addressField = options.addressField || true; 6029 this.addressFieldPlaceholder = options.addressFieldPlaceholder || "Address"; 6030 this.languages = [ 6031 { value: "sq", label: "Albanian" }, 6032 { value: "ar", label: "Arabic" }, 6033 { 6034 value: "eu", 6035 label: "Basque", 6036 }, 6037 { value: "be", label: "Belarusian" }, 6038 { value: "bg", label: "Bulgarian" }, 6039 { 6040 value: "my", 6041 label: "Burmese", 6042 }, 6043 { value: "bn", label: "Bengali" }, 6044 { value: "ca", label: "Catalan" }, 6045 { 6046 value: "zh-cn", 6047 label: "Chinese (simplified)", 6048 }, 6049 { value: "zh-tw", label: "Chinese (traditional)" }, 6050 { 6051 value: "hr", 6052 label: "Croatian", 6053 }, 6054 { value: "cs", label: "Czech" }, 6055 { value: "da", label: "Danish" }, 6056 { 6057 value: "nl", 6058 label: "Dutch", 6059 }, 6060 { value: "en", label: "English" }, 6061 { 6062 value: "en-au", 6063 label: "English (australian)", 6064 }, 6065 { value: "en-gb", label: "English (great Britain)" }, 6066 { 6067 value: "fa", 6068 label: "Farsi", 6069 }, 6070 { value: "fi", label: "Finnish" }, 6071 { value: "fil", label: "Filipino" }, 6072 { 6073 value: "fr", 6074 label: "French", 6075 }, 6076 { value: "gl", label: "Galician" }, 6077 { value: "de", label: "German" }, 6078 { 6079 value: "el", 6080 label: "Greek", 6081 }, 6082 { value: "gu", label: "Gujarati" }, 6083 { value: "iw", label: "Hebrew" }, 6084 { 6085 value: "hi", 6086 label: "Hindi", 6087 }, 6088 { value: "hu", label: "Hungarian" }, 6089 { value: "id", label: "Indonesian" }, 6090 { 6091 value: "it", 6092 label: "Italian", 6093 }, 6094 { value: "ja", label: "Japanese" }, 6095 { value: "kn", label: "Kannada" }, 6096 { 6097 value: "kk", 6098 label: "Kazakh", 6099 }, 6100 { value: "ko", label: "Korean" }, 6101 { value: "ky", label: "Kyrgyz" }, 6102 { 6103 value: "lt", 6104 label: "Lithuanian", 6105 }, 6106 { value: "lv", label: "Latvian" }, 6107 { value: "mk", label: "Macedonian" }, 6108 { 6109 value: "ml", 6110 label: "Malayalam", 6111 }, 6112 { value: "mr", label: "Marathi" },
6113 { value: "no", label: "Norwegian" }, 6114 { 6115 value: "pl", 6116 label: "Polish", 6117 }, 6118 { value: "pt", label: "Portuguese" }, 6119 { 6120 value: "pt-br", 6121 label: "Portuguese (brazil)", 6122 }, 6123 { value: "pt-pt", label: "Portuguese (portugal)" }, 6124 { 6125 value: "pa", 6126 label: "Punjabi", 6127 }, 6128 { value: "ro", label: "Romanian" }, 6129 { value: "ru", label: "Russian" }, 6130 { 6131 value: "sr", 6132 label: "Serbian", 6133 }, 6134 { value: "sk", label: "Slovak" }, 6135 { value: "sl", label: "Slovenian" }, 6136 { 6137 value: "es", 6138 label: "Spanish", 6139 }, 6140 { value: "sv", label: "Swedish" }, 6141 { value: "tl", label: "Tagalog" }, 6142 { 6143 value: "ta", 6144 label: "Tamil", 6145 }, 6146 { value: "te", label: "Telugu" }, 6147 { value: "th", label: "Thai" }, 6148 { 6149 value: "tr", 6150 label: "Turkish", 6151 }, 6152 { value: "uk", label: "Ukrainian" }, 6153 { value: "uz", label: "Uzbek" }, 6154 { 6155 value: "vi", 6156 label: "Vietnamese", 6157 }, 6158 ]; 6159 this.countries = MapSVG.countries; 6160 this.country = options.country; 6161 this.language = options.language; 6162 this.searchByZip = options.searchByZip; 6163 this.zipLength = options.zipLength || 5; 6164 this.userLocationButton = MapSVG.parseBoolean(options.userLocationButton); 6165 this.options = options.options || [ 6166 { value: "10", default: true }, 6167 { value: "30", default: false }, 6168 { value: "50", default: false }, 6169 { value: "100", default: false }, 6170 ]; 6171 let selected = false; 6172 if (this.value) { 6173 this.options.forEach((option) => { 6174 if (option.value === this.value.length) { 6175 option.selected = true; 6176 selected = true; 6177 } 6178 }); 6179 } 6180 if (!selected) { 6181 this.options.forEach(function (option) { 6182 if (option.default) { 6183 option.selected = true; 6184 } 6185 }); 6186 } 6187 const defLengthOption = this.options.find((opt) => opt.selected === true); 6188 this.defaultLength = defLengthOption.value; 6189 this.setDefaultValue(); 6190 } 6191 setDefaultValue() { 6192 this.value = { 6193 units: this.distanceUnits, 6194 geoPoint: { lat: null, lng: null }, 6195 length: this.defaultLength, 6196 address: "", 6197 country: this.country, 6198 }; 6199 } 6200 setDomElements() { 6201 super.setDomElements(); 6202 this.inputs.units = ($$f(this.domElements.main).find('[name="distanceUnits"]')[0]); 6203 this.inputs.geoPoint = ($$f(this.domElements.main).find('[name="distanceGeoPoint"]')[0]); 6204 this.inputs.length = ($$f(this.domElements.main).find('[name="distanceLength"]')[0]); 6205 this.inputs.address = ($$f(this.domElements.main).find('[name="distanceAddress"]')[0]); 6206 } 6207 getSchema() { 6208 const schema = super.getSchema(); 6209 schema.distanceControl = this.distanceControl; 6210 schema.distanceUnits = this.distanceUnits; 6211 schema.distanceUnitsLabel = this.distanceUnitsLabel; 6212 schema.fromLabel = this.fromLabel; 6213 schema.addressField = this.addressField; 6214 schema.addressFieldPlaceholder = this.addressFieldPlaceholder; 6215 schema.userLocationButton = this.userLocationButton; 6216 schema.placeholder = this.placeholder; 6217 schema.language = this.language; 6218 schema.country = this.country; 6219 schema.searchByZip = this.searchByZip; 6220 schema.zipLength = this.zipLength; 6221 schema.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6222 if (schema.distanceControl === "none") { 6223 schema.distanceDefault = schema.options.filter(function (o) { 6224 return o.default; 6225 })[0].value; 6226 } 6227 schema.options.forEach(function (option, index) { 6228 if (schema.options[index].value === "") { 6229 schema.options.splice(index, 1); 6230 } 6231 else { 6232 schema.options[index].default = MapSVG.parseBoolean(schema.options[index].default); 6233 } 6234 }); 6235 return schema; 6236 } 6237 getDataForTemplate() { 6238 const data = super.getDataForTemplate(); 6239 if (this.formBuilder.admin) { 6240 data.languages = this.languages; 6241 data.countries = this.countries; 6242 } 6243 data.language = this.language; 6244 data.country = this.country; 6245 data.searchByZip = this.searchByZip; 6246 data.zipLength = this.zipLength; 6247 data.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6248 return data; 6249 } 6250 destroy() { 6251 if ($$f().mselect2) { 6252 const sel = $$f(this.domElements.main).find(".mapsvg-select2"); 6253 if (sel.length) { 6254 sel.mselect2("destroy"); 6255 } 6256 } 6257 } 6258 initEditor() { 6259 super.initEditor(); 6260 this.mayBeAddDistanceRow(); 6261 if ($$f().mselect2) { 6262 $$f(this.domElements.edit).find("select").mselect2(); 6263 } 6264 } 6265 setEventHandlers() { 6266 super.setEventHandlers(); 6267 const _this = this; 6268 $$f(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-distance-row input", function () { 6269 _this.mayBeAddDistanceRow(); 6270 }); 6271 const server = new Server(); 6272 const locations = new Bloodhound({ 6273 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 6274 queryTokenizer: Bloodhound.tokenizers.whitespace, 6275 remote: { 6276 url: server.getUrl("geocoding") + 6277 "?address=" + 6278 (this.searchByZip === true ? "zip%20" : "") + 6279 "%QUERY%&language=" + 6280 this.language + 6281 (this.country ? "&country=" + this.country : ""), 6282 wildcard: "%QUERY%", 6283 transform: function (response) { 6284 if (response.error_message) { 6285 alert(response.error_message); 6286 } 6287 return response.results; 6288 }, 6289 rateLimitWait: 600, 6290 }, 6291 }); 6292 const thContainer = $$f(this.domElements.main).find(".typeahead"); 6293 if (this.searchByZip) { 6294 $$f(this.domElements.main).find(".mapsvg-distance-fields").addClass("search-by-zip"); 6295 thContainer.on("change keyup", (e) => { 6296 if ($$f(e.target).val().toString().length === _this.zipLength) { 6297 locations.search($$f(e.target).val(), null, (data) => { 6298 if (data && data[0]) { 6299 this.setValue({ geoPoint: data[0].geometry.location }); 6300 this.triggerChanged(); 6301 } 6302 }); 6303 } 6304 }); 6305 } 6306 else { 6307 const spinner = $$f("<span class='spinner-border spinner-border-sm'></span>"); 6308 const tH = thContainer 6309 .typeahead({ minLength: 3 }, { 6310 name: "mapsvg-addresses", 6311 display: "formatted_address", 6312 source: locations, 6313 limit: 5, 6314 }) 6315 .on("typeahead:asyncrequest", function (e) { 6316 spinner.appendTo($$f(e.target).closest(".twitter-typeahead")); 6317 }) 6318 .on("typeahead:asynccancel typeahead:asyncreceive", function (e) { 6319 spinner.remove(); 6320 }); 6321 $$f(this.domElements.main).find(".mapsvg-distance-fields").removeClass("search-by-zip"); 6322 } 6323 if (_this.userLocationButton) { 6324 const userLocationButton = $$f(this.domElements.main).find(".user-location-button"); 6325 userLocationButton.on("click", () => { 6326 _this.formBuilder.mapsvg.showUserLocation((location) => { 6327 locations.search(location.geoPoint.lat + "," + location.geoPoint.lng, null, function (data) { 6328 if (data && data[0]) { 6329 _this.setAddress(data[0].formatted_address); 6330 } 6331 else { 6332 _this.setAddress(location.geoPoint.lat + "," + location.geoPoint.lng); 6333 } 6334 }); 6335 this.setValue({ geoPoint: location.geoPoint }); 6336 this.triggerChanged(); 6337 }); 6338 }); 6339 } 6340 thContainer.on("change keyup", (e) => { 6341 const input = e.target; 6342 if (input.value === "" && this.getValue() !== null) { 6343 this.setValue(null); 6344 this.triggerChanged(); 6345 } 6346 }); 6347 thContainer.on("typeahead:select", (ev, item) => { 6348 this.setValue({ address: item.formatted_address, geoPoint: item.geometry.location }); 6349 this.triggerChanged(); 6350 thContainer.blur(); 6351 }); 6352 $$f(this.inputs.geoPoint).on("change", (e) => { 6353 const geoPoint = e.target.value.split(",").map((value) => parseFloat(value)); 6354 this.setValue({ geoPoint: { lat: geoPoint[0], lng: geoPoint[1] } }, false); 6355 this.triggerChanged(); 6356 }); 6357 $$f(this.inputs.length).on("change", (e) => { 6358 this.setLength(parseInt(e.target.value), false); 6359 this.triggerChanged(); 6360 }); 6361 } 6362 addSelect2() { 6363 if ($$f().mselect2) { 6364 $$f(this.domElements.main) 6365 .find("select") 6366 .mselect2() 6367 .on("select2:focus", function () { 6368 $$f(this).mselect2("open"); 6369 }); 6370 } 6371 } 6372 mayBeAddDistanceRow() { 6373 const _this = this; 6374 const editDistanceRow = $$f($$f("#mapsvg-edit-distance-row").html()); 6375 const z = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 6376 if (z && z.last() && z.last().val() && z.last().val().toString().trim().length) { 6377 const newRow = editDistanceRow.clone(); 6378 newRow.insertAfter($$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 6379 } 6380 const rows = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 6381 const row1 = rows.eq(rows.length - 2); 6382 const row2 = rows.eq(rows.length - 1); 6383 if (row1.length && 6384 row2.length && 6385 !row1.find("input:eq(0)").val().toString().trim() && 6386 !row2.find("input:eq(0)").val().toString().trim()) { 6387 row2.remove(); 6388 } 6389 } 6390 setValue(value, updateInput = true) { 6391 if (value === null) { 6392 this.setGeoPoint(null); 6393 this.setAddress(""); 6394 } 6395 else { 6396 for (const key in value) { 6397 if (typeof this.value[key] !== undefined) { 6398 const method = "set" + MapSVG.ucfirst(key); 6399 if (typeof this[method] === "function") { 6400 this[method](value[key], updateInput); 6401 } 6402 } 6403 } 6404 } 6405 } 6406 setGeoPoint(geoPoint, updateInput = true) { 6407 this.value.geoPoint = geoPoint === null ? { lat: null, lng: null } : geoPoint; 6408 if (updateInput) { 6409 this.setInputGeoPointValue(geoPoint); 6410 } 6411 } 6412 setInputGeoPointValue(geoPoint) { 6413 this.inputs.geoPoint.value = geoPoint ? geoPoint.lat + "," + geoPoint.lng : ""; 6414 } 6415 setLength(length, updateInput = true) { 6416 this.value.length = parseInt(length.toString()); 6417 this.defaultLength = this.value.length; 6418 if (updateInput) { 6419 this.setInputLengthValue(this.value.length); 6420 } 6421 } 6422 setInputLengthValue(length) { 6423 this.inputs.length.value = length.toString(); 6424 } 6425 setAddress(address, updateInput = true) { 6426 this.value.address = address !== null ? address : ""; 6427 if (updateInput) { 6428 this.setInputAddressValue(this.value.address); 6429 } 6430 } 6431 setInputAddressValue(address) { 6432 this.inputs.address.value = address; 6433 } 6434 getValue() { 6435 return this.value.geoPoint.lat === null ? null : this.value; 6436 } 6437 } 6438 6439 const $$g = jQuery; 6440 class EmptyFormElement extends FormElement { 6441 constructor(options, formBuilder, external) { 6442 super(options, formBuilder, external); 6443 this.readonly = true; 6444 } 6445 } 6446 6447 class IdFormElement extends FormElement { 6448 constructor(options, formBuilder, external) { 6449 super(options, formBuilder, external); 6450 } 6451 getData() { 6452 return { name: "id", value: this.value }; 6453 } 6454 } 6455 6456 function createCommonjsModule(fn, module) { 6457 return module = { exports: {} }, fn(module, module.exports), module.exports; 6458 } 6459 6460 var sortable_min = createCommonjsModule(function (module) { 6461 /**! 6462 * Sortable 6463 * @author RubaXa <[email protected]> 6464 * @license MIT 6465 */ 6466 6467 (function sortableModule(factory) { 6468 6469 { 6470 module.exports = factory(); 6471 } 6472 })(function sortableFactory() { 6473 6474 if (typeof window == "undefined" || !window.document) { 6475 return function sortableError() { 6476 throw new Error("Sortable.js requires a window with a document"); 6477 }; 6478 } 6479 6480 var dragEl, 6481 parentEl, 6482 ghostEl, 6483 cloneEl, 6484 rootEl, 6485 nextEl, 6486 scrollEl, 6487 scrollParentEl, 6488 scrollCustomFn, 6489 lastEl, 6490 lastCSS, 6491 lastParentCSS, 6492 oldIndex, 6493 newIndex, 6494 activeGroup, 6495 putSortable, 6496 autoScroll = {}, 6497 tapEvt, 6498 touchEvt, 6499 moved, 6500 /** @const */ 6501 RSPACE = /\s+/g, 6502 expando = "Sortable" + new Date().getTime(), 6503 win = window, 6504 document = win.document, 6505 parseInt = win.parseInt, 6506 $ = win.jQuery || win.Zepto, 6507 Polymer = win.Polymer, 6508 supportDraggable = !!("draggable" in document.createElement("div")), 6509 supportCssPointerEvents = (function (el) { 6510 // false when IE11 6511 if (navigator.userAgent.match(/Trident.*rv[ :]?11\./)) { 6512 return false;
6513 } 6514 el = document.createElement("x"); 6515 el.style.cssText = "pointer-events:auto"; 6516 return el.style.pointerEvents === "auto"; 6517 })(), 6518 _silent = false, 6519 abs = Math.abs, 6520 min = Math.min, 6521 touchDragOverListeners = [], 6522 _autoScroll = _throttle(function ( 6523 /**Event*/ evt, 6524 /**Object*/ options, 6525 /**HTMLElement*/ rootEl 6526 ) { 6527 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 6528 if (rootEl && options.scroll) { 6529 var el, 6530 rect, 6531 sens = options.scrollSensitivity, 6532 speed = options.scrollSpeed, 6533 x = evt.clientX, 6534 y = evt.clientY, 6535 winWidth = window.innerWidth, 6536 winHeight = window.innerHeight, 6537 vx, 6538 vy, 6539 scrollOffsetX, 6540 scrollOffsetY; 6541 6542 // Delect scrollEl 6543 if (scrollParentEl !== rootEl) { 6544 scrollEl = options.scroll; 6545 scrollParentEl = rootEl; 6546 scrollCustomFn = options.scrollFn; 6547 6548 if (scrollEl === true) { 6549 scrollEl = rootEl; 6550 6551 do { 6552 if ( 6553 scrollEl.offsetWidth < scrollEl.scrollWidth || 6554 scrollEl.offsetHeight < scrollEl.scrollHeight 6555 ) { 6556 break; 6557 } 6558 /* jshint boss:true */ 6559 } while ((scrollEl = scrollEl.parentNode)); 6560 } 6561 } 6562 6563 if (scrollEl) { 6564 el = scrollEl; 6565 rect = scrollEl.getBoundingClientRect(); 6566 vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); 6567 vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); 6568 } 6569 6570 if (!(vx || vy)) { 6571 vx = (winWidth - x <= sens) - (x <= sens); 6572 vy = (winHeight - y <= sens) - (y <= sens); 6573 6574 /* jshint expr:true */ 6575 (vx || vy) && (el = win); 6576 } 6577 6578 if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) { 6579 autoScroll.el = el; 6580 autoScroll.vx = vx; 6581 autoScroll.vy = vy; 6582 6583 clearInterval(autoScroll.pid); 6584 6585 if (el) { 6586 autoScroll.pid = setInterval(function () { 6587 scrollOffsetY = vy ? vy * speed : 0; 6588 scrollOffsetX = vx ? vx * speed : 0; 6589 6590 if ("function" === typeof scrollCustomFn) { 6591 return scrollCustomFn.call( 6592 _this, 6593 scrollOffsetX, 6594 scrollOffsetY, 6595 evt 6596 ); 6597 } 6598 6599 if (el === win) { 6600 win.scrollTo( 6601 win.pageXOffset + scrollOffsetX, 6602 win.pageYOffset + scrollOffsetY 6603 ); 6604 } else { 6605 el.scrollTop += scrollOffsetY; 6606 el.scrollLeft += scrollOffsetX; 6607 } 6608 }, 24); 6609 } 6610 } 6611 } 6612 }, 6613 30), 6614 _prepareGroup = function (options) { 6615 function toFn(value, pull) { 6616 if (value === void 0 || value === true) { 6617 value = group.name; 6618 } 6619 6620 if (typeof value === "function") { 6621 return value; 6622 } else { 6623 return function (to, from) { 6624 var fromGroup = from.options.group.name; 6625 6626 return pull 6627 ? value 6628 : value && 6629 (value.join ? value.indexOf(fromGroup) > -1 : fromGroup == value); 6630 }; 6631 } 6632 } 6633 6634 var group = {}; 6635 var originalGroup = options.group; 6636 6637 if (!originalGroup || typeof originalGroup != "object") { 6638 originalGroup = { name: originalGroup }; 6639 } 6640 6641 group.name = originalGroup.name; 6642 group.checkPull = toFn(originalGroup.pull, true); 6643 group.checkPut = toFn(originalGroup.put); 6644 6645 options.group = group; 6646 }; 6647 /** 6648 * @class Sortable 6649 * @param {HTMLElement} el 6650 * @param {Object} [options] 6651 */ 6652 function Sortable(el, options) { 6653 if (!(el && el.nodeType && el.nodeType === 1)) { 6654 throw "Sortable: `el` must be HTMLElement, and not " + {}.toString.call(el); 6655 } 6656 6657 this.el = el; // root element 6658 this.options = options = _extend({}, options); 6659 6660 // Export instance 6661 el[expando] = this; 6662 6663 // Default options 6664 var defaults = { 6665 group: Math.random(), 6666 sort: true, 6667 disabled: false, 6668 store: null, 6669 handle: null, 6670 scroll: true, 6671 scrollSensitivity: 30, 6672 scrollSpeed: 10, 6673 draggable: /[uo]l/i.test(el.nodeName) ? "li" : ">*", 6674 ghostClass: "sortable-ghost", 6675 chosenClass: "sortable-chosen", 6676 dragClass: "sortable-drag", 6677 ignore: "a, img", 6678 filter: null, 6679 animation: 0, 6680 setData: function (dataTransfer, dragEl) { 6681 dataTransfer.setData("Text", dragEl.textContent); 6682 }, 6683 dropBubble: false, 6684 dragoverBubble: false, 6685 dataIdAttr: "data-id", 6686 delay: 0, 6687 forceFallback: false, 6688 fallbackClass: "sortable-fallback", 6689 fallbackOnBody: false, 6690 fallbackTolerance: 0, 6691 fallbackOffset: { x: 0, y: 0 }, 6692 }; 6693 6694 // Set default options 6695 for (var name in defaults) { 6696 !(name in options) && (options[name] = defaults[name]); 6697 } 6698 6699 _prepareGroup(options); 6700 6701 // Bind all private methods 6702 for (var fn in this) { 6703 if (fn.charAt(0) === "_" && typeof this[fn] === "function") { 6704 this[fn] = this[fn].bind(this); 6705 } 6706 } 6707 6708 // Setup drag mode 6709 this.nativeDraggable = options.forceFallback ? false : supportDraggable; 6710 6711 // Bind events 6712 _on(el, "mousedown", this._onTapStart); 6713 _on(el, "touchstart", this._onTapStart); 6714 6715 if (this.nativeDraggable) { 6716 _on(el, "dragover", this); 6717 _on(el, "dragenter", this); 6718 } 6719 6720 touchDragOverListeners.push(this._onDragOver); 6721 6722 // Restore sorting 6723 options.store && this.sort(options.store.get(this)); 6724 } 6725 6726 Sortable.prototype = /** @lends Sortable.prototype */ { 6727 constructor: Sortable, 6728 6729 _onTapStart: function (/** Event|TouchEvent */ evt) { 6730 if (evt.target.tagName == "i" || evt.target.tagName == "I") { 6731 evt.target.click(); 6732 return; 6733 } 6734 var _this = this, 6735 el = this.el, 6736 options = this.options, 6737 type = evt.type, 6738 touch = evt.touches && evt.touches[0], 6739 target = (touch || evt).target, 6740 originalTarget = (evt.target.shadowRoot && evt.path[0]) || target, 6741 filter = options.filter, 6742 startIndex; 6743 6744 // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. 6745 if (dragEl) { 6746 return; 6747 } 6748 6749 if ((type === "mousedown" && evt.button !== 0) || options.disabled) { 6750 return; // only left button or enabled 6751 } 6752 6753 if (options.handle && !_closest(originalTarget, options.handle, el)) { 6754 return; 6755 } 6756 6757 target = _closest(target, options.draggable, el); 6758 6759 if (!target) { 6760 return; 6761 } 6762 6763 // Get the index of the dragged element within its parent 6764 startIndex = _index(target, options.draggable); 6765 6766 // Check filter 6767 if (typeof filter === "function") { 6768 if (filter.call(this, evt, target, this)) { 6769 _dispatchEvent(_this, originalTarget, "filter", target, el, startIndex); 6770 evt.preventDefault(); 6771 return; // cancel dnd 6772 } 6773 } else if (filter) {
6774 filter = filter.split(",").some(function (criteria) { 6775 criteria = _closest(originalTarget, criteria.trim(), el); 6776 6777 if (criteria) { 6778 _dispatchEvent(_this, criteria, "filter", target, el, startIndex); 6779 return true; 6780 } 6781 }); 6782 6783 if (filter) { 6784 evt.preventDefault(); 6785 return; // cancel dnd 6786 } 6787 } 6788 6789 // Prepare `dragstart` 6790 this._prepareDragStart(evt, touch, target, startIndex); 6791 }, 6792 6793 _prepareDragStart: function ( 6794 /** Event */ evt, 6795 /** Touch */ touch, 6796 /** HTMLElement */ target, 6797 /** Number */ startIndex 6798 ) { 6799 var _this = this, 6800 el = _this.el, 6801 options = _this.options, 6802 ownerDocument = el.ownerDocument, 6803 dragStartFn; 6804 6805 if (target && !dragEl && target.parentNode === el) { 6806 tapEvt = evt; 6807 6808 rootEl = el; 6809 dragEl = target; 6810 parentEl = dragEl.parentNode; 6811 nextEl = dragEl.nextSibling; 6812 activeGroup = options.group; 6813 oldIndex = startIndex; 6814 6815 this._lastX = (touch || evt).clientX; 6816 this._lastY = (touch || evt).clientY; 6817 6818 dragEl.style["will-change"] = "transform"; 6819 6820 dragStartFn = function () { 6821 // Delayed drag has been triggered 6822 // we can re-enable the events: touchmove/mousemove 6823 _this._disableDelayedDrag(); 6824 6825 // Make the element draggable 6826 dragEl.draggable = _this.nativeDraggable; 6827 6828 // Chosen item 6829 _toggleClass(dragEl, options.chosenClass, true); 6830 6831 // Bind the events: dragstart/dragend 6832 _this._triggerDragStart(touch); 6833 6834 // Drag start event 6835 _dispatchEvent(_this, rootEl, "choose", dragEl, rootEl, oldIndex); 6836 }; 6837 6838 // Disable "draggable" 6839 options.ignore.split(",").forEach(function (criteria) { 6840 _find(dragEl, criteria.trim(), _disableDraggable); 6841 }); 6842 6843 _on(ownerDocument, "mouseup", _this._onDrop); 6844 _on(ownerDocument, "touchend", _this._onDrop); 6845 _on(ownerDocument, "touchcancel", _this._onDrop); 6846 6847 if (options.delay) { 6848 // If the user moves the pointer or let go the click or touch 6849 // before the delay has been reached: 6850 // disable the delayed drag 6851 _on(ownerDocument, "mouseup", _this._disableDelayedDrag); 6852 _on(ownerDocument, "touchend", _this._disableDelayedDrag); 6853 _on(ownerDocument, "touchcancel", _this._disableDelayedDrag); 6854 _on(ownerDocument, "mousemove", _this._disableDelayedDrag); 6855 _on(ownerDocument, "touchmove", _this._disableDelayedDrag); 6856 6857 _this._dragStartTimer = setTimeout(dragStartFn, options.delay); 6858 } else { 6859 dragStartFn(); 6860 } 6861 } 6862 }, 6863 6864 _disableDelayedDrag: function () { 6865 var ownerDocument = this.el.ownerDocument; 6866 6867 clearTimeout(this._dragStartTimer); 6868 _off(ownerDocument, "mouseup", this._disableDelayedDrag); 6869 _off(ownerDocument, "touchend", this._disableDelayedDrag); 6870 _off(ownerDocument, "touchcancel", this._disableDelayedDrag); 6871 _off(ownerDocument, "mousemove", this._disableDelayedDrag); 6872 _off(ownerDocument, "touchmove", this._disableDelayedDrag); 6873 }, 6874 6875 _triggerDragStart: function (/** Touch */ touch) { 6876 if (touch) { 6877 // Touch device support 6878 tapEvt = { 6879 target: dragEl, 6880 clientX: touch.clientX, 6881 clientY: touch.clientY, 6882 }; 6883 6884 this._onDragStart(tapEvt, "touch"); 6885 } else if (!this.nativeDraggable) { 6886 this._onDragStart(tapEvt, true); 6887 } else { 6888 _on(dragEl, "dragend", this); 6889 _on(rootEl, "dragstart", this._onDragStart); 6890 } 6891 6892 try { 6893 if (document.selection) { 6894 // Timeout neccessary for IE9 6895 setTimeout(function () { 6896 document.selection.empty(); 6897 }); 6898 } else { 6899 window.getSelection().removeAllRanges(); 6900 } 6901 } catch (err) {} 6902 }, 6903 6904 _dragStarted: function () { 6905 if (rootEl && dragEl) { 6906 var options = this.options; 6907 6908 // Apply effect 6909 _toggleClass(dragEl, options.ghostClass, true); 6910 _toggleClass(dragEl, options.dragClass, false); 6911 6912 Sortable.active = this; 6913 6914 // Drag start event 6915 _dispatchEvent(this, rootEl, "start", dragEl, rootEl, oldIndex); 6916 } 6917 }, 6918 6919 _emulateDragOver: function () { 6920 if (touchEvt) { 6921 if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) { 6922 return; 6923 } 6924 6925 this._lastX = touchEvt.clientX; 6926 this._lastY = touchEvt.clientY; 6927 6928 if (!supportCssPointerEvents) { 6929 _css(ghostEl, "display", "none"); 6930 } 6931 6932 var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), 6933 parent = target, 6934 i = touchDragOverListeners.length; 6935 6936 if (parent) { 6937 do { 6938 if (parent[expando]) { 6939 while (i--) { 6940 touchDragOverListeners[i]({ 6941 clientX: touchEvt.clientX, 6942 clientY: touchEvt.clientY, 6943 target: target, 6944 rootEl: parent, 6945 }); 6946 } 6947 6948 break; 6949 } 6950 6951 target = parent; // store last element 6952 } while ( 6953 /* jshint boss:true */ 6954 (parent = parent.parentNode) 6955 ); 6956 } 6957 6958 if (!supportCssPointerEvents) { 6959 _css(ghostEl, "display", ""); 6960 } 6961 } 6962 }, 6963 6964 _onTouchMove: function (/**TouchEvent*/ evt) { 6965 if (tapEvt) { 6966 var options = this.options, 6967 fallbackTolerance = options.fallbackTolerance, 6968 fallbackOffset = options.fallbackOffset, 6969 touch = evt.touches ? evt.touches[0] : evt, 6970 dx = touch.clientX - tapEvt.clientX + fallbackOffset.x, 6971 dy = touch.clientY - tapEvt.clientY + fallbackOffset.
6971y, 6972 translate3d = evt.touches 6973 ? "translate3d(" + dx + "px," + dy + "px,0)" 6974 : "translate(" + dx + "px," + dy + "px)"; 6975 6976 // only set the status to dragging, when we are actually dragging 6977 if (!Sortable.active) { 6978 if ( 6979 fallbackTolerance && 6980 min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < 6981 fallbackTolerance 6982 ) { 6983 return; 6984 } 6985 6986 this._dragStarted(); 6987 } 6988 6989 // as well as creating the ghost element on the document body 6990 this._appendGhost(); 6991 6992 moved = true; 6993 touchEvt = touch; 6994 6995 _css(ghostEl, "webkitTransform", translate3d); 6996 _css(ghostEl, "mozTransform", translate3d); 6997 _css(ghostEl, "msTransform", translate3d); 6998 _css(ghostEl, "transform", translate3d); 6999 7000 evt.preventDefault(); 7001 } 7002 }, 7003 7004 _appendGhost: function () { 7005 if (!ghostEl) { 7006 var rect = dragEl.getBoundingClientRect(), 7007 css = _css(dragEl), 7008 options = this.options, 7009 ghostRect; 7010 7011 ghostEl = dragEl.cloneNode(true); 7012 7013 _toggleClass(ghostEl, options.ghostClass, false); 7014 _toggleClass(ghostEl, options.fallbackClass, true); 7015 _toggleClass(ghostEl, options.dragClass, true); 7016 7017 _css(ghostEl, "top", rect.top - parseInt(css.marginTop, 10)); 7018 _css(ghostEl, "left", rect.left - parseInt(css.marginLeft, 10)); 7019 _css(ghostEl, "width", rect.width); 7020 _css(ghostEl, "height", rect.height); 7021 _css(ghostEl, "opacity", "0.8"); 7022 _css(ghostEl, "position", "fixed"); 7023 _css(ghostEl, "zIndex", "100000"); 7024 _css(ghostEl, "pointerEvents", "none"); 7025 7026 (options.fallbackOnBody && document.body.appendChild(ghostEl)) || 7027 rootEl.appendChild(ghostEl); 7028 7029 // Fixing dimensions. 7030 ghostRect = ghostEl.getBoundingClientRect(); 7031 _css(ghostEl, "width", rect.width * 2 - ghostRect.width); 7032 _css(ghostEl, "height", rect.height * 2 - ghostRect.height); 7033 } 7034 }, 7035 7036 _onDragStart: function (/**Event*/ evt, /**boolean*/ useFallback) { 7037 var dataTransfer = evt.dataTransfer, 7038 options = this.options; 7039 7040 this._offUpEvents(); 7041 7042 if (activeGroup.checkPull(this, this, dragEl, evt) == "clone") { 7043 cloneEl = _clone(dragEl); 7044 _css(cloneEl, "display", "none"); 7045 rootEl.insertBefore(cloneEl, dragEl); 7046 _dispatchEvent(this, rootEl, "clone", dragEl); 7047 } 7048 7049 _toggleClass(dragEl, options.dragClass, true); 7050 7051 if (useFallback) { 7052 if (useFallback === "touch") { 7053 // Bind touch events 7054 _on(document, "touchmove", this._onTouchMove); 7055 _on(document, "touchend", this._onDrop); 7056 _on(document, "touchcancel", this._onDrop); 7057 } else { 7058 // Old brwoser 7059 _on(document, "mousemove", this._onTouchMove); 7060 _on(document, "mouseup", this._onDrop); 7061 } 7062 7063 this._loopId = setInterval(this._emulateDragOver, 50); 7064 } else { 7065 if (dataTransfer) { 7066 dataTransfer.effectAllowed = "move"; 7067 options.setData && options.setData.call(this, dataTransfer, dragEl); 7068 } 7069 7070 _on(document, "drop", this); 7071 setTimeout(this._dragStarted, 0); 7072 } 7073 }, 7074 7075 _onDragOver: function (/**Event*/ evt) { 7076 var el = this.el, 7077 target, 7078 dragRect, 7079 targetRect, 7080 revert, 7081 options = this.options, 7082 group = options.group, 7083 activeSortable = Sortable.active, 7084 isOwner = activeGroup === group, 7085 canSort = options.sort; 7086 7087 if (evt.preventDefault !== void 0) { 7088 evt.preventDefault(); 7089 !options.dragoverBubble && evt.stopPropagation(); 7090 } 7091 7092 moved = true; 7093 7094 if ( 7095 activeGroup && 7096 !options.disabled && 7097 (isOwner 7098 ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list 7099 : putSortable === this || 7100 (activeGroup.checkPull(this, activeSortable, dragEl, evt) && 7101 group.checkPut(this, activeSortable, dragEl, evt))) && 7102 (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback 7103 ) { 7104 // Smart auto-scrolling 7105 _autoScroll(evt, options, this.el); 7106 7107 if (_silent) { 7108 return; 7109 } 7110 7111 target = _closest(evt.target, options.draggable, el); 7112 dragRect = dragEl.getBoundingClientRect(); 7113 putSortable = this; 7114 7115 if (revert) { 7116 _cloneHide(true); 7117 parentEl = rootEl; // actualization 7118 7119 if (cloneEl || nextEl) { 7120 rootEl.insertBefore(dragEl, cloneEl || nextEl); 7121 } else if (!canSort) { 7122 rootEl.appendChild(dragEl); 7123 } 7124 7125 return; 7126 } 7127 7128 if ( 7129 el.children.length === 0 || 7130 el.children[0] === ghostEl || 7131 (el === evt.target && (target = _ghostIsLast(el, evt))) 7132 ) { 7133 if (target) { 7134 if (target.animated) { 7135 return; 7136 } 7137 7138 targetRect = target.getBoundingClientRect(); 7139 } 7140 7141 _cloneHide(isOwner); 7142 7143 if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { 7144 if (!dragEl.contains(el)) { 7145 el.appendChild(dragEl); 7146 parentEl = el; // actualization 7147 } 7148 7149 this._animate(dragRect, dragEl); 7150 target && this._animate(targetRect, target); 7151 } 7152 } else if ( 7153 target && 7154 !target.animated && 7155 target !== dragEl && 7156 target.parentNode[expando] !== void 0 7157 ) { 7158 if (lastEl !== target) { 7159 lastEl = target; 7160 lastCSS = _css(target); 7161 lastParentCSS = _css(target.parentNode); 7162 } 7163 7164 targetRect = target.getBoundingClientRect(); 7165 7166 var width = targetRect.right - targetRect.left, 7167 height = targetRect.bottom - targetRect.top, 7168 floating = 7169 /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display) || 7170 (lastParentCSS.display == "flex" && 7171 lastParentCSS["flex-direction"].indexOf("row") === 0), 7172 isWide = target.offsetWidth > dragEl.offsetWidth, 7173 isLong = target.offsetHeight > dragEl.offsetHeight, 7174 halfway = 7175 (floating 7176 ? (evt.clientX - targetRect.left) / width 7177 : (evt.clientY - targetRect.top) / height) > 0.5, 7178 nextSibling = target.nextElementSibling, 7179 moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt), 7180 after; 7181 7182 if (moveVector !== false) { 7183 _silent = true; 7184 setTimeout(_unsilent, 30); 7185 7186 _cloneHide(isOwner); 7187 7188 if (moveVector === 1 || moveVector === -1) { 7189 after = moveVector === 1; 7190 } else if (floating) { 7191 var elTop = dragEl.offsetTop, 7192 tgTop = target.offsetTop; 7193 7194 if (elTop === tgTop) { 7195 after = 7196 (target.previousElementSibling === dragEl && !isWide) || 7197 (halfway && isWide); 7198 } else if ( 7199 target.previousElementSibling === dragEl || 7200 dragEl.previousElementSibling === target 7201 ) { 7202 after = (evt.clientY - targetRect.top) / height > 0.5; 7203 } else { 7204 after = tgTop > elTop; 7205 } 7206 } else { 7207 after = (nextSibling !== dragEl && !isLong) || (halfway && isLong); 7208 } 7209 7210 if (!dragEl.contains(el)) { 7211 if (after && !nextSibling) { 7212 el.appendChild(dragEl); 7213 } else { 7214 target.parentNode.insertBefore( 7215 dragEl, 7216 after ? nextSibling : target 7217 ); 7218 } 7219 } 7220 7221 parentEl = dragEl.parentNode; // actualization 7222 7223 this._animate(dragRect, dragEl); 7224 this._animate(targetRect, target); 7225 } 7226 } 7227 } 7228 }, 7229 7230 _animate: function (prevRect, target) { 7231 var ms = this.options.animation; 7232 7233 if (ms) { 7234 var currentRect = target.getBoundingClientRect(); 7235 7236 _css(target, "transition", "none"); 7237 _css( 7238 target, 7239 "transform", 7240 "translate3d(" + 7241 (prevRect.left - currentRect.left) + 7242 "px," + 7243 (prevRect.top - currentRect.top) + 7244 "px,0)" 7245 ); 7246 7247 target.offsetWidth; // repaint 7248 7249 _css(target, "transition", "all " + ms + "ms");
7250 _css(target, "transform", "translate3d(0,0,0)"); 7251 7252 clearTimeout(target.animated); 7253 target.animated = setTimeout(function () { 7254 _css(target, "transition", ""); 7255 _css(target, "transform", ""); 7256 target.animated = false; 7257 }, ms); 7258 } 7259 }, 7260 7261 _offUpEvents: function () { 7262 var ownerDocument = this.el.ownerDocument; 7263 7264 _off(document, "touchmove", this._onTouchMove); 7265 _off(ownerDocument, "mouseup", this._onDrop); 7266 _off(ownerDocument, "touchend", this._onDrop); 7267 _off(ownerDocument, "touchcancel", this._onDrop); 7268 }, 7269 7270 _onDrop: function (/**Event*/ evt) { 7271 var el = this.el, 7272 options = this.options; 7273 7274 clearInterval(this._loopId); 7275 clearInterval(autoScroll.pid); 7276 clearTimeout(this._dragStartTimer); 7277 7278 // Unbind events 7279 _off(document, "mousemove", this._onTouchMove); 7280 7281 if (this.nativeDraggable) { 7282 _off(document, "drop", this); 7283 _off(el, "dragstart", this._onDragStart); 7284 } 7285 7286 this._offUpEvents(); 7287 7288 if (evt) { 7289 if (moved) { 7290 evt.preventDefault(); 7291 !options.dropBubble && evt.stopPropagation(); 7292 } 7293 7294 ghostEl && ghostEl.parentNode.removeChild(ghostEl); 7295 7296 if (dragEl) { 7297 if (this.nativeDraggable) { 7298 _off(dragEl, "dragend", this); 7299 } 7300 7301 _disableDraggable(dragEl); 7302 dragEl.style["will-change"] = ""; 7303 7304 // Remove class's 7305 _toggleClass(dragEl, this.options.ghostClass, false); 7306 _toggleClass(dragEl, this.options.chosenClass, false); 7307 7308 if (rootEl !== parentEl) { 7309 newIndex = _index(dragEl, options.draggable); 7310 7311 if (newIndex >= 0) { 7312 // Add event 7313 _dispatchEvent( 7314 null, 7315 parentEl, 7316 "add", 7317 dragEl, 7318 rootEl, 7319 oldIndex, 7320 newIndex 7321 ); 7322 7323 // Remove event 7324 _dispatchEvent( 7325 this, 7326 rootEl, 7327 "remove", 7328 dragEl, 7329 rootEl, 7330 oldIndex, 7331 newIndex 7332 ); 7333 7334 // drag from one list and drop into another 7335 _dispatchEvent( 7336 null, 7337 parentEl, 7338 "sort", 7339 dragEl, 7340 rootEl, 7341 oldIndex, 7342 newIndex 7343 ); 7344 _dispatchEvent( 7345 this, 7346 rootEl, 7347 "sort", 7348 dragEl, 7349 rootEl, 7350 oldIndex, 7351 newIndex 7352 ); 7353 } 7354 } else { 7355 // Remove clone 7356 cloneEl && cloneEl.parentNode.removeChild(cloneEl); 7357 7358 if (dragEl.nextSibling !== nextEl) { 7359 // Get the index of the dragged element within its parent 7360 newIndex = _index(dragEl, options.draggable); 7361 7362 if (newIndex >= 0) { 7363 // drag & drop within the same list 7364 _dispatchEvent( 7365 this, 7366 rootEl, 7367 "update", 7368 dragEl, 7369 rootEl, 7370 oldIndex, 7371 newIndex 7372 ); 7373 _dispatchEvent( 7374 this, 7375 rootEl, 7376 "sort", 7377 dragEl, 7378 rootEl, 7379 oldIndex, 7380 newIndex 7381 ); 7382 } 7383 } 7384 } 7385 7386 if (Sortable.active) { 7387 /* jshint eqnull:true */ 7388 if (newIndex == null || newIndex === -1) { 7389 newIndex = oldIndex; 7390 } 7391 7392 _dispatchEvent(this, rootEl, "end", dragEl, rootEl, oldIndex, newIndex); 7393 7394 // Save sorting 7395 this.save(); 7396 } 7397 } 7398 } 7399
7400 this._nulling(); 7401 }, 7402 7403 _nulling: function () { 7404 rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = scrollEl = scrollParentEl = tapEvt = touchEvt = moved = newIndex = lastEl = lastCSS = putSortable = activeGroup = Sortable.active = null; 7405 }, 7406 7407 handleEvent: function (/**Event*/ evt) { 7408 var type = evt.type; 7409 7410 if (type === "dragover" || type === "dragenter") { 7411 if (dragEl) { 7412 this._onDragOver(evt); 7413 _globalDragOver(evt); 7414 } 7415 } else if (type === "drop" || type === "dragend") { 7416 this._onDrop(evt); 7417 } 7418 }, 7419 7420 /** 7421 * Serializes the item into an array of string. 7422 * @returns {String[]} 7423 */ 7424 toArray: function () { 7425 var order = [], 7426 el, 7427 children = this.el.children, 7428 i = 0, 7429 n = children.length, 7430 options = this.options; 7431 7432 for (; i < n; i++) { 7433 el = children[i]; 7434 if (_closest(el, options.draggable, this.el)) { 7435 order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); 7436 } 7437 } 7438 7439 return order; 7440 }, 7441 7442 /** 7443 * Sorts the elements according to the array. 7444 * @param {String[]} order order of the items 7445 */ 7446 sort: function (order) { 7447 var items = {}, 7448 rootEl = this.el; 7449 7450 this.toArray().forEach(function (id, i) { 7451 var el = rootEl.children[i]; 7452 7453 if (_closest(el, this.options.draggable, rootEl)) { 7454 items[id] = el; 7455 } 7456 }, this); 7457 7458 order.forEach(function (id) { 7459 if (items[id]) { 7460 rootEl.removeChild(items[id]); 7461 rootEl.appendChild(items[id]); 7462 } 7463 }); 7464 }, 7465 7466 /** 7467 * Save the current sorting 7468 */ 7469 save: function () { 7470 var store = this.options.store; 7471 store && store.set(this); 7472 }, 7473 7474 /** 7475 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. 7476 * @param {HTMLElement} el 7477 * @param {String} [selector] default: `options.draggable` 7478 * @returns {HTMLElement|null} 7479 */ 7480 closest: function (el, selector) { 7481 return _closest(el, selector || this.options.draggable, this.el); 7482 }, 7483 7484 /** 7485 * Set/get option 7486 * @param {string} name 7487 * @param {*} [value] 7488 * @returns {*} 7489 */ 7490 option: function (name, value) { 7491 var options = this.options; 7492 7493 if (value === void 0) { 7494 return options[name]; 7495 } else { 7496 options[name] = value; 7497 7498 if (name === "group") { 7499 _prepareGroup(options); 7500 } 7501 } 7502 }, 7503 7504 /** 7505 * Destroy 7506 */ 7507 destroy: function () { 7508 var el = this.el; 7509 7510 el[expando] = null; 7511 7512 _off(el, "mousedown", this._onTapStart); 7513 _off(el, "touchstart", this._onTapStart); 7514 7515 if (this.nativeDraggable) { 7516 _off(el, "dragover", this); 7517 _off(el, "dragenter", this); 7518 } 7519 7520 // Remove draggable attributes 7521 Array.prototype.forEach.call(el.querySelectorAll("[draggable]"), function (el) { 7522 el.removeAttribute("draggable"); 7523 }); 7524 7525 touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); 7526 7527 this._onDrop(); 7528 7529 this.el = el = null; 7530 }, 7531 }; 7532 7533 function _cloneHide(state) { 7534 if (cloneEl && cloneEl.state !== state) { 7535 _css(cloneEl, "display", state ? "none" : ""); 7536 !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl); 7537 cloneEl.state = state; 7538 } 7539 } 7540 7541 function _closest(/**HTMLElement*/ el, /**String*/ selector, /**HTMLElement*/ ctx) { 7542 if (el) { 7543 ctx = ctx || document; 7544 7545 do { 7546 if ((selector === ">*" && el.parentNode === ctx) || _matches(el, selector)) { 7547 return el; 7548 } 7549 /* jshint boss:true */ 7550 } while ((el = _getParentOrHost(el))); 7551 } 7552 7553 return null; 7554 } 7555 7556 function _getParentOrHost(el) { 7557 var parent = el.host; 7558 7559 return parent && parent.nodeType ? parent : el.parentNode; 7560 } 7561 7562 function _globalDragOver(/**Event*/ evt) { 7563 if (evt.dataTransfer) { 7564 evt.dataTransfer.dropEffect = "move"; 7565 } 7566 evt.preventDefault(); 7567 } 7568 7569 function _on(el, event, fn) { 7570 el.addEventListener(event, fn, false); 7571 } 7572 7573 function _off(el, event, fn) { 7574 el.removeEventListener(event, fn, false); 7575 } 7576 7577 function _toggleClass(el, name, state) { 7578 if (el) { 7579 if (el.classList) { 7580 el.classList[state ? "add" : "remove"](name); 7581 } else { 7582 var className = (" " + el.className + " ") 7583 .replace(RSPACE, " ") 7584 .replace(" " + name + " ", " "); 7585 el.className = (className + (state ? " " + name : "")).replace(RSPACE, " "); 7586 } 7587 } 7588 } 7589 7590 function _css(el, prop, val) { 7591 var style = el && el.style; 7592 7593 if (style) { 7594 if (val === void 0) { 7595 if (document.defaultView && document.defaultView.getComputedStyle) { 7596 val = document.defaultView.getComputedStyle(el, ""); 7597 } else if (el.currentStyle) { 7598 val = el.currentStyle; 7599 } 7600 7601 return prop === void 0 ? val : val[prop]; 7602 } else { 7603 if (!(prop in style)) { 7604 prop = "-webkit-" + prop; 7605 } 7606 7607 style[prop] = val + (typeof val === "string" ? "" : "px"); 7608 } 7609 } 7610 } 7611 7612 function _find(ctx, tagName, iterator) { 7613 if (ctx) { 7614 var list = ctx.getElementsByTagName(tagName), 7615 i = 0, 7616 n = list.length; 7617 7618 if (iterator) { 7619 for (; i < n; i++) { 7620 iterator(list[i], i); 7621 } 7622 } 7623 7624 return list; 7625 } 7626 7627 return []; 7628 } 7629 7630 function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) { 7631 sortable = sortable || rootEl[expando]; 7632 7633 var evt = document.createEvent("Event"),
7634 options = sortable.options, 7635 onName = "on" + name.charAt(0).toUpperCase() + name.substr(1); 7636 7637 evt.initEvent(name, true, true); 7638 7639 evt.to = rootEl; 7640 evt.from = fromEl || rootEl; 7641 evt.item = targetEl || rootEl; 7642 evt.clone = cloneEl; 7643 7644 evt.oldIndex = startIndex; 7645 evt.newIndex = newIndex; 7646 7647 rootEl.dispatchEvent(evt); 7648 7649 if (options[onName]) { 7650 options[onName].call(sortable, evt); 7651 } 7652 } 7653 7654 function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt) { 7655 var evt, 7656 sortable = fromEl[expando], 7657 onMoveFn = sortable.options.onMove, 7658 retVal; 7659 7660 evt = document.createEvent("Event"); 7661 evt.initEvent("move", true, true); 7662 7663 evt.to = toEl; 7664 evt.from = fromEl; 7665 evt.dragged = dragEl; 7666 evt.draggedRect = dragRect; 7667 evt.related = targetEl || toEl; 7668 evt.relatedRect = targetRect || toEl.getBoundingClientRect(); 7669 7670 fromEl.dispatchEvent(evt); 7671 7672 if (onMoveFn) { 7673 retVal = onMoveFn.call(sortable, evt, originalEvt); 7674 } 7675 7676 return retVal; 7677 } 7678 7679 function _disableDraggable(el) { 7680 el.draggable = false; 7681 } 7682 7683 function _unsilent() { 7684 _silent = false; 7685 } 7686 7687 /** @returns {HTMLElement|false} */ 7688 function _ghostIsLast(el, evt) { 7689 var lastEl = el.lastElementChild, 7690 rect = lastEl.getBoundingClientRect(); 7691 7692 // 5 â min delta 7693 // abs â нелÑÐ·Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑÑ, а Ñо глÑки пÑи наведении ÑвеÑÑ Ñ 7694 return ( 7695 (evt.clientY - (rect.top + rect.height) > 5 || 7696 evt.clientX - (rect.right + rect.width) > 5) && 7697 lastEl 7698 ); 7699 } 7700 7701 /** 7702 * Generate id 7703 * @param {HTMLElement} el 7704 * @returns {String} 7705 * @private 7706 */ 7707 function _generateId(el) { 7708 var str = el.tagName + el.className + el.src + el.href + el.textContent, 7709 i = str.length, 7710 sum = 0; 7711 7712 while (i--) { 7713 sum += str.charCodeAt(i); 7714 } 7715 7716 return sum.toString(36); 7717 } 7718 7719 /** 7720 * Returns the index of an element within its parent for a selected set of 7721 * elements 7722 * @param {HTMLElement} el 7723 * @param {selector} selector 7724 * @return {number} 7725 */ 7726 function _index(el, selector) { 7727 var index = 0; 7728 7729 if (!el || !el.parentNode) { 7730 return -1; 7731 } 7732 7733 while (el && (el = el.previousElementSibling)) { 7734 if ( 7735 el.nodeName.toUpperCase() !== "TEMPLATE" && 7736 (selector === ">*" || _matches(el, selector)) 7737 ) { 7738 index++; 7739 } 7740 } 7741 7742 return index; 7743 } 7744 7745 function _matches(/**HTMLElement*/ el, /**String*/ selector) { 7746 if (el) { 7747 selector = selector.split("."); 7748 7749 var tag = selector.shift().toUpperCase(), 7750 re = new RegExp("\\s(" + selector.join("|") + ")(?=\\s)", "g"); 7751 7752 return ( 7753 (tag === "" || el.nodeName.toUpperCase() == tag) && 7754 (!selector.length || 7755 ((" " + el.className + " ").match(re) || []).length == selector.length) 7756 ); 7757 } 7758 7759 return false; 7760 } 7761 7762 function _throttle(callback, ms) { 7763 var args, _this; 7764 7765 return function () { 7766 if (args === void 0) { 7767 args = arguments; 7768 _this = this; 7769 7770 setTimeout(function () { 7771 if (args.length === 1) { 7772 callback.call(_this, args[0]); 7773 } else { 7774 callback.apply(_this, args); 7775 } 7776 7777 args = void 0; 7778 }, ms); 7779 } 7780 }; 7781 } 7782 7783 function _extend(dst, src) { 7784 if (dst && src) { 7785 for (var key in src) { 7786 if (src.hasOwnProperty(key)) { 7787 dst[key] = src[key]; 7788 } 7789 } 7790 } 7791 7792 return dst; 7793 } 7794 7795 function _clone(el) { 7796 return $ 7797 ? $(el).clone(true)[0] 7798 : Polymer && Polymer.dom 7799 ? Polymer.dom(el).cloneNode(true) 7800 : el.cloneNode(true); 7801 } 7802 7803 // Export utils 7804 Sortable.utils = { 7805 on: _on, 7806 off: _off, 7807 css: _css, 7808 find: _find, 7809 is: function (el, selector) { 7810 return !!_closest(el, selector, el); 7811 }, 7812 extend: _extend, 7813 throttle: _throttle, 7814 closest: _closest, 7815 toggleClass: _toggleClass, 7816 clone: _clone, 7817 index: _index, 7818 }; 7819 7820 /** 7821 * Create sortable instance 7822 * @param {HTMLElement} el 7823 * @param {Object} [options] 7824 */ 7825 Sortable.create = function (el, options) { 7826 return new Sortable(el, options); 7827 }; 7828 7829 // Export
7830 Sortable.version = "1.4.2"; 7831 return Sortable; 7832 }); 7833 }); 7834 7835 const $$h = jQuery; 7836 class ImagesFormElement extends FormElement { 7837 constructor(options, formBuilder, external) { 7838 super(options, formBuilder, external); 7839 this.searchType = options.searchType || "fulltext"; 7840 this.mediaUploader = external.mediaUploader; 7841 this.button_text = options.button_text || "Browse..."; 7842 this.db_type = "text"; 7843 this.label = options.label || "Images"; 7844 this.name = options.name || "images"; 7845 this.images = this.value || []; 7846 this.value = JSON.stringify(this.value); 7847 } 7848 init() { 7849 super.init(); 7850 this.redrawImages(); 7851 } 7852 setDomElements() { 7853 super.setDomElements(); 7854 } 7855 getData() { 7856 this.updateData(); 7857 return { name: this.name, value: this.images }; 7858 } 7859 getSchema() { 7860 const schema = super.getSchema(); 7861 schema.button_text = this.button_text; 7862 return schema; 7863 } 7864 updateData() { 7865 const newListOfImages = []; 7866 $$h(this.domElements.main) 7867 .find(".mapsvg-thumbnail-wrap") 7868 .each(function (index, el) { 7869 const imageData = $$h(el).data("image"); 7870 newListOfImages.push(imageData); 7871 }); 7872 this.images = newListOfImages; 7873 this.value = JSON.stringify(this.images); 7874 $$h(this.domElements.main).find("input").val(this.value); 7875 } 7876 setEventHandlers() { 7877 super.setEventHandlers(); 7878 if (this.formBuilder.editMode) { 7879 return; 7880 } 7881 const _this = this; 7882 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 7883 this.external.mediaUploader.on("select", () => { 7884 const attachments = _this.external.mediaUploader.state().get("selection").toJSON(); 7885 attachments.forEach(function (img) { 7886 const image = { sizes: {} }; 7887 for (const type in img.sizes) { 7888 image[type] = img.sizes[type].url 7889 .replace("http://", "//") 7890 .replace("https://", "//"); 7891 image.sizes[type] = { 7892 width: img.sizes[type].width, 7893 height: img.sizes[type].height, 7894 }; 7895 } 7896 if (!image.thumbnail) { 7897 image.thumbnail = image.full; 7898 image.sizes.thumbnail = { 7899 width: img.sizes.full.width, 7900 height: img.sizes.full.height, 7901 }; 7902 } 7903 if (!image.medium) { 7904 image.medium = image.full; 7905 image.sizes.medium = { 7906 width: img.sizes.full.width, 7907 height: img.sizes.full.height, 7908 }; 7909 } 7910 image.caption = img.caption; 7911 image.description = img.description; 7912 _this.images.push(image); 7913 }); 7914 this.setValue(this.images); 7915 _this.redrawImages(); 7916 }); 7917 $$h(_this.domElements.main).on("click", ".mapsvg-upload-image", function (e) { 7918 e.preventDefault(); 7919 _this.external.mediaUploader.open(); 7920 }); 7921 $$h(_this.domElements.main).on("click", ".mapsvg-image-delete", function (e) { 7922 e.preventDefault(); 7923 $$h(this).closest(".mapsvg-thumbnail-wrap").remove(); 7924 _this.updateData(); 7925 }); 7926 _this.sortable = new sortable_min(imageDOM[0], { 7927 animation: 150, 7928 onStart: function () { 7929 $$h(_this.domElements.main).addClass("sorting"); 7930 }, 7931 onEnd: function (evt) { 7932 _this.images = []; 7933 $$h(_this.domElements.main) 7934 .find("img") 7935 .each(function (i, image) { 7936 _this.images.push($$h(image).data("image")); 7937 }); 7938 this.value = JSON.stringify(_this.images); 7939 $$h(_this.domElements.main).find("input").val(this.value); 7940 $$h(_this.domElements.main).removeClass("sorting"); 7941 }, 7942 }); 7943 } 7944 redrawImages() { 7945 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 7946 imageDOM.empty(); 7947 this.images &&
7948 this.images.forEach(function (image) { 7949 const img = $$h('<img class="mapsvg-data-thumbnail" />') 7950 .attr("src", image.thumbnail) 7951 .data("image", image); 7952 const imgContainer = $$h('<div class="mapsvg-thumbnail-wrap"></div>').data("image", image); 7953 imgContainer.append(img); 7954 imgContainer.append('<i class="fa fa-times mapsvg-image-delete"></i>'); 7955 imageDOM.append(imgContainer); 7956 }); 7957 $$h(this.domElements.main).find("input").val(this.value); 7958 } 7959 } 7960 7961 const $$i = jQuery; 7962 class LocationFormElement extends FormElement { 7963 constructor(options, formBuilder, external) { 7964 super(options, formBuilder, external); 7965 this.label = this.label || (options.label === undefined ? "Location" : options.label); 7966 this.name = "location"; 7967 this.db_type = "text"; 7968 this.languages = [ 7969 { value: "sq", label: "Albanian" }, 7970 { value: "ar", label: "Arabic" }, 7971 { 7972 value: "eu", 7973 label: "Basque", 7974 }, 7975 { value: "be", label: "Belarusian" }, 7976 { value: "bg", label: "Bulgarian" }, 7977 { 7978 value: "my", 7979 label: "Burmese", 7980 }, 7981 { value: "bn", label: "Bengali" }, 7982 { value: "ca", label: "Catalan" }, 7983 { 7984 value: "zh-cn", 7985 label: "Chinese (simplified)", 7986 }, 7987 { value: "zh-tw", label: "Chinese (traditional)" }, 7988 { 7989 value: "hr", 7990 label: "Croatian", 7991 }, 7992 { value: "cs", label: "Czech" }, 7993 { value: "da", label: "Danish" }, 7994 { 7995 value: "nl", 7996 label: "Dutch", 7997 }, 7998 { value: "en", label: "English" }, 7999 { 8000 value: "en-au", 8001 label: "English (australian)", 8002 }, 8003 { value: "en-gb", label: "English (great Britain)" }, 8004 { 8005 value: "fa", 8006 label: "Farsi", 8007 }, 8008 { value: "fi", label: "Finnish" }, 8009 { value: "fil", label: "Filipino" }, 8010 { 8011 value: "fr", 8012 label: "French", 8013 }, 8014 { value: "gl", label: "Galician" }, 8015 { value: "de", label: "German" }, 8016 { 8017 value: "el", 8018 label: "Greek", 8019 }, 8020 { value: "gu", label: "Gujarati" }, 8021 { value: "iw", label: "Hebrew" }, 8022 { 8023 value: "hi", 8024 label: "Hindi", 8025 }, 8026 { value: "hu", label: "Hungarian" }, 8027 { value: "id", label: "Indonesian" }, 8028 { 8029 value: "it", 8030 label: "Italian", 8031 }, 8032 { value: "ja", label: "Japanese" }, 8033 { value: "kn", label: "Kannada" }, 8034 { 8035 value: "kk", 8036 label: "Kazakh", 8037 }, 8038 { value: "ko", label: "Korean" }, 8039 { value: "ky", label: "Kyrgyz" }, 8040 { 8041 value: "lt", 8042 label: "Lithuanian", 8043 }, 8044 { value: "lv", label: "Latvian" }, 8045 { value: "mk", label: "Macedonian" }, 8046 { 8047 value: "ml", 8048 label: "Malayalam", 8049 }, 8050 { value: "mr", label: "Marathi" }, 8051 { value: "no", label: "Norwegian" }, 8052 { 8053 value: "pl", 8054 label: "Polish", 8055 }, 8056 { value: "pt", label: "Portuguese" }, 8057 { 8058 value: "pt-br", 8059 label: "Portuguese (brazil)", 8060 }, 8061 { value: "pt-pt", label: "Portuguese (portugal)" }, 8062 { 8063 value: "pa", 8064 label: "Punjabi", 8065 }, 8066 { value: "ro", label: "Romanian" }, 8067 { value: "ru", label: "Russian" }, 8068 { 8069 value: "sr", 8070 label: "Serbian", 8071 }, 8072 { value: "sk", label: "Slovak" }, 8073 { value: "sl", label: "Slovenian" }, 8074 { 8075 value: "es", 8076 label: "Spanish", 8077 }, 8078 { value: "sv", label: "Swedish" }, 8079 { value: "tl", label: "Tagalog" }, 8080 { 8081 value: "ta", 8082 label: "Tamil", 8083 }, 8084 { value: "te", label: "Telugu" }, 8085 { value: "th", label: "Thai" }, 8086 { 8087 value: "tr", 8088 label: "Turkish", 8089 }, 8090 { value: "uk", label: "Ukrainian" }, 8091 { value: "uz", label: "Uzbek" }, 8092 { 8093 value: "vi", 8094 label: "Vietnamese", 8095 }, 8096 ]; 8097 this.language = options.language; 8098 this.markerImages = MapSVG.markerImages; 8099 this.markersByField = options.markersByField; 8100 this.markerField = options.markerField; 8101 this.markersByFieldEnabled = MapSVG.parseBoolean(options.markersByFieldEnabled); 8102 this.templates.marker = Handlebars.compile($$i("#mapsvg-data-tmpl-marker").html()); 8103 } 8104 init() { 8105 super.init(); 8106 if (this.value) { 8107 this.renderMarker(); 8108 } 8109 this.renderMarkerSelector(); 8110 } 8111 getSchema() { 8112 const schema = super.getSchema(); 8113 schema.language = this.language; 8114 schema.markersByField = this.markersByField; 8115 schema.markerField = this.markerField; 8116 schema.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8117 return schema; 8118 } 8119 getData() { 8120 return { name: this.name, value: this.value }; 8121 } 8122 getDataForTemplate() { 8123 const data = super.getDataForTemplate(); 8124 if (this.formBuilder.admin) { 8125 data.languages = this.languages; 8126 data.markerImages = MapSVG.markerImages; 8127 data.markersByField = this.markersByField; 8128 data.markerField = this.markerField; 8129 data.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8130 const _this = this;
8131 data.markerImages.forEach(function (m) { 8132 if (m.path === _this.formBuilder.mapsvg.getData().options.defaultMarkerImage) { 8133 m.default = true; 8134 } 8135 else { 8136 m.default = false; 8137 } 8138 }); 8139 } 8140 data.language = this.language; 8141 if (this.value) { 8142 data.location = this.value; 8143 if (data.location.marker) { 8144 data.location.img = 8145 (this.value.marker.src.indexOf(MapSVG.urls.uploads) === 0 ? "uploads/" : "") + 8146 this.value.marker.src.split("/").pop(); 8147 } 8148 } 8149 data.showUploadBtn = data.external.filtersMode; 8150 return data; 8151 } 8152 initEditor() { 8153 super.initEditor(); 8154 this.renderMarkerSelector(); 8155 this.fillMarkersByFieldOptions(this.markerField); 8156 } 8157 setDomElements() { 8158 super.setDomElements(); 8159 this.domElements.markerImageButton = $$i(this.domElements.main).find("img")[0]; 8160 } 8161 setEventHandlers() { 8162 super.setEventHandlers(); 8163 const _this = this; 8164 const server = new Server(); 8165 if (_this.formBuilder.mapsvg.isGeo()) { 8166 const locations = new Bloodhound({ 8167 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 8168 queryTokenizer: Bloodhound.tokenizers.whitespace, 8169 remote: { 8170 url: server.getUrl("geocoding") + "?address=%QUERY%&language=" + this.language, 8171 wildcard: "%QUERY%", 8172 transform: function (response) { 8173 if (response.error_message) { 8174 alert(response.error_message); 8175 } 8176 return response.results; 8177 }, 8178 rateLimitWait: 600, 8179 }, 8180 }); 8181 const thContainer = $$i(this.domElements.main).find(".typeahead"); 8182 const tH = thContainer 8183 .typeahead({ 8184 minLength: 3, 8185 }, { 8186 name: "mapsvg-addresses", 8187 display: "formatted_address", 8188 source: locations, 8189 }) 8190 .on("typeahead:asyncrequest", function (e) { 8191 $$i(e.target).addClass("tt-loading"); 8192 }) 8193 .on("typeahead:asynccancel typeahead:asyncreceive", function (e) { 8194 $$i(e.target).removeClass("tt-loading"); 8195 }); 8196 thContainer.on("typeahead:select", (ev, item) => { 8197 this.setValue(null, false); 8198 const address = {}; 8199 address.formatted = item.formatted_address; 8200 item.address_components.forEach((addr_item) => { 8201 const type = addr_item.types[0]; 8202 address[type] = addr_item.long_name; 8203 if (addr_item.short_name != addr_item.long_name) { 8204 address[type + "_short"] = addr_item.short_name; 8205 } 8206 }); 8207 const locationData = { 8208 address: address, 8209 geoPoint: new GeoPoint(item.geometry.location.lat, item.geometry.location.lng), 8210 img: this.formBuilder.mapsvg.getMarkerImage(this.formBuilder.getData()), 8211 imagePath: this.formBuilder.mapsvg.getMarkerImage(this.formBuilder.getData()), 8212 }; 8213 this.setValue(locationData, false); 8214 thContainer.typeahead("val", ""); 8215 this.triggerChanged(); 8216 }); 8217 $$i(this.domElements.main).on("change", ".marker-file-uploader", function () { 8218 _this.markerIconUpload(this); 8219 }); 8220 } 8221 $$i(this.domElements.main).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8222 e.preventDefault(); 8223 $$i(this).toggleClass("active"); 8224 _this.toggleMarkerSelector(); 8225 }); 8226 $$i(this.domElements.main).on("click", ".mapsvg-marker-delete", function (e) { 8227 e.preventDefault(); 8228 _this.setValue(null); 8229 _this.triggerChanged(); 8230 }); 8231 } 8232 setEditorEventHandlers() { 8233 super.setEditorEventHandlers(); 8234 const _this = this; 8235 $$i(this.domElements.edit).on("change", ".marker-file-uploader", function () { 8236 _this.markerIconUpload(this); 8237 }); 8238 $$i(this.domElements.edit).on("change", 'select[name="markerField"]', function () { 8239 const fieldName = $$i(this).val(); 8240 _this.fillMarkersByFieldOptions(fieldName); 8241 }); 8242 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-selector button", function (e) { 8243 e.preventDefault(); 8244 const src = $$i(this).find("img").attr("src"); 8245 $$i(this).parent().find("button").removeClass("active"); 8246 $$i(this).addClass("active"); 8247 _this.formBuilder.mapsvg.setDefaultMarkerImage(src); 8248 }); 8249 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8250 $$i(this).toggleClass("active"); 8251 _this.toggleMarkerSelectorInLocationEditor.call(_this, $$i(this), e); 8252 }); 8253 } 8254 markerIconUpload(input) { 8255 const uploadBtn = $$i(input).closest(".btn-file").buttonLoading(true); 8256 for (let i = 0; i < input.files.length; i++) { 8257 const data = new FormData(); 8258 data.append("file", input.files[0]); 8259 const server = new Server(); 8260 server 8261 .ajax("markers", { 8262 type: "POST", 8263 data: data, 8264 processData: false, 8265 contentType: false, 8266 }) 8267 .done((resp) => { 8268 if (resp.error) { 8269 alert(resp.error); 8270 } 8271 else { 8272 const marker = resp.marker; 8273 const newMarker = ` 8274 <button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose active"> 8275 <img src="${marker.path}" /> 8276 </button> 8277 </button> 8278 `; 8279 $$i(this.domElements.markerSelector) 8280 .find(".mapsvg-marker-image-btn.active") 8281 .removeClass("active"); 8282 $$i(newMarker).appendTo(this.domElements.markerSelector); 8283 this.setMarkerImage(marker.path); 8284 MapSVG.markerImages.push(marker); 8285 } 8286 }) 8287 .always(function () { 8288 uploadBtn.buttonLoading(false); 8289 }); 8290 } 8291 } 8292 mayBeAddDistanceRow() { 8293 const _this = this; 8294 if (!this.domElements.editDistanceRow) { 8295 this.domElements.editDistanceRow = $$i($$i("#mapsvg-edit-distance-row").html())[0]; 8296 } 8297 const z = $$i(this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 8298 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 8299 const newRow = $$i(this.templates.editDistanceRow).clone(); 8300 newRow.insertAfter($$i(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 8301 } 8302 const rows = $$i(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 8303 const row1 = rows.eq(rows.length - 2); 8304 const row2 = rows.eq(rows.length - 1); 8305 if (row1.length && 8306 row2.length && 8307 !row1.find("input:eq(0)").val().toString().trim() && 8308 !row2.find("input:eq(0)").val().toString().trim()) { 8309 row2.remove(); 8310 } 8311 } 8312 fillMarkersByFieldOptions(fieldName) { 8313 const _this = this; 8314 const field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 8315 if (field) { 8316 const markerImg = _this.formBuilder.mapsvg.options.defaultMarkerImage; 8317 const rows = []; 8318 field.options.forEach(function (option) { 8319 const img = _this.markersByField && _this.markersByField[option.value] 8320 ? _this.markersByField[option.value] 8321 : markerImg; 8322 rows.push('<tr data-option-id="' + 8323 option.value + 8324 '"><td>' + 8325 option.label + 8326 '</td><td><button class="btn dropdown-toggle btn-outline-secondary mapsvg-marker-image-btn-trigger mapsvg-marker-image-btn"><img src="' + 8327 img + 8328 '" class="new-marker-img" /><span class="caret"></span></button></td></tr>'); 8329 }); 8330 $$i("#markers-by-field").empty().append(rows); 8331 } 8332 } 8333 renderMarker(marker) { 8334 if (marker && marker.location) { 8335 this.value = marker.location.getData(); 8336 } 8337 this.renderMarkerHtml(); 8338 } 8339 renderMarkerHtml() { 8340 if (!this.value) { 8341 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8342 } 8343 else { 8344 $$i(this.domElements.main) 8345 .find(".mapsvg-new-marker") 8346 .show() 8347 .html(this.templates.marker(this.value)); 8348 } 8349 } 8350 toggleMarkerSelector() { 8351 if (this.domElements.markerSelectorWrap && 8352 $$i(this.domElements.markerSelectorWrap).is(":visible")) { 8353 $$i(this.domElements.markerSelectorWrap).hide(); 8354 return; 8355 } 8356 if (this.domElements.markerSelectorWrap && 8357 $$i(this.domElements.markerSelectorWrap).not(":visible")) { 8358 $$i(this.domElements.markerSelector).find(".active").removeClass("active"); 8359 if (this.value && this.value.imagePath) { 8360 $$i(this.domElements.markerSelector) 8361 .find('[src="' + this.value.imagePath + '"]') 8362 .parent() 8363 .addClass("active"); 8364 } 8365 $$i(this.domElements.markerSelectorWrap).show(); 8366 return; 8367 } 8368 } 8369 renderMarkerSelector() { 8370 const _this = this; 8371 const view = this.formBuilder.editMode ? this.domElements.edit : this.domElements.main; 8372 if (!view) 8373 return; 8374 const currentImage = this.value ? this.value.imagePath : null; 8375 const images = MapSVG.markerImages.map(function (image) { 8376 return ('<button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose ' + 8377 (currentImage == image.path ? "active" : "") + 8378 '"><img src="' + 8379 image.path + 8380 '" /></button>'); 8381 }); 8382 this.domElements.markerSelectorWrap = $$i(view).find(".mapsvg-marker-image-selector")[0]; 8383 this.domElements.markerSelector = $$i(this.domElements.markerSelectorWrap).find(".mapsvg-marker-images")[0]; 8384 if (this.domElements.markerSelector) { 8385 $$i(this.domElements.markerSelector).empty(); 8386 } 8387 if (!this.formBuilder.editMode) { 8388 this.domElements.markerSelectorWrap.style.display = "none"; 8389 $$i(this.domElements.markerSelector).on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8390 e.preventDefault(); 8391 const src = $$i(this).find("img").attr("src"); 8392 $$i(_this.domElements.markerSelectorWrap).hide(); 8393 $$i(_this.domElements.markerSelector).find(".active").removeClass("active"); 8394 $$i(this).addClass("active"); 8395 $$i(_this.domElements.main) 8396 .find(".mapsvg-marker-image-btn-trigger") 8397 .toggleClass("active", false); 8398 $$i(_this.domElements.markerImageButton).attr("src", src); 8399 _this.setMarkerImage(src); 8400 }); 8401 } 8402 $$i(this.domElements.markerSelector).html(images.join("")); 8403 } 8404 setMarkerImage(src) { 8405 this.formBuilder.mapsvg.setDefaultMarkerImage(src); 8406 const value = this.value; 8407 if (value) { 8408 value.img = src; 8409 value.imagePath = src; 8410 this.setValue(value); 8411 this.triggerChanged(); 8412 this.renderMarker(); 8413 } 8414 } 8415 toggleMarkerSelectorInLocationEditor(jQueryObj, e) { 8416 e.preventDefault(); 8417 const _this = this; 8418 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").is(":visible")) { 8419 jQueryObj.data("markerSelector").hide(); 8420 return; 8421 } 8422 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").not(":visible")) { 8423 jQueryObj.data("markerSelector").show(); 8424 return; 8425 } 8426 const markerBtn = $$i(this).closest("td").find(".mapsvg-marker-image-btn-trigger"); 8427 const currentImage = markerBtn.attr("src"); 8428 const images = MapSVG.markerImages.map(function (image) { 8429 return ('<button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose ' + 8430 (currentImage == image.path ? "active" : "") + 8431 '"><img src="' + 8432 image.path + 8433 '" /></button>'); 8434 }); 8435 if (!jQueryObj.data("markerSelector")) { 8436 const ms = $$i('<div class="mapsvg-marker-image-selector"></div>'); 8437 jQueryObj.closest("td").append(ms); 8438 jQueryObj.data("markerSelector", ms); 8439 } 8440 else { 8441 jQueryObj.data("markerSelector").empty(); 8442 } 8443 jQueryObj.data("markerSelector").html(images.join("")); 8444 jQueryObj 8445 .data("markerSelector") 8446 .on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8447 e.preventDefault(); 8448 const src = $$i(this).find("img").attr("src"); 8449 jQueryObj.data("markerSelector").hide(); 8450 const td = $$i(this).closest("td"); 8451 const fieldId = $$i(this).closest("tr").data("option-id"); 8452 const btn = td.find(".mapsvg-marker-image-btn-trigger"); 8453 btn.toggleClass("active", false); 8454 btn.find("img").attr("src", src); 8455 _this.setMarkerByField(fieldId, src); 8456 }); 8457 } 8458 setMarkerByField(fieldId, markerImg) { 8459 this.markersByField = this.markersByField || {}; 8460 this.markersByField[fieldId] = markerImg; 8461 } 8462 deleteMarker() { 8463 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8464 $$i(this.domElements.main).find(".mapsvg-marker-id").attr("disabled", "disabled"); 8465 } 8466 destroy() { 8467 if ($$i().mselect2) { 8468 const sel = $$i(this.domElements.main).find(".mapsvg-select2"); 8469 if (sel.length) { 8470 sel.mselect2("destroy"); 8471 } 8472 } 8473 this.domElements.markerSelector && $$i(this.domElements.markerSelector).popover("d
8473ispose"); 8474 } 8475 setValue(value, updateInput = true) { 8476 this.value = value; 8477 this.renderMarker(); 8478 } 8479 } 8480 8481 const $$j = jQuery; 8482 class ModalFormElement extends FormElement { 8483 constructor(options, formBuilder, external) { 8484 super(options, formBuilder, external); 8485 this.showButtonText = options.showButtonText; 8486 } 8487 getSchema() { 8488 const schema = super.getSchema(); 8489 schema.showButtonText = this.showButtonText; 8490 return schema; 8491 } 8492 } 8493 8494 const $$k = jQuery; 8495 class PostFormElement extends FormElement { 8496 constructor(options, formBuilder, external) { 8497 super(options, formBuilder, external); 8498 if (this.formBuilder.admin) 8499 this.post_types = this.formBuilder.admin.getPostTypes(); 8500 this.post_type = options.post_type || this.post_types[0]; 8501 this.add_fields = MapSVG.parseBoolean(options.add_fields); 8502 this.db_type = "int(11)"; 8503 this.name = "post"; 8504 this.post = options.post; 8505 } 8506 setDomElements() { 8507 super.setDomElements(); 8508 this.inputs.postSelect = ($$k(this.domElements.main).find(".mapsvg-find-post")[0]); 8509 } 8510 getSchema() { 8511 const schema = super.getSchema(); 8512 schema.post_type = this.post_type; 8513 schema.add_fields = this.add_fields; 8514 return schema; 8515 } 8516 destroy() { 8517 if ($$k().mselect2) { 8518 const sel = $$k(this.domElements.main).find(".mapsvg-select2"); 8519 if (sel.length) { 8520 sel.mselect2("destroy"); 8521 } 8522 } 8523 } 8524 getDataForTemplate() { 8525 const data = super.getDataForTemplate(); 8526 if (this.formBuilder.admin) 8527 data.post_types = this.formBuilder.admin.getPostTypes(); 8528 data.post_type = this.post_type; 8529 data.post = this.post; 8530 data.add_fields = this.add_fields || 0; 8531 return data; 8532 } 8533 setEventHandlers() { 8534 super.setEventHandlers(); 8535 const server = new Server(); 8536 $$k(this.inputs.postSelect) 8537 .mselect2({ 8538 placeholder: "Search post by title", 8539 allowClear: true, 8540 disabled: this.readonly, 8541 ajax: { 8542 url: server.getUrl("posts"), 8543 dataType: "json", 8544 delay: 250, 8545 data: (params) => { 8546 return { 8547 filters: { post_type: this.post_type }, 8548 search: params.term, 8549 page: params.page, 8550 }; 8551 }, 8552 processResults: (data, params) => { 8553 params.page = params.page || 1; 8554 return { 8555 results: data.posts ? data.posts : [], 8556 pagination: { 8557 more: false, 8558 }, 8559 }; 8560 }, 8561 cache: true, 8562 }, 8563 escapeMarkup: (markup) => { 8564 return markup; 8565 }, 8566 minimumInputLength: 1, 8567 templateResult: this.formatRepo, 8568 templateSelection: this.formatRepoSelection, 8569 }) 8570 .on("select2:select", (e) => { 8571 const post = e.params.data; 8572 this.setValue(post); 8573 this.setInputValue(post); 8574 this.triggerChanged(); 8575 }) 8576 .on("change", (e) => { 8577 if (e.target.value === "") { 8578 $$k(this.domElements.main).find(".mapsvg-post-id").text(""); 8579 $$k(this.domElements.main).find(".mapsvg-post-url").text(""); 8580 this.setValue(null, false); 8581 this.triggerChanged(); 8582 } 8583 }); 8584 } 8585 formatRepo(repo) { 8586 if (repo.loading) { 8587 return repo.text; 8588 } 8589 else { 8590 return "<div class='select2-result-repository clearfix'>" + repo.post_title + "</div>"; 8591 } 8592 } 8593 formatRepoSelection(repo) { 8594 return repo.post_title || repo.text; 8595 } 8596 setValue(post, updateInput = true) { 8597 this.value = post; 8598 if (updateInput) { 8599 this.setInputValue(post); 8600 } 8601 } 8602 setInputValue(post) { 8603 $$k(this.domElements.main).find(".mapsvg-post-id").text(post.id); 8604 $$k(this.domElements.main).find(".mapsvg-post-url").text(post.url).attr("href", post.url); 8605 } 8606 } 8607 8608 const $$l = jQuery; 8609 class RadioFormElement extends FormElement { 8610 constructor(options, formBuilder, external) { 8611 super(options, formBuilder, external); 8612 this.setOptions(options.options); 8613 } 8614 setDomElements() { 8615 super.setDomElements(); 8616 this.inputs.radios = this.formBuilder.getForm().elements[this.name]; 8617 this.$radios = $$l(this.domElements.main).find('input[type="radio"]'); 8618 } 8619 setEventHandlers() { 8620 super.setEventHandlers(); 8621 this.$radios.on("change", (e) => { 8622 this.setValue(e.target.value, false); 8623 this.triggerChanged(); 8624 }); 8625 } 8626 setInputValue(value) { 8627 this.inputs.radios.value = value; 8628 } 8629 } 8630 8631 const $$m = jQuery; 8632 class RegionsFormElement extends FormElement { 8633 constructor(options, formBuilder, external) { 8634 super(options, formBuilder, external); 8635 this.searchable = MapSVG.parseBoolean(options.searchable); 8636 this.options = this.formBuilder.getRegionsList(); 8637 this.label = options.label === undefined ? "Regions" : options.label;
8638 this.name = "regions"; 8639 this.db_type = "text"; 8640 if (typeof this.value === "undefined") { 8641 this.value = []; 8642 } 8643 this.regionsTableName = this.formBuilder.mapsvg.regionsRepository.getSchema().name; 8644 } 8645 setDomElements() { 8646 super.setDomElements(); 8647 this.inputs.select = $$m(this.domElements.main).find("select")[0]; 8648 } 8649 getData() { 8650 return { name: "regions", value: this.value }; 8651 } 8652 getSchema() { 8653 const schema = super.getSchema(); 8654 if (schema.multiselect) 8655 schema.db_type = "text"; 8656 const opts = $$m.extend(true, {}, { options: this.options }); 8657 schema.options = opts.options; 8658 schema.optionsDict = {}; 8659 schema.options.forEach(function (option) { 8660 schema.optionsDict[option.id] = option.title || option.id; 8661 }); 8662 return schema; 8663 } 8664 getDataForTemplate() { 8665 const data = super.getDataForTemplate(); 8666 data.regionsTableName = this.regionsTableName; 8667 data.regionsFromCurrentTable = this.getRegionsForCurrentTable(); 8668 return data; 8669 } 8670 getRegionsForCurrentTable() { 8671 return this.value 8672 ? this.value.filter((region) => region.tableName === this.regionsTableName) 8673 : []; 8674 } 8675 setEventHandlers() { 8676 super.setEventHandlers(); 8677 $$m(this.inputs.select).on("change", (e) => { 8678 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 8679 const selectedValues = selectedOptions.map((option) => option.value); 8680 this.setValue(selectedValues, false); 8681 this.triggerChanged(); 8682 }); 8683 } 8684 destroy() { 8685 if ($$m().mselect2) { 8686 const sel = $$m(this.domElements.main).find(".mapsvg-select2"); 8687 if (sel.length) { 8688 sel.mselect2("destroy"); 8689 } 8690 } 8691 } 8692 setValue(regionIds, updateInput = true) { 8693 const regionsFromOtherTables = this.value.filter((region) => region.tableName !== this.regionsTableName); 8694 const regions = []; 8695 regionIds.forEach((regionId) => { 8696 const region = this.formBuilder.mapsvg.getRegion(regionId); 8697 regions.push({ id: region.id, title: region.title, tableName: this.regionsTableName }); 8698 }); 8699 this.value = regions.concat(regionsFromOtherTables); 8700 if (updateInput) { 8701 this.setInputValue(regionIds); 8702 } 8703 } 8704 } 8705 8706 const $$n = jQuery; 8707 class SaveFormElement extends FormElement { 8708 constructor(options, formBuilder, external) { 8709 super(options, formBuilder, external); 8710 this.readonly = true; 8711 } 8712 setDomElements() { 8713 super.setDomElements(); 8714 this.inputs.btnSave = $$n(this.domElements.main).find(".btn-save")[0]; 8715 this.inputs.btnClose = $$n(this.domElements.main).find(".mapsvg-close")[0]; 8716 } 8717 setEventHandlers() { 8718 super.setEventHandlers(); 8719 $$n(this.inputs.btnSave).on("click", (e) => { 8720 e.preventDefault(); 8721 this.events.trigger("click.btn.save"); 8722 }); 8723 $$n(this.inputs.btnClose).on("click", (e) => { 8724 e.preventDefault(); 8725 this.events.trigger("click.btn.close"); 8726 }); 8727 } 8728 } 8729 8730 const $$o = jQuery; 8731 class SearchFormElement extends FormElement { 8732 constructor(options, formBuilder, external) { 8733 super(options, formBuilder, external); 8734 this.searchType = options.searchType || "fulltext"; 8735 } 8736 setDomElements() { 8737 super.setDomElements(); 8738 this.inputs.text = $$o(this.domElements.main).find("input")[0]; 8739 } 8740 setEventHandlers() { 8741 super.setEventHandlers(); 8742 $$o(this.inputs.text).on("change keyup paste", (e) => { 8743 this.setValue(e.target.value, false); 8744 this.triggerChanged(); 8745 }); 8746 } 8747 getSchema() { 8748 const schema = super.getSchema(); 8749 schema.searchFallback = MapSVG.parseBoolean(this.searchFallback); 8750 schema.placeholder = this.placeholder; 8751 schema.noResultsText = this.noResultsText; 8752 schema.width = this.width; 8753 return schema; 8754 } 8755 } 8756 8757 const $$p = jQuery; 8758 class SelectFormElement extends FormElement { 8759 constructor(options, formBuilder, external) { 8760 super(options, formBuilder, external); 8761 this.searchable = MapSVG.parseBoolean(options.searchable); 8762 this.multiselect = MapSVG.parseBoolean(options.multiselect); 8763 this.optionsGrouped = options.optionsGrouped; 8764 this.db_type = this.multiselect ? "text" : "varchar(255)"; 8765 this.setOptions(options.options); 8766 } 8767 setDomElements() { 8768 super.setDomElements(); 8769 this.inputs.select = $$p(this.domElements.main).find("select")[0]; 8770 } 8771 getSchema() { 8772 const schema = super.getSchema(); 8773 schema.multiselect = MapSVG.parseBoolean(this.multiselect); 8774 if (schema.multiselect) 8775 schema.db_type = "text"; 8776 schema.optionsGrouped = this.optionsGrouped; 8777 const opts = $$p.extend(true, {}, { options: this.options }); 8778 schema.options = opts.options || []; 8779 schema.optionsDict = {}; 8780 schema.options.forEach(function (option) { 8781 schema.optionsDict[option.value] = option.label; 8782 }); 8783 return schema; 8784 } 8785 setEventHandlers() { 8786 super.setEventHandlers(); 8787 $$p(this.inputs.select).on("change", (e) => { 8788 if (this.multiselect) { 8789 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 8790 const selectedValues = selectedOptions.map((option) => { 8791 return { label: option.label, value: option.value }; 8792 }); 8793 this.setValue(selectedValues, false); 8794 this.triggerChanged(); 8795 } 8796 else { 8797 this.setValue(this.inputs.select.value, false); 8798 this.triggerChanged(); 8799 } 8800 }); 8801 } 8802 addSelect2() { 8803 if ($$p().mselect2) { 8804 const select2Options = {}; 8805 if (this.formBuilder.filtersMode && this.type == "select") { 8806 select2Options.placeholder = this.placeholder; 8807 if (!this.multiselect) { 8808 select2Options.allowClear = true; 8809 } 8810 } 8811 $$p(this.domElements.main) 8812 .find("select") 8813 .css({ width: "100%", display: "block" }) 8814 .mselect2(select2Options) 8815 .on("select2:focus", function () { 8816 $$p(this).mselect2("open"); 8817 }); 8818 $$p(this.domElements.main) 8819 .find(".select2-selection--multiple .select2-search__field") 8820 .css("width", "100%"); 8821 } 8822 } 8823 setOptions(options) { 8824 if (options) { 8825 this.options = []; 8826 this.optionsDict = {}; 8827 options.forEach((value, key) => { 8828 this.options.push(value); 8829 if (this.optionsGrouped) { 8830 value.options.forEach((value2, key2) => { 8831 this.optionsDict[value2.value] = value2; 8832 }); 8833 } 8834 else { 8835 this.optionsDict[key] = value; 8836 } 8837 }); 8838 return this.options; 8839 } 8840 else { 8841 return this.setOptions([ 8842 { label: "Option one", name: "option_one", value: 1 }, 8843 { label: "Option two", name: "option_two", value: 2 }, 8844 ]); 8845 } 8846 } 8847 setInputValue(value) { 8848 this.inputs.select.value = value; 8849 $$p(this.inputs.select).trigger("change.select2"); 8850 } 8851 } 8852 8853 const $$q = jQuery; 8854 class StatusFormElement extends FormElement { 8855 constructor(options, formBuilder, external) { 8856 super(options, formBuilder, external); 8857 this.label = options.label || "Status"; 8858 this.name = "status"; 8859 this.setOptions(options.options); 8860 } 8861 setDomElements() { 8862 super.setDomElements(); 8863 this.inputs.select = $$q(this.domElements.main).find("select")[0]; 8864 if ($$q().colorpicker) { 8865 $$q(this.domElements.main) 8866 .find(".cpicker") 8867 .colorpicker() 8868 .on("changeColor.colorpicker", function (event) { 8869 const input = $$q(this).find("input"); 8870 if (input.val() == "") 8871 $$q(this).find("i").css({ "background-color": "" }); 8872 }); 8873 this.domElements.edit && 8874 $$q(this.domElements.edit) 8875 .find(".cpicker") 8876 .colorpicker() 8877 .on("changeColor.colorpicker", function (event) { 8878 const input = $$q(this).find("input"); 8879 if (input.val() == "") 8880 $$q(this).find("i").css({ "background-color": "" }); 8881 }); 8882 } 8883 } 8884 destroy() { 8885 if ($$q().mselect2) { 8886 const sel = $$q(this.domElements.main).find(".mapsvg-select2"); 8887 if (sel.length) { 8888 sel.mselect2("destroy"); 8889 } 8890 } 8891 } 8892 setEditorEventHandlers() { 8893 super.setEditorEventHandlers(); 8894 const _this = this; 8895 $$q(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-status-row input", function () { 8896 _this.mayBeAddStatusRow(); 8897 }); 8898 } 8899 initEditor() { 8900 super.initEditor(); 8901 const _this = this; 8902 $$q(_this.domElements.edit) 8903 .find(".cpicker") 8904 .colorpicker() 8905 .on("changeColor.colorpicker", function (event) { 8906 const input = $$q(this).find("input"); 8907 const index = $$q(this).closest("tr").index(); 8908 if (input.val() == "") 8909 $$q(this).find("i").css({ "background-color": "" }); 8910 _this.options[index] = _this.options[index] || { 8911 label: "", 8912 value: "", 8913 color: "", 8914 disabled: false, 8915 }; 8916 _this.options[index]["color"] = input.val(); 8917 }); 8918 _this.mayBeAddStatusRow(); 8919 } 8920 mayBeAddStatusRow() { 8921 const _this = this; 8922 const editStatusRow = $$q($$q("#mapsvg-edit-status-row").html()); 8923 const z = $$q(_this.domElements.edit).find(".mapsvg-edit-status-label:last-child"); 8924 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 8925 const newRow = editStatusRow.clone(); 8926 newRow.insertAfter($$q(_this.domElements.edit).find(".mapsvg-edit-status-row:last-child")); 8927 newRow 8928 .find(".cpicker") 8929 .colorpicker() 8930 .on("changeColor.colorpicker", function (event) { 8931 const input = $$q(this).find("input"); 8932 const index = $$q(this).closest("tr").index(); 8933 if (input.val() == "") 8934 $$q(this).find("i").css({ "background-color": "" }); 8935 _this.options[index] = _this.options[index] || { 8936 label: "", 8937 value: "", 8938 color: "", 8939 disabled: false, 8940 }; 8941 _this.options[index]["color"] = input.val(); 8942 }); 8943 } 8944 const rows = $$q(_this.domElements.edit).find(".mapsvg-edit-status-row"); 8945 const row1 = rows.eq(rows.length - 2); 8946 const row2 = rows.eq(rows.length - 1); 8947 if (row1.length && 8948 row2.length && 8949 !(row1.find("input:eq(0)").val().toString().trim() || 8950 row1.find("input:eq(1)").val().toString().trim() || 8951 row1.find("input:eq(2)").val().toString().trim()) && 8952 !(row2.find("input:eq(0)").val().toString().trim() || 8953 row2.find("input:eq(1)").val().toString().trim() || 8954 row2.find("input:eq(2)").val().toString().trim())) { 8955 row2.remove(); 8956 } 8957 } 8958 setEventHandlers() { 8959 super.setEventHandlers(); 8960 $$q(this.inputs.select).on("change keyup paste", (e) => { 8961 this.setValue(e.target.value, false); 8962 this.triggerChanged(); 8963 }); 8964 } 8965 getSchema() { 8966 const schema = super.getSchema(); 8967 const opts = $$q.extend(true, {}, { options: this.options }); 8968 schema.options = opts.options; 8969 schema.optionsDict = {}; 8970 schema.options.forEach(function (option, index) { 8971 if (schema.options[index].value === "") { 8972 schema.options.splice(index, 1); 8973 } 8974 else { 8975 schema.options[index].disabled = MapSVG.parseBoolean(schema.options[index].disabled); 8976 schema.optionsDict[option.value] = option; 8977 } 8978 }); 8979 return schema; 8980 } 8981 setInputValue(value) { 8982 this.inputs.select.value = value; 8983 } 8984 } 8985 8986 const $$r = jQuery; 8987 class TextareaFormElement extends FormElement { 8988 constructor(options, formBuilder, external) { 8989 super(options, formBuilder, external); 8990 this.searchType = options.searchType || "fulltext"; 8991 this.searchable = MapSVG.parseBoolean(options.searchable); 8992 this.autobr = options.autobr; 8993 this.html = options.html; 8994 this.db_type = "text"; 8995 } 8996 setDomElements() { 8997 super.setDomElements(); 8998 this.inputs.textarea = $$r(this.domElements.main).find("textarea")[0]; 8999 if (this.html) { 9000 this.editor = CodeMirror.fromTextArea(this.inputs.textarea, { 9001 mode: { name: "handlebars", base: "text/html" }, 9002 matchBrackets: true, 9003 lineNumbers: true, 9004 }); 9005 if (this.formBuilder.admin) { 9006 this.editor.on("change", this.setTextareaValue); 9007 } 9008 } 9009 } 9010 setEventHandlers() { 9011 super.setEventHandlers(); 9012 $$r(this.inputs.textarea).on("change keyup paste", (e) => { 9013 this.setValue(e.target.value, false); 9014 this.triggerChanged(); 9015 }); 9016 } 9017 getSchema() { 9018 const schema = super.getSchema(); 9019 schema.autobr = this.autobr; 9020 schema.html = this.html; 9021 return schema; 9022 } 9023 getDataForTemplate() { 9024 const data = super.getDataForTemplate(); 9025 data.html = this.html; 9026 return data; 9027 } 9028 setTextareaValue(codemirror, changeobj) { 9029 const handler = codemirror.getValue(); 9030 const textarea = $$r(codemirror.getTextArea()); 9031 textarea.val(handler).trigger("change"); 9032 } 9033 destroy() { 9034 const cm = $$r(this.domElements.main).find(".CodeMirror"); 9035 if (cm.length) { 9036 cm.empty().remove(); 9037 } 9038 } 9039 } 9040 9041 const $$s = jQuery; 9042 class TextFormElement extends FormElement { 9043
9043 constructor(options, formBuilder, external) { 9044 super(options, formBuilder, external); 9045 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9046 this.width = 9047 this.formBuilder.filtersHide && !this.formBuilder.modal 9048 ? null 9049 : options.width || "100%"; 9050 this.db_type = "varchar(255)"; 9051 } 9052 setDomElements() { 9053 super.setDomElements(); 9054 this.inputs.text = $$s(this.domElements.main).find('input[type="text"]')[0]; 9055 } 9056 getSchema() { 9057 const schema = super.getSchema(); 9058 schema.searchType = this.searchType; 9059 return schema; 9060 } 9061 setEventHandlers() { 9062 super.setEventHandlers(); 9063 $$s(this.inputs.text).on("change keyup paste", (e) => { 9064 this.setValue(e.target.value, false); 9065 this.triggerChanged(); 9066 }); 9067 } 9068 setInputValue(value) { 9069 this.inputs.text.value = value; 9070 } 9071 } 9072 9073 const $$t = jQuery; 9074 class TitleFormElement extends FormElement { 9075 constructor(options, formBuilder, external) { 9076 super(options, formBuilder, external); 9077 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9078 this.width = 9079 this.formBuilder.filtersHide && !this.formBuilder.modal 9080 ? null 9081 : options.width || "100%"; 9082 this.db_type = "varchar(255)"; 9083 } 9084 setDomElements() { 9085 super.setDomElements(); 9086 this.inputs.text = $$t(this.domElements.main).find('input[type="text"]')[0]; 9087 } 9088 getSchema() { 9089 const schema = super.getSchema(); 9090 schema.searchType = this.searchType; 9091 return schema; 9092 } 9093 setEventHandlers() { 9094 super.setEventHandlers(); 9095 $$t(this.inputs.text).on("change keyup paste", (e) => { 9096 this.setValue(e.target.value, false); 9097 this.triggerChanged(); 9098 }); 9099 } 9100 setInputValue(value) { 9101 this.inputs.text.value = value; 9102 } 9103 } 9104 9105 const $$u = jQuery; 9106 class ColorPickerFormElement extends FormElement { 9107 constructor(options, formBuilder, external) { 9108 super(options, formBuilder, external); 9109 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9110 this.width = 9111 this.formBuilder.filtersHide && !this.formBuilder.modal 9112 ? null 9113 : options.width || "100%"; 9114 this.db_type = "varchar(255)"; 9115 } 9116 setDomElements() { 9117 super.setDomElements(); 9118 this.inputs.text = $$u(this.domElements.main).find("input.cpicker")[0]; 9119 $$u(this.domElements.main).find(".colorpicker-element").colorpicker(); 9120 } 9121 getSchema() { 9122 const schema = super.getSchema(); 9123 schema.searchType = this.searchType; 9124 return schema; 9125 } 9126 setEventHandlers() { 9127 super.setEventHandlers(); 9128 $$u(this.inputs.text).on("change keyup paste", (e) => { 9129 this.setValue(e.target.value, false); 9130 this.triggerChanged(); 9131 }); 9132 $$u(this.domElements.main).find(".colorpicker-element").colorpicker().on("changeColor.colorpicker", (e) => { 9133 this.setValue(this.inputs.text.value, false); 9134 this.triggerChanged(); 9135 }); 9136 } 9137 setInputValue(value) { 9138 this.inputs.text.value = value; 9139 } 9140 } 9141 9142 const $$v = jQuery; 9143 class FormElementFactory { 9144 constructor(options) { 9145 this.mapsvg = options.mapsvg; 9146 this.editMode = options.editMode; 9147 this.filtersMode = options.filtersMode; 9148 this.namespace = options.namespace; 9149 this.mediaUploader = options.mediaUploader; 9150 this.formBuilder = options.formBuilder; 9151 this.showNames = options.showNames !== false; 9152 } 9153 create(options) { 9154 const types = { 9155 checkbox: CheckboxFormElement, 9156 checkboxes: CheckboxesFormElement, 9157 date: DateFormElement, 9158 distance: DistanceFormElement, 9159 empty: EmptyFormElement, 9160 id: IdFormElement, 9161 image: ImagesFormElement, 9162 location: LocationFormElement, 9163 modal: ModalFormElement, 9164 post: PostFormElement, 9165 radio: RadioFormElement, 9166 region: RegionsFormElement, 9167 save: SaveFormElement, 9168 search: SearchFormElement, 9169 select: SelectFormElement, 9170 status: StatusFormElement, 9171 text: TextFormElement, 9172 textarea: TextareaFormElement, 9173 title: TitleFormElement, 9174 colorpicker: ColorPickerFormElement, 9175 }; 9176 const formElement = new types[options.type](options, this.formBuilder, this.getExtraParams()); 9177 formElement.init(); 9178 return formElement; 9179 } 9180 getExtraParams() { 9181 const databaseFields = []; 9182 let databaseFieldsFilterableShort = []; 9183 const regionFields = []; 9184 const regions = []; 9185 let mapIsGeo = false;
9186 if (this.mapsvg) { 9187 mapIsGeo = this.mapsvg.isGeo(); 9188 const schemaObjects = this.mapsvg.objectsRepository.getSchema(); 9189 if (schemaObjects) { 9190 schemaObjects.getFields().forEach(function (obj) { 9191 if (obj.type == "text" || 9192 obj.type == "region" || 9193 obj.type == "textarea" || 9194 obj.type == "post" || 9195 obj.type == "select" || 9196 obj.type == "radio" || 9197 obj.type == "checkbox") { 9198 if (obj.type == "post") { 9199 databaseFields.push("Object.post.post_title"); 9200 } 9201 else { 9202 databaseFields.push("Object." + obj.name); 9203 } 9204 } 9205 }); 9206 databaseFieldsFilterableShort = schemaObjects 9207 .getFieldsAsArray() 9208 .filter(function (obj) { 9209 return obj.type == "select" || obj.type == "radio" || obj.type == "region"; 9210 }) 9211 .map(function (obj) { 9212 return obj.name; 9213 }); 9214 } 9215 const schemaRegions = this.mapsvg.regionsRepository.getSchema(); 9216 if (schemaRegions) { 9217 const regionFields = schemaRegions.getFieldsAsArray().map(function (obj) { 9218 if (obj.type == "status" || 9219 obj.type == "text" || 9220 obj.type == "textarea" || 9221 obj.type == "post" || 9222 obj.type == "select" || 9223 obj.type == "radio" || 9224 obj.type == "checkbox") { 9225 if (obj.type == "post") { 9226 return "Region.post.post_title"; 9227 } 9228 else { 9229 return "Region." + obj.name; 9230 } 9231 } 9232 }); 9233 } 9234 const regions = new ArrayIndexed("id"); 9235 this.mapsvg.regions.forEach((region) => { 9236 regions.push({ id: region.id, title: region.title }); 9237 }); 9238 } 9239 return { 9240 databaseFields: databaseFields, 9241 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 9242 regionFields: regionFields, 9243 regions: regions, 9244 mapIsGeo: mapIsGeo, 9245 mediaUploader: this.mediaUploader, 9246 filtersMode: this.filtersMode, 9247 showNames: this.showNames, 9248 }; 9249 } 9250 } 9251 9252 const $$w = jQuery; 9253 class FormBuilder { 9254 constructor(options) { 9255 const _this = this; 9256 this.events = new Events(); 9257 this.container = options.container; 9258 this.namespace = options.namespace; 9259 this.mediaUploader = options.mediaUploader; 9260 this.schema = options.schema || []; 9261 this.editMode = options.editMode == undefined ? false : options.editMode; 9262 this.filtersMode = options.filtersMode == undefined ? false : options.filtersMode; 9263 this.filtersHide = options.filtersHide == undefined ? false : options.filtersHide; 9264 this.modal = options.modal == undefined ? false : options.modal; 9265 this.admin = options.admin; 9266 this.mapsvg = options.mapsvg; 9267 this.data = options.data || {}; 9268 this.clearButton = options.clearButton || false; 9269 this.clearButtonText = options.clearButtonText || ""; 9270 this.searchButton = options.searchButton || false; 9271 this.searchButtonText = options.searchButtonText || ""; 9272 this.showButtonText = options.showButtonText || ""; 9273 this.scrollable = 9274 typeof options.scrollable !== "undefined" 9275 ? options.scrollable 9276 : !_this.editMode && !_this.filtersMode; 9277 this.showNames = typeof options.showNames !== "undefined" ? options.showNames : true; 9278 this.formElementFactory = new FormElementFactory({ 9279 mapsvg: this.mapsvg, 9280 formBuilder: this, 9281 mediaUploader: this.mediaUploader, 9282 editMode: this.editMode, 9283 filtersMode: this.filtersMode, 9284 namespace: this.namespace, 9285 showNames: this.showNames, 9286 }); 9287 this.events = new Events(this); 9288 if (options.events && Object.keys(options.events).length > 0) { 9289 for (const eventName in options.events) { 9290 this.events.on(eventName, options.events[eventName]); 9291 } 9292 } 9293 this.template = "form-builder"; 9294 this.closeOnSave = options.closeOnSave === true; 9295 this.newRecord = options.newRecord === true; 9296 this.types = options.types || [ 9297 "text", 9298 "textarea", 9299 "checkbox", 9300 "radio", 9301 "select", 9302 "image", 9303 "region", 9304 "location", 9305 "post", 9306 "date", 9307 ]; 9308 this.templates = {}; 9309 this.elements = {}; 9310 this.view = $$w("<div />").addClass("mapsvg-form-builder")[0]; 9311 if (this.editMode) 9312 $$w(this.view).addClass("full-flex"); 9313 if (!this.showNames) { 9314 $$w(this.view).addClass("hide-names"); 9315 } 9316 this.formElements = new ArrayIndexed("name"); 9317 if (!MapSVG.templatesLoaded[this.template]) { 9318 this.loadTemplates(() => this.init()); 9319 } 9320 else { 9321 this.init(); 9322 } 9323 } 9324 loadTemplates(callback) { 9325 $$w.get(MapSVG.urls.root + "dist/" + this.template + ".html", (data) => { 9326 $$w(data).appendTo("body");
9327 MapSVG.templatesLoaded[this.template] = true; 9328 Handlebars.registerPartial("dataMarkerPartial", $$w("#mapsvg-data-tmpl-marker").html()); 9329 if (this.editMode) { 9330 Handlebars.registerPartial("markerByFieldPartial", $$w("#mapsvg-markers-by-field-tmpl-partial").html()); 9331 } 9332 callback(); 9333 }); 9334 } 9335 init() { 9336 const _this = this; 9337 MapSVG.formBuilder = this; 9338 this.form = document.createElement("form"); 9339 this.form.className = "mapsvg-data-form-view"; 9340 if (!this.filtersMode) { 9341 this.form.classList.add("form-horizontal"); 9342 } 9343 if (this.editMode) { 9344 const template = document.getElementById("mapsvg-form-editor-tmpl-ui").innerHTML; 9345 const templateCompiled = Handlebars.compile(template); 9346 this.view.innerHTML = templateCompiled({ types: this.types }); 9347 this.view.classList.add("edit"); 9348 this.form.classList.add("mapsvg-data-flex-full"); 9349 this.form.classList.add("mapsvg-data-container"); 9350 $$w(this.view).find(".mapsvg-data-preview").prepend(this.form); 9351 this.formEditor = $$w(this.view).find("#mapsvg-data-form-edit")[0]; 9352 } 9353 else { 9354 this.view.appendChild(this.form); 9355 } 9356 _this.elements = { 9357 buttons: { 9358 text: $$w(_this.view).find("#mapsvg-data-btn-text")[0], 9359 textarea: $$w(_this.view).find("#mapsvg-data-btn-textarea")[0], 9360 checkbox: $$w(_this.view).find("#mapsvg-data-btn-checkbox")[0], 9361 radio: $$w(_this.view).find("#mapsvg-data-btn-radio")[0], 9362 select: $$w(_this.view).find("#mapsvg-data-btn-select")[0], 9363 image: $$w(_this.view).find("#mapsvg-data-btn-image")[0], 9364 region: $$w(_this.view).find("#mapsvg-data-btn-region")[0], 9365 marker: $$w(_this.view).find("#mapsvg-data-btn-marker")[0], 9366 saveSchema: $$w(_this.view).find("#mapsvg-data-btn-save-schema")[0], 9367 }, 9368 containers: { 9369 buttons_add: $$w(_this.view).find("#mapsvg-data-buttons-add")[0], 9370 }, 9371 }; 9372 _this.redraw(); 9373 } 9374 getForm() { 9375 return this.form; 9376 } 9377 getFormEditor() { 9378 return this.formEditor; 9379 } 9380 viewDidLoad() { } 9381 setEventHandlers() { 9382 const _this = this; 9383 if (this.filtersMode && this.clearButton) { 9384 $$w(this.elements.buttons.clearButton).on("click", () => { 9385 this.clearAllFields(); 9386 }); 9387 } 9388 $$w(window) 9389 .off("keydown.form.mapsvg") 9390 .on("keydown.form.mapsvg", function (e) { 9391 if (MapSVG.formBuilder) { 9392 if ((e.metaKey || e.ctrlKey) && e.keyCode == 13) 9393 MapSVG.formBuilder.save(); 9394 else if (e.keyCode == 27) 9395 MapSVG.formBuilder.close(); 9396 } 9397 }); 9398 if (this.editMode) { 9399 $$w(this.view).on("click", "#mapsvg-data-buttons-add button", function (e) { 9400 e.preventDefault(); 9401 const type = $$w(this).data("create"); 9402 const formElement = _this.formElementFactory.create({ type: type }); 9403 _this.addField(formElement); 9404 }); 9405 $$w(this.view).on("click", "#mapsvg-data-btn-save-schema", function (e) { 9406 e.preventDefault(); 9407 const fields = _this.getSchema(); 9408 const counts = {}; 9409 _this.formElements.forEach(function (elem) { 9410 counts[elem.name] = (counts[elem.name] || 0) + 1; 9411 }); 9412 $$w(_this.getForm()).find(".form-group").removeClass("has-error"); 9413 const errors = []; 9414 const reservedFields = [ 9415 "lat", 9416 "lon", 9417 "lng", 9418 "location", 9419 "location_lat", 9420 "location_lon", 9421 "location_lng", 9422 "location_address", 9423 "location_img", 9424 "marker", 9425 "marker_id", 9426 "regions", 9427 "region_id", 9428 "post", 9429 "post_title", 9430 "post_url", 9431 "keywords", 9432 "status", 9433 ]; 9434 const reservedFieldsToTypes = { 9435 regions: "region", 9436 status: "status", 9437 post: "post", 9438 marker: "marker", 9439 location: "location", 9440 }; 9441 let errUnique, errEmpty;
9442 _this.formElements.forEach(function (formElement, index) { 9443 let err = false; 9444 if (!_this.filtersMode) { 9445 if (counts[formElement.name] > 1) { 9446 if (!errUnique) { 9447 errUnique = "Field names should be unique"; 9448 errors.push(errUnique); 9449 err = true; 9450 } 9451 } 9452 else if (formElement.name.length === 0) { 9453 if (!errEmpty) { 9454 errEmpty = "Field name can't be empty"; 9455 errors.push(errEmpty); 9456 err = true; 9457 } 9458 } 9459 else if (reservedFields.indexOf(formElement.name) != -1) { 9460 if (!reservedFieldsToTypes[formElement.name] || 9461 (reservedFieldsToTypes[formElement.name] && 9462 reservedFieldsToTypes[formElement.name] != formElement.type)) { 9463 const msg = 'Field name "' + 9464 formElement.name + 9465 '" is reserved, please set another name'; 9466 errors.push(msg); 9467 err = true; 9468 } 9469 } 9470 } 9471 if (formElement.options && 9472 formElement.type != "region" && 9473 formElement.type != "marker") { 9474 const vals = formElement.options.map(function (obj) { 9475 return obj.value; 9476 }); 9477 const uniq = [...Array.from(new Set(vals).values())]; 9478 if (vals.length != uniq.length) { 9479 errors.push('Check "Options" list - values should not repeat'); 9480 err = true; 9481 } 9482 } 9483 err && $$w(formElement.domElements.main).addClass("has-error"); 9484 }); 9485 if (errors.length === 0) { 9486 _this.events.trigger("saveSchema", _this, [_this, fields]); 9487 } 9488 else { 9489 jQuery.growl.error({ title: "Errors", message: errors.join("<br />") }); 9490 } 9491 }); 9492 setTimeout(function () { 9493 const el = _this.getForm(); 9494 _this.sortable = new Sortable(el, { 9495 animation: 150, 9496 onStart: function () { 9497 $$w(_this.getForm()).addClass("sorting"); 9498 }, 9499 onEnd: function () { 9500 setTimeout(function () { 9501 $$w(_this.getForm()).removeClass("sorting"); 9502 _this.formElements.clear(); 9503 $$w(el) 9504 .find(".form-group") 9505 .each(function (index, elem) { 9506 _this.formElements.push($$w(elem).data("formElement")); 9507 }); 9508 }, 500); 9509 }, 9510 }); 9511 }, 1000); 9512 } 9513 new ResizeSensor(this.view, function () { 9514 _this.scrollApi && _this.scrollApi.reinitialise(); 9515 }); 9516 } 9517 clearAllFields() { 9518 $$w(this.getForm()) 9519 .find("input") 9520 .not(":button, :submit, :reset, :hidden, :checkbox, :radio") 9521 .val("") 9522 .prop("selected", false); 9523 $$w(this.getForm()).find('input[type="radio"]').prop("checked", false); 9524 $$w(this.getForm()).find('input[type="checkbox"]').prop("checked", false); 9525 $$w(this.getForm()).find("select").val("").trigger("change.select2"); 9526 this.events.trigger("cleared"); 9527 } 9528 setFormElementEventHandlers(formElement) { 9529 const _this = this; 9530 if (this.editMode) { 9531 formElement.events.on("click", (elem) => { 9532 this.edit(elem); 9533 }); 9534 formElement.events.on("delete", (elem) => { 9535 this.deleteField(elem); 9536 }); 9537 } 9538 else { 9539 formElement.events.on("changed", (_formElement) => { 9540 const name = _formElement.name; 9541 const value = _formElement.value; 9542 if (_formElement.type !== "search") { 9543 this.events.trigger("changed.field", _formElement, [_formElement, name, value]); 9544 } 9545 else { 9546 this.events.trigger("changed.search", _formElement, [_formElement, value]); 9547 } 9548 }); 9549 const locationField = _this.mapsvg && 9550 _this.mapsvg.objectsRepository && 9551 _this.mapsvg.objectsRepository.getSchema() && 9552 _this.mapsvg.objectsRepository.getSchema().getField("location"); 9553 if (locationField && 9554 locationField.markersByFieldEnabled && 9555 locationField.markerField && 9556 formElement.name == locationField.markerField && 9557 Object.values(locationField.markersByField).length > 0) { 9558 formElement.events.on("changed", (_formElement) => { 9559 const name = _formElement.name; 9560 const value = _formElement.value; 9561 const src = locationField.markersByField[value]; 9562 if (src) { 9563 if (_this.markerBackup) { 9564 const marker = _this.mapsvg.getMarker(_this.markerBackup.id); 9565 marker.setImage(src); 9566 $$w(_this.view).find(".mapsvg-marker-image-btn img").attr("src", src); 9567 } 9568 } 9569 }); 9570 } 9571 } 9572 } 9573 save() { 9574 const _this = this; 9575 if (_this.markerBackup) { 9576 const marker = _this.mapsvg.getEditingMarker(); 9577 marker.events.off("change"); 9578 _this.markerBackup = marker.getOptions(); 9579 _this.mapsvg.unsetEditingMarker(); 9580 } 9581 const data = _this.getData(); 9582 _this.saved = true; 9583 this.events.trigger("save", _this, [_this, data]); 9584 } 9585 getFormElementByType(type) { 9586 return this.formElements.find((el) => el.type === type); 9587 } 9588 getData() { 9589 const data = {};
9590 this.formElements.forEach((formElement) => { 9591 if (formElement.readonly === false || formElement.type === "id") { 9592 const _formElementData = formElement.getData(); 9593 data[_formElementData.name] = _formElementData.value; 9594 } 9595 }); 9596 return data; 9597 } 9598 reset() { 9599 this.formElements.forEach((formElement) => { 9600 formElement.setValue(null); 9601 }); 9602 } 9603 update(data) { 9604 this.schema.getFields().forEach((field) => { 9605 const formElement = this.formElements.get(field.name); 9606 if (formElement) { 9607 if (typeof data[field.name] !== "undefined") { 9608 formElement.setValue(data[field.name]); 9609 } 9610 else { 9611 formElement.setValue(null); 9612 } 9613 } 9614 }); 9615 } 9616 redraw() { 9617 const _this = this; 9618 delete _this.markerBackup; 9619 $$w(this.container).empty(); 9620 $$w(this.getForm()).empty(); 9621 this.formElements.clear(); 9622 this.schema && 9623 this.schema.fields.length > 0 && 9624 this.schema.fields.forEach((fieldSettings) => { 9625 if (this.filtersMode) { 9626 if (fieldSettings.type == "distance") { 9627 fieldSettings.value = this.data.distance 9628 ? this.data.distance 9629 : fieldSettings.value !== undefined 9630 ? fieldSettings.value 9631 : null; 9632 } 9633 else { 9634 fieldSettings.value = this.data[fieldSettings.parameterNameShort]; 9635 } 9636 } 9637 else { 9638 fieldSettings.value = this.data 9639 ? this.data[fieldSettings.name] 9640 : fieldSettings.value !== undefined 9641 ? fieldSettings.value 9642 : null; 9643 } 9644 if (fieldSettings.type == "location" && !this.editMode) { 9645 if (fieldSettings.value && 9646 fieldSettings.value.marker && 9647 fieldSettings.value.marker.id) ; 9648 this.admin && this.admin.setMode && this.admin.setMode("editMarkers"); 9649 this.admin && this.admin.enableMarkersMode(true); 9650 } 9651 else if (fieldSettings.type == "post") { 9652 fieldSettings.post = this.data["post"]; 9653 } 9654 else if (fieldSettings.type === "region") { 9655 fieldSettings.options = new ArrayIndexed("id", this.getRegionsList()); 9656 } 9657 const formElement = this.formElementFactory.create(fieldSettings); 9658 if (this.filtersMode) { 9659 if (!this.filtersHide || 9660 (this.filtersHide && this.modal && fieldSettings.type !== "search") || 9661 (!this.modal && fieldSettings.type === "search")) { 9662 this.addField(formElement); 9663 } 9664 } 9665 else { 9666 this.addField(formElement); 9667 } 9668 }); 9669 if (!_this.editMode) { 9670 if (this.schema.fields.length === 0 && !this.filtersMode) { 9671 const formElement = this.formElementFactory.create({ type: "empty" }); 9672 _this.addField(formElement); 9673 } 9674 else { 9675 if (_this.admin && !_this.admin.isMetabox) { 9676 const formElement = this.formElementFactory.create({ type: "save" }); 9677 formElement.events.on("click.btn.save", () => { 9678 this.save(); 9679 }); 9680 formElement.events.on("click.btn.close", () => { 9681 this.close(); 9682 }); 9683 _this.addField(formElement); 9684 } 9685 } 9686 } 9687 if (_this.filtersMode && _this.filtersHide && !_this.modal) { 9688 const formElement = this.formElementFactory.create({ 9689 type: "modal", 9690 showButtonText: _this.showButtonText, 9691 });
9692 this.showFiltersButton = _this.addField(formElement); 9693 } 9694 if (this.scrollable) { 9695 const nano = $$w('<div class="nano"></div>'); 9696 const nanoContent = $$w('<div class="nano-content"></div>'); 9697 nano.append(nanoContent); 9698 nanoContent.append(this.view); 9699 $$w(_this.container).append(nano); 9700 nano.jScrollPane({ contentWidth: "0px", mouseWheelSpeed: 30 }); 9701 _this.scrollApi = nano.data("jsp"); 9702 } 9703 else { 9704 $$w(_this.container).append(this.view); 9705 } 9706 if (_this.filtersMode && _this.clearButton) { 9707 _this.elements.buttons.clearButton = $$w('<div class="form-group mapsvg-filters-reset-container"><button class="btn btn-outline-secondary mapsvg-filters-reset">' + 9708 _this.clearButtonText + 9709 "</button></div>")[0]; 9710 $$w(this.getForm()).append(_this.elements.buttons.clearButton); 9711 } 9712 if (_this.filtersMode && _this.searchButton) { 9713 _this.elements.buttons.searchButton = $$w('<div class="form-group mapsvg-filters-reset-container" id="mapsvg-search-container"><button class="btn btn-outline-secondary mapsvg-filters-reset">' + 9714 _this.searchButtonText + 9715 "</button></div>")[0]; 9716 $$w(this.getForm()).append(_this.elements.buttons.searchButton); 9717 } 9718 if (!this.editMode && !_this.filtersMode) 9719 $$w(this.view).find("input:visible,textarea:visible").not(".tt-hint").first().focus(); 9720 const cm = $$w(this.container).find(".CodeMirror"); 9721 cm.each(function (index, el) { 9722 el && el.CodeMirror.refresh(); 9723 }); 9724 _this.setEventHandlers(); 9725 this.events.trigger("init", this, [this, this.getData()]); 9726 this.events.trigger("loaded", this, [this]); 9727 } 9728 updateExtraParamsInFormElements() { 9729 this.formElements.forEach((formElement) => { 9730 formElement.setExternal(this.formElementFactory.getExtraParams()); 9731 if (formElement.type === "location") { 9732 formElement.redraw(); 9733 } 9734 }); 9735 } 9736 deleteField(formElement) { 9737 const _this = this; 9738 _this.formElements.delete(formElement.name); 9739 } 9740 getExtraParams() { 9741 const databaseFields = []; 9742 this.mapsvg.objectsRepository 9743 .getSchema() 9744 .getFields() 9745 .forEach(function (obj) { 9746 if (obj.type == "text" || 9747 obj.type == "region" || 9748 obj.type == "textarea" || 9749 obj.type == "post" || 9750 obj.type == "select" || 9751 obj.type == "radio" || 9752 obj.type == "checkbox") { 9753 if (obj.type == "post") { 9754 databaseFields.push("Object.post.post_title"); 9755 } 9756 else { 9757 databaseFields.push("Object." + obj.name); 9758 } 9759 } 9760 }); 9761 let databaseFieldsFilterableShort = []; 9762 databaseFieldsFilterableShort = this.mapsvg.objectsRepository 9763 .getSchema() 9764 .getFieldsAsArray() 9765 .filter(function (obj) { 9766 return obj.type == "select" || obj.type == "radio" || obj.type == "region"; 9767 }) 9768 .map(function (obj) { 9769 return obj.name; 9770 }); 9771 let markerFieldsShort = []; 9772 markerFieldsShort = databaseFieldsFilterableShort.filter((o) => o.type === "select" || o.type === "radio"); 9773 const regionFields = this.mapsvg.regionsRepository 9774 .getSchema() 9775 .getFieldsAsArray() 9776 .map(function (obj) { 9777 if (obj.type == "status" || 9778 obj.type == "text" || 9779 obj.type == "textarea" || 9780 obj.type == "post" || 9781 obj.type == "select" || 9782 obj.type == "radio" || 9783 obj.type == "checkbox") { 9784 if (obj.type == "post") { 9785 return "Region.post.post_title"; 9786 } 9787 else { 9788 return "Region." + obj.name; 9789 } 9790 } 9791 }); 9792 return { 9793 databaseFields: databaseFields, 9794 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 9795 regionFields: regionFields, 9796 markerFieldsShort: markerFieldsShort, 9797 }; 9798 } 9799 addField(formElement) { 9800 const _this = this; 9801 if (["region", "marker", "post", "status", "distance", "location", "search"].indexOf(formElement.type) != -1) { 9802 let repeat = false;
9803 _this.formElements.forEach(function (control) { 9804 if (control.type == formElement.type) 9805 repeat = true; 9806 }); 9807 if (repeat) { 9808 jQuery.growl.error({ 9809 title: "Error", 9810 message: 'You can add only 1 "' + MapSVG.ucfirst(formElement.type) + '" field', 9811 }); 9812 return; 9813 } 9814 } 9815 _this.formElements.push(formElement); 9816 _this.getForm().append(formElement.domElements.main); 9817 this.setFormElementEventHandlers(formElement); 9818 if (this.editMode) { 9819 if (formElement.protected) { 9820 formElement.hide(); 9821 } 9822 else { 9823 this.edit(formElement); 9824 } 9825 } 9826 return formElement; 9827 } 9828 edit(formElement) { 9829 const _this = this; 9830 _this.currentlyEditing && _this.currentlyEditing.destroyEditor(); 9831 this.getFormEditor().appendChild(formElement.getEditor()); 9832 formElement.initEditor(); 9833 _this.currentlyEditing = formElement; 9834 $$w(_this.getForm()).find(".form-group.active").removeClass("active"); 9835 $$w(formElement.domElements.main).addClass("active"); 9836 } 9837 get() { 9838 } 9839 getSchema() { 9840 return this.formElements.map(function (formElement) { 9841 return formElement.getSchema(); 9842 }); 9843 } 9844 close() { 9845 this.formElements.forEach((formElement) => formElement.destroy()); 9846 MapSVG.formBuilder = null; 9847 this.events.trigger("close", this, [this]); 9848 } 9849 destroy() { 9850 $$w(this.view).empty().remove(); 9851 this.sortable = null; 9852 } 9853 toJSON(addEmpty) { 9854 const obj = {}; 9855 function add(obj, name, value) { 9856 if (!addEmpty && !value) 9857 return false; 9858 if (name.length == 1) { 9859 obj[name[0]] = value; 9860 } 9861 else { 9862 if (obj[name[0]] == null) { 9863 if (name[1] === "") { 9864 obj[name[0]] = []; 9865 } 9866 else { 9867 obj[name[0]] = {}; 9868 } 9869 } 9870 if (obj[name[0]].length !== undefined) { 9871 obj[name[0]].push(value); 9872 } 9873 else { 9874 add(obj[name[0]], name.slice(1), value); 9875 } 9876 } 9877 } 9878 $$w(this.elements.containers.formView) 9879 .find("input, textarea, select") 9880 .each(function () { 9881 if (!$$w(this).data("skip") && 9882 !$$w(this).prop("disabled") && 9883 $$w(this).attr("name") && 9884 !(!addEmpty && 9885 $$w(this).attr("type") == "checkbox" && 9886 $$w(this).attr("checked") == undefined) && 9887 !($$w(this).attr("type") == "radio" && $$w(this).attr("checked") == undefined)) { 9888 let value; 9889 if ($$w(this).attr("type") == "checkbox") { 9890 value = $$w(this).prop("checked"); 9891 } 9892 else { 9893 value = $$w(this).val(); 9894 } 9895 add(obj, $$w(this).attr("name").replace(/]/g, "").split("["), value); 9896 } 9897 }); 9898 return obj; 9899 } 9900 getRegionsList() { 9901 return this.mapsvg.regions.map(function (r) { 9902 return { id: r.id, title: r.title }; 9903 }); 9904 } 9905 getRegionsAsArray() { 9906 return this.mapsvg.regions; 9907 } 9908 setRegions(location) { 9909 const regionsFormElement = this.formElements.get("regions"); 9910 if (this.mapsvg.options.source.indexOf("/geo-calibrated/us
9910a.svg") !== -1) { 9911 regionsFormElement.setValue(["US-" + location.address.state_short]); 9912 } 9913 else if (this.mapsvg.options.source.indexOf("/geo-calibrated/world.svg") !== -1) { 9914 if (location.address.country_short) { 9915 regionsFormElement.setValue([location.address.country_short]); 9916 } 9917 } 9918 else { 9919 if (location.address.administrative_area_level_1) { 9920 this.mapsvg.regions.forEach((_region) => { 9921 if (_region.title === location.address.administrative_area_level_1 || 9922 _region.title === location.address.administrative_area_level_2 || 9923 _region.id === 9924 location.address.country_short + 9925 "-" + 9926 location.address.administrative_area_level_1_short) { 9927 regionsFormElement.setValue([_region.id]); 9928 } 9929 }); 9930 } 9931 } 9932 } 9933 } 9934 9935 const $$x = jQuery; 9936 class FiltersController extends DetailsController { 9937 constructor(options) { 9938 super(options); 9939 this.showButtonText = options.showButtonText; 9940 this.clearButton = options.clearButton; 9941 this.clearButtonText = options.clearButtonText; 9942 this.searchButton = options.searchButton; 9943 this.searchButtonText = options.searchButtonText; 9944 this.padding = options.padding; 9945 this.schema = options.schema; 9946 this.hideFilters = options.hide; 9947 this.query = options.query; 9948 } 9949 viewDidLoad() { 9950 super.viewDidLoad(); 9951 const _this = this; 9952 this.formBuilder = new FormBuilder({ 9953 container: this.containers.contentView, 9954 filtersMode: true, 9955 schema: this.schema, 9956 modal: this.modal, 9957 filtersHide: this.hideFilters, 9958 showButtonText: this.showButtonText, 9959 clearButton: this.clearButton, 9960 clearButtonText: this.clearButtonText, 9961 searchButton: this.searchButton, 9962 searchButtonText: this.searchButtonText, 9963 editMode: false, 9964 mapsvg: this.mapsvg, 9965 data: {}, 9966 admin: false, 9967 events: { 9968 "changed.field": (formElement, field, value) => { 9969 const filters = {}; 9970 filters[field] = value; 9971 this.query.setFilters(filters); 9972 _this.events.trigger("changed.field", _this, [field, value]); 9973 _this.events.trigger("changed.fields", _this, [field, value]); 9974 }, 9975 "changed.search": (formElement, value) => { 9976 this.query.setSearch(value); 9977 _this.events.trigger("changed.search", _this, [value]); 9978 }, 9979 cleared: (formBuilder) => { 9980 this.query.clearFilters(); 9981 this.events.trigger("cleared.filters", _this, []); 9982 }, 9983 loaded: (formBuilder) => { 9984 $$x(formBuilder.container).find(".mapsvg-form-builder").css({ 9985 padding: _this.padding, 9986 }); 9987 this.updateScroll(); 9988 this.events.trigger("loaded"); 9989 }, 9990 }, 9991 }); 9992 } 9993 reset() { 9994 this.formBuilder && this.formBuilder.reset(); 9995 } 9996 update(query) { 9997 this.formBuilder && this.formBuilder.update(query.filters); 9998 } 9999 setFiltersCounter() { 10000 if (this.hideFilters) { 10001 const filtersCounter = Object.keys(this.query.filters).length; 10002 const filtersCounterString = filtersCounter === 0 ? "" : f
10002iltersCounter.toString(); 10003 this.formBuilder && 10004 this.formBuilder.showFiltersButton && 10005 $$x(this.formBuilder.showFiltersButton.domElements.main) 10006 .find("button") 10007 .html(this.showButtonText + " <b>" + filtersCounterString + "</b>"); 10008 } 10009 } 10010 setEventHandlers() { 10011 super.setEventHandlers(); 10012 const _this = this; 10013 $$x(this.containers.view).on("click", ".mapsvg-btn-show-filters", function () { 10014 _this.events.trigger("click.btn.showFilters"); 10015 }); 10016 $$x(this.containers.view).on("click", "#mapsvg-search-container", function () { 10017 _this.events.trigger("click.btn.searchButton"); 10018 }); 10019 } 10020 } 10021 10022 const $$y = jQuery; 10023 class PopoverController extends Controller { 10024 constructor(options) { 10025 super(options); 10026 options.autoresize = true; 10027 this.point = options.point; 10028 this.yShift = options.yShift; 10029 this.mapObject = options.mapObject; 10030 this.id = this.mapObject.id + "_" + Math.random(); 10031 $$y(this.containers.main).data("popover-id", this.id); 10032 } 10033 setPoint(point) { 10034 this.point = point; 10035 } 10036 getToolbarTemplate() { 10037 if (this.withToolbar) 10038 return '<div class="mapsvg-popover-close"></div>'; 10039 else 10040 return ""; 10041 } 10042 viewDidLoad() { 10043 super.viewDidLoad.call(this); 10044 if (MapSVG.isPhone && 10045 this.mapsvg.options.popovers.mobileFullscreen && 10046 !this.mobileCloseBtn) { 10047 this.mobileCloseBtn = $$y('<button class="mapsvg-mobile-modal-close mapsvg-btn">' + 10048 this.mapsvg.getData().options.mobileView.labelClose + 10049 "</button>")[0]; 10050 $$y(this.containers.view).append(this.mobileCloseBtn); 10051 } 10052 this.adjustScreenPosition(); 10053 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10054 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10055 this.adjustHeight(); 10056 this.updateScroll(); 10057 this.autoresize && this.resizeSensor.setScroll(); 10058 this.events.trigger("shown", this, [this]); 10059 } 10060 adjustHeight() { 10061 $$y(this.containers.main).height($$y(this.containers.main).find(".mapsvg-auto-height").outerHeight() + 10062 (this.containers.toolbar ? $$y(this.containers.toolbar).outerHeight() : 0)); 10063 } 10064 adjustScreenPosition() { 10065 if (this.point) { 10066 const pos = this.mapsvg.converter.convertSVGToPixel(this.point); 10067 pos.y -= this.yShift; 10068 pos.x = Math.round(pos.x); 10069 pos.y = Math.round(pos.y); 10070 this.setScreenPosition(pos.x, pos.y); 10071 } 10072 } 10073 moveSrceenPositionBy(deltaX, deltaY) { 10074 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 10075 this.setScreenPosition(x, y); 10076 } 10077 setScreenPosition(x, y) { 10078 this.screenPoint = new ScreenPoint(x, y); 10079 $$y(this.containers.main).css({ 10080 transform: "translateX(-50%) translate(" + x + "px," + y + "px)", 10081 }); 10082 } 10083 setEventHandlers() { 10084 $$y("body").off(".popover.mapsvg"); 10085 $$y(this.containers.view).on("click touchend", ".mapsvg-popover-close, .mapsvg-mobile-modal-close", (e) => { 10086 e.stopImmediatePropagation(); 10087 this.close(); 10088 }); 10089 $$y("body").on("mouseup.popover.mapsvg touchend.popover.mapsvg", (e) => { 10090 if (this.mapsvg.isScrolling || 10091 $$y(e.target).closest(".mapsvg-directory").length || 10092 $$y(e.target).closest(".mapsvg-popover").length || 10093 $$y(e.target).hasClass("mapsvg-btn-map")) 10094 return; 10095 this.close(); 10096 }); 10097 } 10098 close() { 10099 if ($$y(this.containers.main).data("popover-id") != this.id || 10100 !$$y(this.containers.main).is(":visible")) 10101 return; 10102 this.destroy(); 10103 if (this.mapObject instanceof Region) { 10104 this.mapsvg.deselectRegion(this.mapObject); 10105 } 10106 if (this.mapObject instanceof Marker) { 10107 this.mapsvg.deselectAllMarkers(); 10108 } 10109 this.events.trigger("closed", this, [this]); 10110 } 10111 destroy() { 10112 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", false); 10113 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", false); 10114 super.destroy.call(this); 10115 } 10116 show() { 10117 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10118 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10119 } 10120 } 10121 10122 const $$z = jQuery; 10123 class Tooltip extends Controller { 10124 constructor(options) { 10125 super(options); 10126 this.scrollable = false;
10127 this.withToolbar = false; 10128 this.autoresize = false; 10129 this.screenPoint = new ScreenPoint(0, 0); 10130 this.posOriginal = {}; 10131 this.posShifted = {}; 10132 this.posShiftedPrev = {}; 10133 this.mirror = {}; 10134 this.noPadding = true; 10135 this.setPosition(options.position); 10136 this.setSize(options.minWidth, options.maxWidth); 10137 } 10138 setSize(minWidth, maxWidth) { 10139 this.minWidth = minWidth; 10140 this.maxWidth = maxWidth; 10141 this.containers.main.style["min-width"] = this.minWidth + "px"; 10142 this.containers.main.style["max-width"] = this.maxWidth + "px"; 10143 } 10144 setPosition(position) { 10145 const ex = position.split("-"); 10146 if (ex[0].indexOf("top") != -1 || ex[0].indexOf("bottom") != -1) { 10147 this.posOriginal.topbottom = ex[0]; 10148 } 10149 if (ex[0].indexOf("left") != -1 || ex[0].indexOf("right") != -1) { 10150 this.posOriginal.leftright = ex[0]; 10151 } 10152 if (ex[1]) { 10153 this.posOriginal.leftright = ex[1]; 10154 } 10155 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10156 this.containers.main.classList.add("mapsvg-tt-" + position); 10157 } 10158 setScreenPoint(x, y) { 10159 this.screenPoint.x = x; 10160 this.screenPoint.y = y; 10161 } 10162 viewDidLoad() { 10163 super.viewDidLoad.call(this); 10164 } 10165 viewDidAppear() { 10166 super.viewDidAppear(); 10167 this.events.trigger("shown", this, [this]); 10168 } 10169 setScreenPosition(x, y) { 10170 this.setScreenPoint(x, y); 10171 this.containers.main.style.transform = 10172 "translateX(-50%) translate(" + x + "px," + y + "px)"; 10173 } 10174 setEventHandlers() { 10175 const event = "mousemove.tooltip.mapsvg-" + this.mapsvg.id; 10176 $$z("body") 10177 .off(event) 10178 .on(event, (e) => { 10179 MapSVG.mouse = MapSVG.mouseCoords(e); 10180 this.containers.main.style.left = 10181 e.clientX + 10182 $$z(window).scrollLeft() - 10183 $$z(this.mapsvg.containers.map).offset().left + 10184 "px"; 10185 this.containers.main.style.top = 10186 e.clientY + 10187 $$z(window).scrollTop() - 10188 $$z(this.mapsvg.containers.map).offset().top + 10189 "px"; 10190 const m = new ScreenPoint(e.clientX + $$z(window).scrollLeft(), e.clientY + $$z(window).scrollTop()); 10191 const _tbbox = this.containers.main.getBoundingClientRect(); 10192 const _mbbox = this.mapsvg.containers.wrap.getBoundingClientRect(); 10193 const tbbox = { 10194 top: _tbbox.top + $$z(window).scrollTop(), 10195 bottom: _tbbox.bottom + $$z(window).scrollTop(), 10196 left: _tbbox.left + $$z(window).scrollLeft(), 10197 right: _tbbox.right + $$z(window).scrollLeft(), 10198 width: _tbbox.width, 10199 height: _tbbox.height, 10200 }; 10201 const mbbox = { 10202 top: _mbbox.top + $$z(window).scrollTop(), 10203 bottom: _mbbox.bottom + $$z(window).scrollTop(), 10204 left: _mbbox.left + $$z(window).scrollLeft(), 10205 right: _mbbox.right + $$z(window).scrollLeft(), 10206 width: _mbbox.width, 10207 height: _mbbox.height, 10208 }; 10209 if (m.x > mbbox.right || 10210 m.y > mbbox.bottom || 10211 m.x < mbbox.left || 10212 m.y < mbbox.top) { 10213 return; 10214 } 10215 if (this.mirror.top || this.mirror.bottom) { 10216 if (this.mirror.top && m.y > this.mirror.top) { 10217 this.mirror.top = 0; 10218 delete this.posShifted.topbottom; 10219 } 10220 else if (this.mirror.bottom && m.y < this.mirror.bottom) { 10221 this.mirror.bottom = 0; 10222 delete this.posShifted.topbottom; 10223 } 10224 } 10225 else { 10226 if (tbbox.bottom < mbbox.top + tbbox.height) { 10227 this.posShifted.topbottom = "bottom"; 10228 this.mirror.top = m.y; 10229 } 10230 else if (tbbox.top > mbbox.bottom - tbbox.height) { 10231 this.posShifted.topbottom = "top"; 10232 this.mirror.bottom = m.y; 10233 } 10234 } 10235 if (this.mirror.right || this.mirror.left) { 10236 if (this.mirror.left && m.x > this.mirror.left) { 10237 this.mirror.left = 0; 10238 delete this.posShifted.leftright; 10239 } 10240 else if (this.mirror.right && m.x < this.mirror.right) { 10241 this.mirror.right = 0; 10242 delete this.posShifted.leftright; 10243 } 10244 } 10245 else { 10246 if (tbbox.right < mbbox.left + tbbox.width) { 10247 this.posShifted.leftright = "right"; 10248 this.mirror.left = m.x; 10249 } 10250 else if (tbbox.left > mbbox.right - tbbox.width) { 10251 this.posShifted.leftright = "left"; 10252 this.mirror.right = m.x; 10253 } 10254 } 10255 let pos = $$z.extend({}, this.posOriginal, this.posShifted); 10256 const _pos = []; 10257 pos.topbottom && _pos.push(pos.topbottom); 10258 pos.leftright && _pos.push(pos.leftright); 10259 pos = _pos.join("-"); 10260 if (this.posShifted.topbottom != this.posOriginal.topbottom || 10261 this.posShifted.leftright != this.posOriginal.leftright) { 10262 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10263 this.containers.main.classList.add("mapsvg-tt-" + pos); 10264 this.posShiftedPrev = pos; 10265 } 10266 }); 10267 } 10268 setContent(template, data) { 10269 this.containers.main.innerHTML = template(data); 10270 return this; 10271 } 10272 show() { 10273 this.containers.main.classList.add("mapsvg-tooltip-visible"); 10274 return this; 10275 } 10276 hide() { 10277 this.containers.main.classList.remove("mapsvg-tooltip-visible"); 10278 return this; 10279 } 10280 } 10281 10282 const $$A = jQuery; 10283 class MapSVGMap { 10284 constructor(containerId, mapParams) { 10285 this.markerOptions = { src: MapSVG.urls.root + "markers/pin1_red.png" }; 10286 const options = mapParams.options; 10287 this.updateOutdatedOptions(options); 10288 this.dirtyFields = []; 10289 this.containerId = containerId; 10290 this.options = $$A.extend(true, {}, DefaultOptions, options); 10291 this.options.source = this.urlToRelativePath(this.options.source); 10292 this.editMode = this.options.editMode; 10293 delete this.options.editMode; 10294 this.id = mapParams.id; 10295 this.svgFileLastChanged = mapParams.svgFileLastChanged; 10296 this.regions = new ArrayIndexed("id"); 10297 this.objects = new ArrayIndexed("id"); 10298 this.events = new Events(this); 10299 this.highlightedRegions = []; 10300 this.editRegions = { on: false }; 10301 this.editMarkers = { on: false }; 10302 this.editData = { on: false }; 10303 this.controllers = {}; 10304 this.containers = { 10305 map: document.getElementById(this.containerId), 10306 scrollpane: $$A('<div class="mapsvg-scrollpane"></div>')[0], 10307 layers: $$A('<div class="mapsvg-layers-wrap"></div>')[0], 10308 }; 10309 this.containers.map.appendChild(this.containers.layers); 10310 this.containers.map.appendChild(this.containers.scrollpane); 10311 this.whRatio = 0; 10312 this.isScrolling = false;
10313 this.markerOptions = {}; 10314 this.svgDefault = {}; 10315 this.scale = 1; 10316 this._scale = 1; 10317 this.selected_id = []; 10318 this.regions = new ArrayIndexed("id"); 10319 if (!this.options.database.regionsTableName) { 10320 this.options.database.regionsTableName = "regions_" + this.id; 10321 } 10322 if (!this.options.database.objectsTableName) { 10323 this.options.database.objectsTableName = "objects_" + this.id; 10324 } 10325 this.regionsRepository = new Repository("region", "regions/" + this.options.database.regionsTableName); 10326 this.regionsRepository.query.update({ perpage: 0 }); 10327 this.objectsRepository = new Repository("object", "objects/" + this.options.database.objectsTableName); 10328 this.objectsRepository.query.update({ perpage: this.options.database.pagination.perpage }); 10329 this.schemaRepository = new SchemaRepository(); 10330 this.markers = new ArrayIndexed("id"); 10331 this.markersClusters = new ArrayIndexed("id"); 10332 this._viewBox = new ViewBox(0, 0, 0, 0); 10333 this.viewBox = new ViewBox(0, 0, 0, 0); 10334 this.zoomLevel = 0; 10335 this.scroll = { 10336 tx: 0, 10337 ty: 0, 10338 vxi: 0, 10339 vyi: 0, 10340 x: 0, 10341 y: 0, 10342 dx: 0, 10343 dy: 0, 10344 vx: 0, 10345 vy: 0, 10346 gx: 0, 10347 gy: 0, 10348 touchScrollStart: 0, 10349 }; 10350 this.layers = {}; 10351 this.geoCoordinates = false; 10352 this.geoViewBox = new GeoViewBox(new GeoPoint(0, 0), new GeoPoint(0, 0)); 10353 this.eventsPreventList = {}; 10354 this.googleMaps = { 10355 loaded: false, 10356 initialized: false, 10357 map: null, 10358 zoomLimit: true, 10359 maxZoomService: null, 10360 }; 10361 this.init(); 10362 } 10363 urlToRelativePath(url) { 10364 if (url.indexOf("//") === 0) 10365 url = url.replace(/^\/\/[^/]+/, "").replace("//", "/"); 10366 else 10367 url = url.replace(/^.*:\/\/[^/]+/, "").replace("//", "/"); 10368 return url; 10369 } 10370 setGroups(groups) { 10371 const _this = this; 10372 if (!this.groups) { 10373 _this.groups = new ArrayIndexed("id", _this.options.groups, { 10374 autoId: true, 10375 unique: true, 10376 }); 10377 } 10378 else { 10379 this.options.groups = this.groups; 10380 } 10381 _this.groups.forEach(function (g) { 10382 g.objects && 10383 g.objects.length && 10384 g.objects.forEach(function (obj) { 10385 _this.containers.svg 10386 .querySelector("#" + obj.value) 10387 .classList.toggle("mapsvg-hidden", !g.visible); 10388 }); 10389 }); 10390 } 10391 getGroupSelectOptions() { 10392 const _this = this; 10393 const optionGroups = []; 10394 const options = []; 10395 const options2 = []; 10396 $$A(_this.containers.svg) 10397 .find("g") 10398 .each(function (index) { 10399 const id = $$A(this)[0].getAttribute("id"); 10400 if (id) { 10401 const title = $$A(this)[0].getAttribute("title"); 10402 options.push({ label: title, value: id }); 10403 } 10404 }); 10405 optionGroups.push({ title: "SVG Layers / Groups", options: options }); 10406 $$A(_this.containers.svg) 10407 .find("path,ellipse,circle,polyline,polygon,rectangle,img,text") 10408 .each(function (index) { 10409 const id = $$A(this)[0].getAttribute("id"); 10410 if (id) { 10411 const title = $$A(this)[0].getAttribute("title"); 10412 options2.push({ label: title, value: id }); 10413 } 10414 }); 10415 optionGroups.push({ title: "Other SVG objects", options: options2 }); 10416 return optionGroups; 10417 } 10418 setLayersControl(options) { 10419 const _this = this; 10420 if (options) 10421 $$A.extend(true, this.options.layersControl, options); 10422 if (this.options.layersControl.on) { 10423 if (!this.containers.layersControl) { 10424 this.containers.layersControl = document.createElement("div"); 10425 this.containers.layersControl.classList.add("mapsvg-layers-control"); 10426 this.containers.layersControlLabel = document.createElement("div"); 10427 this.containers.layersControlLabel.classList.add("mapsvg-layers-label"); 10428 this.containers.layersControl.appendChild(this.containers.layersControlLabel); 10429 const layersControlWrap = document.createElement("div"); 10430 layersControlWrap.classList.add("mapsvg-layers-list-wrap"); 10431 this.containers.layersControl.appendChild(layersControlWrap); 10432 this.containers.layersControlListNano = document.createElement("div"); 10433 this.containers.layersControlListNano.classList.add("nano"); 10434 layersControlWrap.appendChild(this.containers.layersControlListNano); 10435 this.containers.layersControlList = document.createElement("div"); 10436 this.containers.layersControlList.classList.add("mapsvg-layers-list"); 10437 this.containers.layersControlList.classList.add("nano-content"); 10438 this.containers.layersControlListNano.appendChild(this.containers.layersControlList); 10439 this.containers.mapContainer.appendChild(this.containers.layersControl); 10440 } 10441 this.containers.layersControl.style.display = "block"; 10442 this.containers.layersControlLabel.innerHTML = this.options.layersControl.label; 10443 this.containers.layersControlLabel.style.display = "block"; 10444 this.containers.layersControlList.innerHTML = ""; 10445 while (this.containers.layersControlList.firstChild) { 10446 this.containers.layersControlList.removeChild(this.containers.layersControlList.firstChild); 10447 } 10448 this.containers.layersControl.classList.remove("mapsvg-top-left", "mapsvg-top-right", "mapsvg-bottom-left", "mapsvg-bottom-right"); 10449 this.containers.layersControl.classList.add("mapsvg-" + this.options.layersControl.position); 10450 if (this.options.menu.on && 10451 !this.options.menu.customContainer && 10452 this.options.layersControl.position.indexOf("left") !== -1) { 10453 this.containers.layersControl.style.left = this.options.menu.width; 10454 } 10455 this.containers.layersControl.style.maxHeight = this.options.layersControl.maxHeight; 10456 this.options.groups.forEach((g) => { 10457 const item = document.createElement("div"); 10458 item.classList.add("mapsvg-layers-item"); 10459 item.setAttribute("data-group-id", g.id); 10460 item.innerHTML = 10461 '<input type="checkbox" class="ios8-switch ios8-switch-sm" ' + 10462 (g.visible ? "checked" : "") + 10463 " /><label>" + 10464 g.title + 10465 "</label>"; 10466 this.containers.layersControlList.appendChild(item); 10467 }); 10468 $$A(this.containers.layersControlListNano).nanoScroller({ 10469 preventPageScrolling: true, 10470 iOSNativeScrolling: true, 10471 }); 10472 $$A(this.containers.layersControl).off(); 10473 $$A(this.containers.layersControl).on("click", ".mapsvg-layers-item", function () { 10474 const id = $$A(this).data("group-id"); 10475 const input = $$A(this).find("input"); 10476 input.prop("checked", !input.prop("checked")); 10477 _this.groups.forEach(function (g) { 10478 if (g.id === id) 10479 g.visible = !g.visible; 10480 }); 10481 _this.setGroups(); 10482 }); 10483 $$A(this.containers.layersControlLabel).off(); 10484 $$A(this.containers.layersControlLabel).on("click", () => { 10485 $$A(_this.containers.layersControl).toggleClass("closed"); 10486 }); 10487 $$A(this.containers.layersControl).toggleClass("closed", !this.options.layersControl.expanded); 10488 } 10489 else { 10490 if (this.containers.layersControl) { 10491 this.containers.layersControl.style.display = "none"; 10492 } 10493 } 10494 }
10495 loadDataObjects(params) { 10496 return this.objectsRepository.find(params); 10497 } 10498 loadDirectory() { 10499 if (!this.editMode && 10500 this.options.menu.source === "database" && 10501 this.objectsRepository.getLoaded().length === 0) { 10502 return; 10503 } 10504 if (this.options.menu.on) { 10505 this.controllers.directory.loadItemsToDirectory(); 10506 } 10507 this.setPagination(); 10508 } 10509 setPagination() { 10510 const _this = this; 10511 this.containers.pagerMap && $$A(this.containers.pagerMap).empty().remove(); 10512 this.containers.pagerDir && $$A(this.containers.pagerDir).empty().remove(); 10513 if (_this.options.database.pagination.on && 10514 _this.options.database.pagination.perpage !== 0) { 10515 this.containers.directory.classList.toggle("mapsvg-with-pagination", ["directory", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10516 this.containers.map.classList.toggle("mapsvg-with-pagination", ["map", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10517 if (_this.options.menu.on) { 10518 this.containers.pagerDir = _this.getPagination(); 10519 _this.controllers.directory.addPagination(this.containers.pagerDir); 10520 } 10521 this.containers.pagerMap = _this.getPagination(); 10522 this.containers.map.appendChild(this.containers.pagerMap); 10523 } 10524 } 10525 getPagination(callback) { 10526 const _this = this; 10527 const pager = $$A('<nav class="mapsvg-pagination"><ul class="pager"><!--<li class="mapsvg-first"><a href="#">First</a></li>--><li class="mapsvg-prev"><a href="#">← ' + 10528 _this.options.database.pagination.prev + 10529 " " + 10530 _this.options.database.pagination.perpage + 10531 '</a></li><li class="mapsvg-next"><a href="#">' + 10532 _this.options.database.pagination.next + 10533 " " + 10534 _this.options.database.pagination.perpage + 10535 ' →</a></li><!--<li class="mapsvg-last"><a href="#">Last</a></li>--></ul></nav>'); 10536 if (this.objectsRepository.onFirstPage() && this.objectsRepository.onLastPage()) { 10537 pager.hide(); 10538 } 10539 else { 10540 pager.find(".mapsvg-prev").removeClass("disabled"); 10541 pager.find(".mapsvg-first").removeClass("disabled"); 10542 pager.find(".mapsvg-last").removeClass("disabled"); 10543 pager.find(".mapsvg-next").removeClass("disabled"); 10544 this.objectsRepository.onLastPage() && 10545 pager.find(".mapsvg-next").addClass("disabled") && 10546 pager.find(".mapsvg-last").addClass("disabled"); 10547 this.objectsRepository.onFirstPage() && 10548 pager.find(".mapsvg-prev").addClass("disabled") && 10549 pager.find(".mapsvg-first").addClass("disabled"); 10550 } 10551 pager 10552 .on("click", ".mapsvg-next:not(.disabled)", (e) => { 10553 e.preventDefault(); 10554 if (this.objectsRepository.onLastPage()) 10555 return; 10556 const query = new Query({ page: this.objectsRepository.query.page + 1 }); 10557 this.objectsRepository.find(query).done(function () { 10558 callback && callback(); 10559 }); 10560 }) 10561 .on("click", ".mapsvg-prev:not(.disabled)", function (e) { 10562 e.preventDefault(); 10563 if (_this.objectsRepository.onFirstPage()) 10564 return; 10565 const query = new Query({ page: _this.objectsRepository.query.page - 1 }); 10566 _this.objectsRepository.find(query).done(function () { 10567 callback && callback(); 10568 }); 10569 }) 10570 .on("click", ".mapsvg-first:not(.disabled)", function (e) { 10571 e.preventDefault(); 10572 if (_this.objectsRepository.onFirstPage()) 10573 return; 10574 const query = new Query({ page: 1 }); 10575 _this.objectsRepository.find(query).done(function () { 10576 callback && callback(); 10577 }); 10578 }) 10579 .on("click", ".mapsvg-last:not(.disabled)", function (e) { 10580 e.preventDefault(); 10581 if (_this.objectsRepository.onLastPage()) 10582 return; 10583 const query = new Query({ lastpage: true }); 10584 _this.objectsRepository.find(query).done(function () { 10585 callback && callback(); 10586 }); 10587 }); 10588 return pager[0]; 10589 } 10590 deleteMarkers() { 10591 while (this.markers.length) { 10592 this.markerDelete(this.markers[0]); 10593 } 10594 }
10595 deleteClusters() { 10596 if (this.markersClusters) { 10597 this.markersClusters.forEach(function (markerCluster) { 10598 markerCluster.destroy(); 10599 }); 10600 this.markersClusters.clear(); 10601 } 10602 } 10603 addLocations() { 10604 const _this = this; 10605 this.firstDataLoad = this.firstDataLoad === undefined; 10606 let locationField = this.objectsRepository.getSchema().getFieldByType("location"); 10607 if (!locationField) { 10608 return; 10609 } 10610 locationField = locationField.name; 10611 if (locationField) { 10612 if (this.firstDataLoad) { 10613 this.setMarkerImagesDependency(); 10614 } 10615 _this.deleteMarkers(); 10616 _this.deleteClusters(); 10617 _this.clusters = {}; 10618 _this.clustersByZoom = []; 10619 if (this.objectsRepository.getLoaded().length > 0) { 10620 this.objectsRepository.getLoaded().forEach(function (object) { 10621 if (object[locationField]) { 10622 if (object[locationField].img && 10623 (object[locationField].geoPoint || object[locationField].svgPoint)) { 10624 new Marker({ 10625 location: object[locationField], 10626 object: object, 10627 mapsvg: _this, 10628 }); 10629 } 10630 } 10631 }); 10632 if (_this.options.clustering.on) { 10633 _this.startClusterizer(); 10634 } 10635 else { 10636 this.objectsRepository.getLoaded().forEach(function (object) { 10637 if (object.location && object.location.marker) { 10638 _this.markerAdd(object.location.marker); 10639 } 10640 }); 10641 _this.mayBeFitMarkers(); 10642 } 10643 } 10644 } 10645 } 10646 addClustersFromWorker(zoomLevel, clusters) { 10647 const _this = this; 10648 _this.clustersByZoom[zoomLevel] = []; 10649 for (const cell in clusters) { 10650 const markers = clusters[cell].markers.map(function (marker) { 10651 return _this.objectsRepository.objects.findById(marker.id).location.marker; 10652 }); 10653 _this.clustersByZoom[zoomLevel].push(new MarkerCluster({ 10654 markers: markers, 10655 svgPoint: new SVGPoint(clusters[cell].x, clusters[cell].y), 10656 cellX: clusters[cell].cellX, 10657 cellY: clusters[cell].cellY, 10658 }, _this)); 10659 } 10660 if (_this.zoomLevel === zoomLevel) { 10661 _this.clusterizeMarkers(); 10662 } 10663 } 10664 startClusterizer() { 10665 if (!this.objectsRepository || this.objectsRepository.getLoaded().length === 0) { 10666 return; 10667 } 10668 const locationField = this.objectsRepository.getSchema().getFieldByType("location"); 10669 if (!locationField) { 10670 return false; 10671 } 10672 if (!this.clusterizerWorker) { 10673 this.clusterizerWorker = new Worker(MapSVG.urls.root + "js/mapsvg/Core/clustering.js"); 10674 this.clusterizerWorker.onmessage = (evt) => { 10675 if (evt.data.clusters) { 10676 this.addClustersFromWorker(evt.data.zoomLevel, evt.data.clusters); 10677 } 10678 }; 10679 } 10680 const objectsData = []; 10681 this.objectsRepository 10682 .getLoaded() 10683 .filter((o) => { 10684 return o.location && o.location.marker; 10685 }) 10686 .forEach((o) => { 10687 objectsData.push({ 10688 id: o.id, 10689 x: o.location.marker.svgPoint.x, 10690 y: o.location.marker.svgPoint.y, 10691 }); 10692 }); 10693 this.clusterizerWorker.postMessage({ 10694 objects: objectsData, 10695 cellSize: 50, 10696 mapWidth: this.containers.map.clientWidth, 10697 zoomLevels: this.zoomLevels, 10698 zoomLevel: this.zoomLevel, 10699 zoomDelta: this.zoomDelta, 10700 svgViewBox: this.svgDefault.viewBox, 10701 }); 10702 this.events.on("zoom", () => { 10703 this.clusterizerWorker.postMessage({ 10704 message: "zoom", 10705 zoomLevel: this.zoomLevel, 10706 }); 10707 }); 10708 } 10709 clusterizeMarkers(skipFitMarkers) { 10710 $$A(this.layers.markers) 10711 .children() 10712 .each((i, obj) => { 10713 $$A(obj).detach(); 10714 }); 10715 this.markers.clear(); 10716 this.markersClusters.clear();
10717 this.clustersByZoom && 10718 this.clustersByZoom[this.zoomLevel] && 10719 this.clustersByZoom[this.zoomLevel].forEach((cluster) => { 10720 if (this.options.googleMaps.on && 10721 this.googleMaps.map && 10722 this.googleMaps.map.getZoom() >= 17) { 10723 this.markerAdd(cluster.markers[0]); 10724 } 10725 else { 10726 if (cluster.markers.length > 1) { 10727 this.markersClusterAdd(cluster); 10728 } 10729 else { 10730 this.markerAdd(cluster.markers[0]); 10731 } 10732 } 10733 }); 10734 if (this.editingMarker) { 10735 this.markerAdd(this.editingMarker); 10736 } 10737 if (!skipFitMarkers) { 10738 this.mayBeFitMarkers(); 10739 } 10740 if (this.options.labelsMarkers.on) { 10741 this.setLabelsMarkers(); 10742 } 10743 } 10744 getCssUrl() { 10745 return MapSVG.urls.root + "css/mapsvg.css"; 10746 } 10747 isGeo() { 10748 return this.mapIsGeo; 10749 } 10750 functionFromString(string) { 10751 let func; 10752 let error; 10753 const fn = string.trim(); 10754 if (fn.indexOf("{") == -1 || fn.indexOf("function") !== 0 || fn.indexOf("(") == -1) { 10755 return new SyntaxError("MapSVG user function error: no function body."); 10756 } 10757 const fnBody = fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")); 10758 const params = fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")); 10759 try { 10760 func = new Function(params, fnBody); 10761 } 10762 catch (err) { 10763 error = err; 10764 } 10765 if (!error) 10766 return func; 10767 else 10768 return error; 10769 } 10770 getOptions(forTemplate, forWeb) { 10771 const options = $$A.extend(true, {}, this.options); 10772 function clearEmpties(o) { 10773 for (const k in o) { 10774 if (!o[k] || typeof o[k] !== "object") { 10775 continue; 10776 } 10777 clearEmpties(o[k]); 10778 if (Object.keys(o[k]).length === 0) { 10779 delete o[k]; 10780 } 10781 } 10782 } 10783 clearEmpties(options.regions); 10784 $$A.extend(true, options, this.optionsDelta); 10785 options.viewBox = this._viewBox.toArray(); 10786 options.filtersSchema = this.filtersSchema.getFieldsAsArray(); 10787 if (options.filtersSchema.length > 0) { 10788 options.filtersSchema.forEach((field) => { 10789 if (field.type === "distance") { 10790 field.value = ""; 10791 } 10792 }); 10793 } 10794 delete options.markers; 10795 if (forTemplate) { 10796 options.svgFilename = options.source.split("/").pop(); 10797 options.svgFiles = MapSVG.svgFiles; 10798 } 10799 if (forWeb) 10800 $$A.each(options, (key, val) => { 10801 if (JSON.stringify(val) == JSON.stringify(this.defaults[key])) 10802 delete options[key]; 10803 }); 10804 delete options.backend; 10805 return options; 10806 } 10807 restoreDeltaOptions() { 10808 this.update(this.optionsDelta); 10809 this.optionsDelta = {}; 10810 } 10811 setEvents(functions) { 10812 let compiledFunction; 10813 for (const eventName in functions) { 10814 if (typeof functions[eventName] === "string") { 10815 compiledFunction = 10816 functions[eventName] != "" 10817 ? this.functionFromString(functions[eventName]) 10818 : null; 10819 if (!compiledFunction || 10820 compiledFunction.error || 10821 compiledFunction instanceof TypeError || 10822 compiledFunction instanceof SyntaxError) { 10823 continue; 10824 } 10825 } 10826 else if (typeof functions[eventName] === "function") { 10827 compiledFunction = functions[eventName]; 10828 } 10829 this.events.off(eventName); 10830 this.events.on(eventName, compiledFunction); 10831 if (eventName.indexOf("directory") !== -1) { 10832 const event = eventName.split(".")[0]; 10833 if (this.controllers && this.controllers.directory) { 10834 this.controllers.directory.events.off(event); 10835 this.controllers.directory.events.on(event, compiledFunction); 10836 } 10837 } 10838 } 10839 $$A.extend(true, this.options.events, functions); 10840 }
10841 setActions(options) { 10842 $$A.extend(true, this.options.actions, options); 10843 } 10844 setDetailsView(options) { 10845 options = options || this.options.detailsView || {}; 10846 $$A.extend(true, this.options.detailsView, options); 10847 if (this.options.detailsView.location === "top" && this.options.menu.position === "left") { 10848 this.options.detailsView.location = "leftSidebar"; 10849 } 10850 else if (this.options.detailsView.location === "top" && 10851 this.options.menu.position === "right") { 10852 this.options.detailsView.location = "rightSidebar"; 10853 } 10854 if (this.options.detailsView.location === "near" || 10855 this.options.detailsView.location === "mapContainer") { 10856 this.options.detailsView.location = "map"; 10857 } 10858 if (!this.containers.detailsView) { 10859 this.containers.detailsView = $$A('<div class="mapsvg-details-container"></div>')[0]; 10860 } 10861 $$A(this.containers.detailsView).toggleClass("mapsvg-details-container-relative", !(MapSVG.isPhone && this.options.detailsView.mobileFullscreen) && 10862 !this.shouldBeScrollable(this.options.detailsView.location)); 10863 if (this.options.detailsView.location === "custom") { 10864 $$A("#" + this.options.detailsView.containerId).append($$A(this.containers.detailsView)); 10865 } 10866 else { 10867 if (MapSVG.isPhone && this.options.detailsView.mobileFullscreen) { 10868 $$A("body").append($$A(this.containers.detailsView)); 10869 $$A(this.containers.detailsView).addClass("mapsvg-container-fullscreen"); 10870 } 10871 else { 10872 this.containers[this.options.detailsView.location].append(this.containers.detailsView); 10873 } 10874 if (this.options.detailsView.margin) { 10875 $$A(this.containers.detailsView).css("margin", this.options.detailsView.margin); 10876 } 10877 $$A(this.containers.detailsView).css("width", this.options.detailsView.width); 10878 } 10879 } 10880 setMobileView(options) { 10881 $$A.extend(true, this.options.mobileView, options); 10882 } 10883 attachDataToRegions(object) { 10884 this.regions.forEach(function (region) { 10885 region.objects = []; 10886 }); 10887 this.objectsRepository.getLoaded().forEach((obj, index) => { 10888 const regions = obj.getRegionsForTable(this.regionsRepository.schema.name); 10889 if (regions && regions.length) { 10890 regions.forEach((region) => { 10891 const r = this.getRegion(region.id); 10892 if (r) 10893 r.objects.push(obj); 10894 }); 10895 } 10896 }); 10897 } 10898 setTemplates(templates) { 10899 this.templates = this.templates || {}; 10900 for (let name in templates) { 10901 if (name != undefined) { 10902 this.options.templates[name] = templates[name]; 10903 let t = this.options.templates[name]; 10904 if (name == "directoryItem" || name == "directoryCategoryItem") { 10905 const dirItemTemplate = this.options.templates.directoryItem; 10906 t = 10907 '{{#each items}}<div id="mapsvg-directory-item-{{id}}" class="mapsvg-directory-item" data-object-id="{{id}}">' + 10908 dirItemTemplate + 10909 "</div>{{/each}}"; 10910 if (this.options.menu.categories && 10911 this.options.menu.categories.on && 10912 this.options.menu.categories.groupBy) { 10913 const t2 = this.options.templates["directoryCategoryItem"]; 10914 t = 10915 '{{#each items}}{{#with category}}<div id="mapsvg-category-item-{{value}}" class="mapsvg-category-item" data-category-value="{{value}}">' + 10916 t2 + 10917 '</div><div class="mapsvg-category-block" data-category-id="{{value}}">{{/with}}' + 10918 t + 10919 "</div>{{/each}}"; 10920 } 10921 name = "directory"; 10922 } 10923 try { 10924 this.options.templates[name] = t; 10925 this.templates[name] = Handlebars.compile(t, { strict: false }); 10926 } 10927 catch (err) { 10928 console.error(err); 10929 this.templates[name] = Handlebars.compile("", { strict: false }); 10930 } 10931 if (this.editMode && 10932 (name == "directory" || name == "directoryCategoryItem") && 10933 this.controllers && 10934 this.controllers.directory) { 10935 this.controllers.directory.templates.main = this.templates[name]; 10936 this.loadDirectory(); 10937 } 10938 } 10939 } 10940 } 10941 update(options) { 10942 for (const key in options) { 10943 if (key == "regions") { 10944 for (const id in options.regions) { 10945 const region = this.getRegion(id); 10946 region && region.update(options.regions[id]); 10947 if (options.regions[id].disabled != undefined) { 10948 this.deselectRegion(region); 10949 this.options.regions[id] = this.options.regions[id] || {}; 10950 this.options.regions[id].disabled = region.disabled; 10951 } 10952 } 10953 } 10954 else { 10955 const setter = "set" + MapSVG.ucfirst(key); 10956 if (typeof this[setter] == "function") 10957 this[setter](options[key]); 10958 else { 10959 this.options[key] = options[key]; 10960 } 10961 } 10962 } 10963 } 10964 getDirtyFields() { 10965 return this.getData(); 10966 } 10967 clearDirtyFields() { 10968 this.dirtyFields = []; 10969 } 10970 setTitle(title) { 10971 title && (this.options.title = title); 10972 } 10973 setExtension(extension) { 10974 if (extension) { 10975 this.options.extension = extension; 10976 } 10977 else { 10978 delete this.options.extension; 10979 } 10980 } 10981 setDisableLinks(on) { 10982 on = MapSVG.parseBoolean(on); 10983 if (on) { 10984 $$A(this.containers.map).on("click.a.mapsvg", "a", function (e) { 10985 e.preventDefault(); 10986 }); 10987 } 10988 else { 10989 $$A(this.containers.map).off("click.a.mapsvg"); 10990 } 10991 this.disableLinks = on; 10992 }
10993 setLoadingText(val) { 10994 this.options.loadingText = val; 10995 } 10996 setLockAspectRatio(onoff) { 10997 this.options.lockAspectRatio = MapSVG.parseBoolean(onoff); 10998 } 10999 setMarkerEditHandler(handler) { 11000 this.markerEditHandler = handler; 11001 } 11002 setChoroplethSourceField(field) { 11003 this.options.choropleth.sourceField = field; 11004 this.redrawChoropleth(); 11005 } 11006 setRegionEditHandler(handler) { 11007 this.regionEditHandler = handler; 11008 } 11009 setDisableAll(on) { 11010 on = MapSVG.parseBoolean(on); 11011 $$A.extend(true, this.options, { disableAll: on }); 11012 $$A(this.containers.map).toggleClass("mapsvg-disabled-regions", on); 11013 } 11014 setRegionStatuses(_statuses) { 11015 this.options.regionStatuses = {}; 11016 const colors = {}; 11017 _statuses.forEach((statusOptions) => { 11018 this.options.regionStatuses[statusOptions.value] = statusOptions; 11019 colors[statusOptions.value] = statusOptions.color.length 11020 ? statusOptions.color 11021 : undefined; 11022 }); 11023 this.setColors({ status: colors }); 11024 } 11025 setColorsIgnore(val) { 11026 this.options.colorsIgnore = MapSVG.parseBoolean(val); 11027 this.regionsRedrawColors(); 11028 } 11029 setColors(colors) { 11030 for (const i in colors) { 11031 if (i === "status") { 11032 for (const s in colors[i]) { 11033 MapSVG.fixColorHash(colors[i][s]); 11034 } 11035 } 11036 else { 11037 if (typeof colors[i] == "string") { 11038 MapSVG.fixColorHash(colors[i]); 11039 } 11040 } 11041 } 11042 $$A.extend(true, this.options, { colors: colors }); 11043 if (colors && colors.status) 11044 this.options.colors.status = colors.status; 11045 if (this.options.colors.markers) { 11046 for (const z in this.options.colors.markers) { 11047 for (const x in this.options.colors.markers[z]) { 11048 this.options.colors.markers[z][x] = parseInt(this.options.colors.markers[z][x]); 11049 } 11050 } 11051 } 11052 if (this.options.colors.background) 11053 $$A(this.containers.map).css({ background: this.options.colors.background }); 11054 if (this.options.colors.hover) { 11055 this.options.colors.hover = !isNaN(this.options.colors.hover) 11056 ? parseInt(this.options.colors.hover + "") 11057 : this.options.colors.hover; 11058 } 11059 if (this.options.colors.selected) { 11060 this.options.colors.selected = !isNaN(this.options.colors.selected) 11061 ? parseInt(this.options.colors.selected + "") 11062 : this.options.colors.selected; 11063 } 11064 $$A(this.containers.leftSidebar).css({ 11065 "background-color": this.options.colors.leftSidebar, 11066 }); 11067 $$A(this.containers.rightSidebar).css({ 11068 "background-color": this.options.colors.rightSidebar, 11069 }); 11070 $$A(this.containers.header).css({ "background-color": this.options.colors.header }); 11071 $$A(this.containers.footer).css({ "background-color": this.options.colors.footer }); 11072 if ($$A(this.containers.detailsView) && this.options.colors.detailsView !== undefined) { 11073 $$A(this.containers.detailsView).css({ 11074 "background-color": this.options.colors.detailsView, 11075 }); 11076 } 11077 if ($$A(this.containers.directory) && this.options.colors.directory !== undefined) { 11078 $$A(this.containers.directory).css({ 11079 "background-color": this.options.colors.directory, 11080 }); 11081 } 11082 if ($$A(this.containers.filtersModal) && this.options.colors.modalFilters !== undefined) { 11083 $$A(this.containers.filtersModal).css({ 11084 "background-color": this.options.colors.modalFilters, 11085 }); 11086 } 11087 if ($$A(this.containers.filters) && this.options.colors.directorySearch) { 11088 $$A(this.containers.filters).css({ 11089 "background-color": this.options.colors.directorySearch, 11090 }); 11091 } 11092 else if ($$A(this.containers.filters)) { 11093 $$A(this.containers.filters).css({ 11094 "background-color": "", 11095 }); 11096 }
11097 if (!this.containers.clustersCss) { 11098 this.containers.clustersCss = ($$A("<style></style>").appendTo("body")[0]); 11099 } 11100 let css = ""; 11101 if (this.options.colors.clusters) { 11102 css += "background-color: " + this.options.colors.clusters + ";"; 11103 } 11104 if (this.options.colors.clustersBorders) { 11105 css += "border-color: " + this.options.colors.clustersBorders + ";"; 11106 } 11107 if (this.options.colors.clustersText) { 11108 css += "color: " + this.options.colors.clustersText + ";"; 11109 } 11110 $$A(this.containers.clustersCss).html(".mapsvg-marker-cluster {" + css + "}"); 11111 if (!this.containers.clustersHoverCss) { 11112 this.containers.clustersHoverCss = ($$A("<style></style>").appendTo("body")[0]); 11113 } 11114 let cssHover = ""; 11115 if (this.options.colors.clustersHover) { 11116 cssHover += "background-color: " + this.options.colors.clustersHover + ";"; 11117 } 11118 if (this.options.colors.clustersHoverBorders) { 11119 cssHover += "border-color: " + this.options.colors.clustersHoverBorders + ";"; 11120 } 11121 if (this.options.colors.clustersHoverText) { 11122 cssHover += "color: " + this.options.colors.clustersHoverText + ";"; 11123 } 11124 $$A(this.containers.clustersHoverCss).html(".mapsvg-marker-cluster:hover {" + cssHover + "}"); 11125 if (!this.containers.markersCss) { 11126 this.containers.markersCss = $$A("<style></style>").appendTo("head")[0]; 11127 } 11128 const markerCssText = ".mapsvg-with-marker-active .mapsvg-marker {\n" + 11129 " opacity: " + 11130 this.options.colors.markers.inactive.opacity / 100 + 11131 ";\n" + 11132 " -webkit-filter: grayscale(" + 11133 (100 - this.options.colors.markers.inactive.saturation) + 11134 "%);\n" + 11135 " filter: grayscale(" + 11136 (100 - this.options.colors.markers.inactive.saturation) + 11137 "%);\n" + 11138 "}\n" + 11139 ".mapsvg-with-marker-active .mapsvg-marker-active {\n" + 11140 " opacity: " + 11141 this.options.colors.markers.active.opacity / 100 + 11142 ";\n" + 11143 " -webkit-filter: grayscale(" + 11144 (100 - this.options.colors.markers.active.saturation) + 11145 "%);\n" + 11146 " filter: grayscale(" + 11147 (100 - this.options.colors.markers.active.saturation) + 11148 "%);\n" + 11149 "}\n" + 11150 ".mapsvg-with-marker-hover .mapsvg-marker {\n" + 11151 " opacity: " + 11152 this.options.colors.markers.unhovered.opacity / 100 + 11153 ";\n" + 11154 " -webkit-filter: grayscale(" + 11155 (100 - this.options.colors.markers.unhovered.saturation) + 11156 "%);\n" + 11157 " filter: grayscale(" + 11158 (100 - this.options.colors.markers.unhovered.saturation) + 11159 "%);\n" + 11160 "}\n" + 11161 ".mapsvg-with-marker-hover .mapsvg-marker-hover {\n" + 11162 " opacity: " + 11163 this.options.colors.markers.hovered.opacity / 100 + 11164 ";\n" + 11165 " -webkit-filter: grayscale(" + 11166 (100 - this.options.colors.markers.hovered.saturation) + 11167 "%);\n" + 11168 " filter: grayscale(" + 11169 (100 - this.options.colors.markers.hovered.saturation) + 11170 "%);\n" + 11171 "}\n"; 11172 $$A(this.containers.markersCss).html(markerCssText); 11173 $$A.each(this.options.colors, (key, color) => { 11174 if (color === null || color == "") 11175 delete this.options.colors[key]; 11176 }); 11177 this.regionsRedrawColors(); 11178 } 11179 setTooltips(options) { 11180 if (options.on !== undefined) 11181 options.on = MapSVG.parseBoolean(options.on); 11182 $$A.extend(true, this.options, { tooltips: options }); 11183 if (!this.containers.tooltip) { 11184 this.containers.tooltip = $$A("<div />").addClass("mapsvg-tooltip")[0]; 11185 $$A(this.containers.map).append(this.containers.tooltip); 11186 this.controllers.tooltip = new Tooltip({ 11187 mapsvg: this, 11188 container: this.containers.tooltip, 11189 position: this.options.tooltips.position, 11190 maxWidth: this.options.tooltips.maxWidth, 11191 minWidth: this.options.tooltips.minWidth, 11192 }); 11193 this.controllers.tooltip._init(); 11194 } 11195 if (typeof this.options.tooltips.position !== "undefined") { 11196 this.controllers.tooltip.setPosition(this.options.tooltips.position); 11197 } 11198 if (typeof this.options.tooltips.maxWidth !== "undefined" || 11199 typeof this.options.tooltips.minWidth !== "undefined") { 11200 this.controllers.tooltip.setSize(this.options.tooltips.maxWidth, this.options.tooltips.minWidth); 11201 } 11202 } 11203 setPopovers(options) { 11204 if (options.on !== undefined) 11205 options.on = MapSVG.parseBoolean(options.on); 11206 $$A.extend(this.options.popovers, options); 11207 if (!this.containers.popover) { 11208 this.containers.popover = $$A("<div />").addClass("mapsvg-popover")[0]; 11209 this.layers.popovers.append(this.containers.popover); 11210 } 11211 $$A(this.containers.popover).css({ 11212 width: this.options.popovers.width + (this.options.popovers.width == "auto" ? "" : "px"), 11213 "max-width": this.options.popovers.maxWidth + "%", 11214 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 100 + 11215 "px", 11216 }); 11217 if (this.options.popovers.mobileFullscreen && MapSVG.
11217isPhone) { 11218 $$A("body").toggleClass("mapsvg-fullscreen-popovers", true); 11219 $$A(this.containers.popover).appendTo("body"); 11220 } 11221 } 11222 setRegionPrefix(prefix) { 11223 this.options.regionPrefix = prefix; 11224 } 11225 setInitialViewBox(v) { 11226 if (typeof v == "string") 11227 v = v 11228 .trim() 11229 .split(" ") 11230 .map(function (v) { 11231 return parseFloat(v); 11232 }); 11233 this._viewBox.update(new ViewBox(v)); 11234 if (this.options.googleMaps.on) { 11235 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 11236 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 11237 } 11238 this.zoomLevel = 0; 11239 this.setZoomLevels(); 11240 } 11241 setViewBoxOnStart() { 11242 this.viewBoxFull = this.svgDefault.viewBox; 11243 this.viewBoxFake = this.viewBox; 11244 this.whRatioFull = this.viewBoxFull.width / this.viewBox.width; 11245 this.containers.svg.setAttribute("viewBox", this.viewBoxFull.toString()); 11246 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11247 this.iosDownscaleFactor = this.svgDefault.viewBox.width > 9999 ? 100 : 10; 11248 this.containers.svg.style.width = 11249 (this.svgDefault.viewBox.width / this.iosDownscaleFactor).toString() + "px"; 11250 } 11251 else { 11252 this.containers.svg.style.width = this.svgDefault.viewBox.width + "px"; 11253 } 11254 this.vbStart = true; 11255 } 11256 setViewBox(viewBox, adjustGoogleMap = true) { 11257 let initial = false; 11258 if (typeof viewBox === "undefined" || (viewBox.width === 0 && viewBox.height === 0)) {
11259 viewBox = this.svgDefault.viewBox; 11260 initial = true; 11261 } 11262 const isZooming = viewBox.width != this.viewBox.width || viewBox.height != this.viewBox.height; 11263 this.viewBox.update(viewBox); 11264 this.whRatio = this.viewBox.width / this.viewBox.height; 11265 !this.vbStart && this.setViewBoxOnStart(); 11266 if (initial) { 11267 if (this._viewBox.width === 0 && this._viewBox.height === 0) { 11268 this._viewBox.update(this.viewBox); 11269 } 11270 this._scale = 1; 11271 } 11272 this.scale = this.getScale(); 11273 this.superScale = (this.whRatioFull * this.svgDefault.viewBox.width) / this.viewBox.width; 11274 const w = this.svgDefault.viewBox.width / this.containers.map.clientWidth; 11275 this.superScale = this.superScale / w; 11276 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11277 this.superScale *= this.iosDownscaleFactor; 11278 } 11279 this.scroll.tx = Math.round((this.svgDefault.viewBox.x - this.viewBox.x) * this.scale); 11280 this.scroll.ty = Math.round((this.svgDefault.viewBox.y - this.viewBox.y) * this.scale); 11281 if (this.googleMaps.map && adjustGoogleMap !== false) { 11282 const googlePrevZoom = this.googleMaps.map.getZoom(); 11283 this.googleMaps.map.setZoom(this.getZoomForGoogle()); 11284 if (googlePrevZoom !== this.googleMaps.map.getZoom()) { 11285 this.googleMaps.map.setCenter(this.getCenterGeoPoint()); 11286 } 11287 } 11288 else { 11289 this.containers.scrollpane.style.transform = 11290 "translate(" + this.scroll.tx + "px," + this.scroll.ty + "px)"; 11291 this.containers.svg.style.transform = "scale(" + this.superScale + ")"; 11292 this.syncZoomLevelWithGoogle(); 11293 } 11294 this.movingItemsAdjustScreenPosition(); 11295 if (isZooming) { 11296 this.mapAdjustStrokes(); 11297 this.toggleSvgLayerOnZoom(); 11298 if (this.options.clustering.on) { 11299 this.throttle(this.clusterizeOnZoom, 400, this); 11300 } 11301 else { 11302 this.events.trigger("zoom"); 11303 } 11304 } 11305 return true; 11306 } 11307 syncZoomLevelWithGoogle() { 11308 if (this.googleMaps.map && 11309 this.googleMaps.map.getZoom() !== this.getZoomForGoogle() && 11310 typeof this.zoomDelta !== "undefined") { 11311 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11312 } 11313 } 11314 getCenterGeoPoint() { 11315 return this.converter.convertSVGToGeo(this.getCenterSvgPoint()); 11316 } 11317 getCenterSvgPoint() { 11318 return new SVGPoint(this.viewBox.x + this.viewBox.width / 2, this.viewBox.y + this.viewBox.height / 2); 11319 } 11320 getZoomForGoogle() { 11321 return this.zoomLevel + this.zoomDelta; 11322 } 11323 getZoomRange() { 11324 const range = { min: 0, max: 0 }; 11325 if (this.options.googleMaps.on) { 11326 range.min = Math.max(0, this.options.zoom.limit[0] + this.zoomDelta) - this.zoomDelta; 11327 range.max = Math.min(22, this.options.zoom.limit[1] + this.zoomDelta) - this.zoomDelta; 11328 } 11329 else { 11330 range.min = this.options.zoom.limit[0]; 11331 range.max = this.options.zoom.limit[1]; 11332 } 11333 return range; 11334 } 11335 enableMovingElementsAnimation() { 11336 $$A(this.containers.map).removeClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11337 } 11338 disableMovingElementsAnimation() { 11339 $$A(this.containers.map).addClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11340 } 11341 clusterizeOnZoom() { 11342 if (this.options.googleMaps.on && this.googleMaps.map && this.zoomDelta) { 11343 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11344 } 11345 this.events.trigger("zoom"); 11346 this.clusterizeMarkers(true); 11347 } 11348 throttle(method, delay, scope, params) { 11349 clearTimeout(method._tId); 11350 method._tId = setTimeout(function () { 11351 method.apply(scope, params); 11352 }, delay); 11353 }
11354 setViewBoxByGoogleMapBounds() { 11355 const googleMapBounds = this.googleMaps.map.getBounds(); 11356 if (!googleMapBounds) 11357 return; 11358 const googleMapBoundsJSON = googleMapBounds.toJSON(); 11359 if (googleMapBoundsJSON.west == -180 && googleMapBoundsJSON.east == 180) { 11360 const center = this.googleMaps.map.getCenter().toJSON(); 11361 } 11362 const ne = new GeoPoint(googleMapBounds.getNorthEast().lat(), googleMapBounds.getNorthEast().lng()); 11363 const sw = new GeoPoint(googleMapBounds.getSouthWest().lat(), googleMapBounds.getSouthWest().lng()); 11364 const xyNE = this.converter.convertGeoToSVG(ne); 11365 const xySW = this.converter.convertGeoToSVG(sw); 11366 if (xyNE.x < xySW.y) { 11367 const mapPointsWidth = (this.svgDefault.viewBox.width / this.mapLonDelta) * 360; 11368 xySW.x = -(mapPointsWidth - xySW.y); 11369 } 11370 const width = xyNE.x - xySW.x; 11371 const height = xySW.y - xyNE.y; 11372 const viewBox = new ViewBox(xySW.x, xyNE.y, width, height); 11373 this.setViewBox(viewBox); 11374 } 11375 redraw() { 11376 if (MapSVG.browser.ie) { 11377 $$A(this.containers.svg).css({ height: this.svgDefault.viewBox.height }); 11378 } 11379 if (this.options.googleMaps.on && this.googleMaps.map) { 11380 google.maps.event.trigger(this.googleMaps.map, "resize"); 11381 } 11382 else { 11383 this.setViewBox(this.viewBox); 11384 } 11385 $$A(this.containers.popover) && 11386 $$A(this.containers.popover).css({ 11387 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 11388 100 + 11389 "px", 11390 }); 11391 if (this.controllers && this.controllers.directory) { 11392 this.controllers.directory.updateTopShift(); 11393 this.controllers.directory.updateScroll(); 11394 } 11395 this.movingItemsAdjustScreenPosition(); 11396 this.mapAdjustStrokes(); 11397 } 11398 setSize(width, height, responsive) { 11399 this.options.width = width; 11400 this.options.height = height; 11401 this.options.responsive = 11402 responsive != null && responsive != undefined 11403 ? MapSVG.parseBoolean(responsive) 11404 : this.options.responsive; 11405 if (!this.options.width && !this.options.height) { 11406 this.options.width = this.svgDefault.width; 11407 this.options.height = this.svgDefault.height; 11408 } 11409 else if (!this.options.width && this.options.height) { 11410 this.options.width = 11411 (this.options.height * this.svgDefault.width) / this.svgDefault.height; 11412 } 11413 else if (this.options.width && !this.options.height) { 11414 this.options.height = 11415 (this.options.width * this.svgDefault.height) / this.svgDefault.width; 11416 } 11417 this.whRatio = this.options.width / this.options.height; 11418 this.scale = this.getScale(); 11419 this.setResponsive(responsive); 11420 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 11421 this.redrawBubbles(); 11422 } 11423 this.movingItemsAdjustScreenPosition(); 11424 } 11425 setResponsive(on) { 11426 on = on != undefined ? MapSVG.parseBoolean(on) : this.options.responsive; 11427 $$A(this.containers.map).css({ 11428 width: "100%", 11429 height: "0", 11430 "padding-bottom": (this.viewBox.height * 100) / this.viewBox.width + "%", 11431 }); 11432 if (on) { 11433 $$A(this.containers.wrap).css({ 11434 width: "100%", 11435 height: "auto", 11436 }); 11437 } 11438 else { 11439 $$A(this.containers.wrap).css({ 11440 width: this.options.width + "px", 11441 height: this.options.height + "px", 11442 }); 11443 } 11444 $$A.extend(true, this.options, { responsive: on }); 11445 if (!this.resizeSensor) { 11446 this.resizeSensor = new ResizeSensor(this.containers.map, () => { 11447 this.redraw(); 11448 }); 11449 } 11450 this.redraw(); 11451 } 11452 setScroll(options, skipEvents) { 11453 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11454 options.limit != undefined && (options.limit = MapSVG.parseBoolean(options.limit)); 11455 $$A.extend(true, this.options, { scroll: options }); 11456 !skipEvents && this.setEventHandlers(); 11457 } 11458 setZoom(options) { 11459 options = options || {}; 11460 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11461 options.fingers != undefined && (options.fingers = MapSVG.parseBoolean(options.fingers)); 11462 options.mousewheel != undefined && 11463 (options.mousewheel = MapSVG.parseBoolean(options.mousewheel)); 11464 options.delta = 2; 11465 if (options.limit) { 11466 if (typeof options.limit == "string") 11467 options.limit = options.limit.split(";"); 11468 options.limit = [parseInt(options.limit[0]), parseInt(options.limit[1])]; 11469 } 11470 if (!this.zoomLevels) { 11471 this.setZoomLevels(); 11472 } 11473 $$A.extend(true, this.options, { zoom: options }); 11474 $$A(this.containers.map).off("wheel.mapsvg"); 11475 if (this.options.zoom.mousewheel) { 11476 if (MapSVG.browser.firefox) { 11477 this.firefoxScroll = { insideIframe: false, scrollX: 0, scrollY: 0 }; 11478 $$A(this.containers.map) 11479 .on("mouseenter", () => { 11480 this.firefoxScroll.insideIframe = true; 11481 this.firefoxScroll.scrollX = window.scrollX; 11482 this.firefoxScroll.scrollY = window.scrollY; 11483 }) 11484 .on("mouseleave", () => { 11485 this.firefoxScroll.insideIframe = false;
11486 }); 11487 $$A(document).scroll(() => { 11488 if (this.firefoxScroll.insideIframe) 11489 window.scrollTo(this.firefoxScroll.scrollX, this.firefoxScroll.scrollY); 11490 }); 11491 } 11492 $$A(this.containers.map).on("wheel.mapsvg", (event) => { 11493 this.throttle(this.mouseWheelZoom, 500, this, [event]); 11494 return; 11495 }); 11496 } 11497 this.canZoom = true; 11498 } 11499 mouseWheelZoom(event) { 11500 if ($$A(event.target).hasClass("mapsvg-popover") || 11501 $$A(event.target).closest(".mapsvg-popover").length || 11502 $$A(event.target).hasClass("mapsvg-details-container") || 11503 $$A(event.target).closest(".mapsvg-details-container").length) { 11504 return; 11505 } 11506 event.preventDefault(); 11507 const d = Math.sign(-event.originalEvent.deltaY); 11508 const center = this.getSvgPointAtClick(event.originalEvent); 11509 d > 0 ? this.zoomIn(center) : this.zoomOut(center); 11510 } 11511 setControls(options) { 11512 options = options || {}; 11513 $$A.extend(true, this.options, { controls: options }); 11514 this.options.controls.zoom = MapSVG.parseBoolean(this.options.controls.zoom); 11515 this.options.controls.zoomReset = MapSVG.parseBoolean(this.options.controls.zoomReset); 11516 this.options.controls.userLocation = MapSVG.parseBoolean(this.options.controls.userLocation); 11517 this.options.controls.previousMap = MapSVG.parseBoolean(this.options.controls.previousMap); 11518 const loc = this.options.controls.location || "right"; 11519 if (!this.containers.controls) { 11520 const buttons = $$A("<div />").addClass("mapsvg-buttons"); 11521 const zoomGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11522 const zoomIn = $$A("<div />").addClass("mapsvg-btn-map mapsvg-in"); 11523 zoomIn.on("touchend click", (e) => { 11524 if (e.cancelable) { 11525 e.preventDefault(); 11526 } 11527 e.stopPropagation(); 11528 this.zoomIn(); 11529 }); 11530 const zoomOut = $$A("<div />").addClass("mapsvg-btn-map mapsvg-out"); 11531 zoomOut.on("touchend click", (e) => { 11532 if (e.cancelable) { 11533 e.preventDefault(); 11534 } 11535 e.stopPropagation(); 11536 this.zoomOut(); 11537 }); 11538 zoomGroup.append(zoomIn).append(zoomOut); 11539 const location = $$A("<div />").addClass("mapsvg-btn-map mapsvg-btn-location"); 11540 location.on("touchend click", (e) => { 11541 if (e.cancelable) { 11542 e.preventDefault(); 11543 } 11544 e.stopPropagation(); 11545 this.showUserLocation((location) => { 11546 if (this.options.scroll.on) { 11547 this.centerOn(location.marker); 11548 } 11549 }); 11550 }); 11551 const userLocationIcon = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 447.342 447.342" style="enable-background:new 0 0 447.342 447.342;" xml:space="preserve"><path d="M443.537,3.805c-3.84-3.84-9.686-4.893-14.625-2.613L7.553,195.239c-4.827,2.215-7.807,7.153-7.535,12.459 c0.254,5.305,3.727,9.908,8.762,11.63l129.476,44.289c21.349,7.314,38.125,24.089,45.438,45.438l44.321,129.509 c1.72,5.018,6.325,8.491,11.63,8.762c5.306,0.271,10.244-2.725,12.458-7.535L446.15,18.429 C448.428,13.491,447.377,7.644,443.537,3.805z"/></svg>'; 11552 location.html(userLocationIcon); 11553 const locationGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11554 locationGroup.append(location); 11555 const zoomResetIcon = '<svg height="14px" version="1.1" viewBox="0 0 14 14" width="14px" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="none" fill-rule="evenodd" id="Page-1" stroke="none" stroke-width="1"><g fill="#000000" transform="translate(-215.000000, -257.000000)"><g id="fullscreen" transform="translate(215.000000, 257.000000)"><path d="M2,9 L0,9 L0,14 L5,14 L5,12 L2,12 L2,9 L2,9 Z M0,5 L2,5 L2,2 L5,2 L5,0 L0,0 L0,5 L0,5 Z M12,12 L9,12 L9,14 L14,14 L14,9 L12,9 L12,12 L12,12 Z M9,0 L9,2 L12,2 L12,5 L14,5 L14,0 L9,0 L9,0 Z" /></g></g></g></svg>'; 11556 const zoomResetButton = $$A("<div />") 11557 .html(zoomResetIcon) 11558 .addClass("mapsvg-btn-map mapsvg-btn-zoom-reset"); 11559 zoomResetButton.on("touchend click", (e) => { 11560 if (e.cancelable) { 11561 e.preventDefault(); 11562 } 11563 e.stopPropagation(); 11564 this.viewBoxReset(true); 11565 }); 11566 const zoomResetGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11567 zoomResetGroup.append(zoomResetButton); 11568 const previousMapIcon = '<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="mapsvg-previous-map-icon" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" sodipodi:docname="undo.svg" inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata id="metadata19"><rdf:RDF><cc:Work rdf:about="">' + 11569 '<dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs id="defs17" /><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1920" inkscape:window-height="1017" id="namedview15" showgrid="false" inkscape:zoom="1.0103686" inkscape:cx="181.33521" inkscape:cy="211.70893" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="Capa_1" /> <g id="g6" transform="matrix(0.53219423,0,0,0.52547259,122.72749,106.63302)">' + 11570 '<g id="g4">
11570<path d="m 142.716,293.147 -94,-107.602 94,-107.602 c 7.596,-8.705 6.71,-21.924 -1.995,-29.527 -8.705,-7.596 -21.917,-6.703 -29.527,1.995 L 5.169,171.782 c -6.892,7.882 -6.892,19.65 0,27.532 l 106.026,121.372 c 4.143,4.729 9.94,7.157 15.771,7.157 4.883,0 9.786,-1.702 13.755,-5.169 8.706,-7.603 9.598,-20.822 1.995,-29.527 z" id="path2" inkscape:connector-curvature="0" /></g></g><g id="g12" transform="matrix(0.53219423,0,0,0.52547259,122.72749,106.63302)"><g id="g10"> <path d="M 359.93,164.619 H 20.926 C 9.368,164.619 0,173.986 0,185.545 c 0,11.558 9.368,20.926 20.926,20.926 H 359.93 c 60.776,0 110.218,49.441 110.218,110.211 0,60.77 -49.442,110.211 -110.218,110.211 H 48.828 c -11.558,0 -20.926,9.368 -20.926,20.926 0,11.558 9.368,20.926 20.926,20.926 H 359.93 C 443.774,468.745 512,400.526 512,316.682 512,232.838 443.781,164.619 359.93,164.619 Z" ' + 11571 'id="path8" inkscape:connector-curvature="0" /></g></g></svg>'; 11572 const previousMapButton = $$A("<div />") 11573 .html(previousMapIcon) 11574 .addClass("mapsvg-btn-map mapsvg-btn-previous-map"); 11575 previousMapButton.on("touchend click", (e) => { 11576 if (e.cancelable) { 11577 e.preventDefault(); 11578 } 11579 e.stopPropagation(); 11580 this.loadPreviousMap(); 11581 }); 11582 const previousMapGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11583 previousMapGroup.append(previousMapButton); 11584 this.containers.controls = buttons[0]; 11585 this.controls = { 11586 zoom: zoomGroup[0], 11587 userLocation: locationGroup[0], 11588 zoomReset: zoomResetGroup[0], 11589 previousMap: previousMapGroup[0], 11590 }; 11591 $$A(this.containers.map).append($$A(this.containers.controls)); 11592 } 11593 $$A(this.controls.zoom).toggle(this.options.controls.zoom); 11594 $$A(this.controls.userLocation).toggle(this.options.controls.userLocation); 11595 $$A(this.controls.zoomReset).toggle(this.options.controls.zoomReset); 11596 $$A(this.controls.previousMap).toggle(this.options.controls.previousMap && this.options.previousMapsIds.length > 0); 11597 $$A(this.containers.controls).removeClass("left"); 11598 $$A(this.containers.controls).removeClass("right"); 11599 (loc == "right" && $$A(this.containers.controls).addClass("right")) || 11600 (loc == "left" && $$A(this.containers.controls).addClass("left")); 11601 } 11602 setZoomLevels() { 11603 if (!this.zoomLevels) { 11604 this.zoomLevels = new ArrayIndexed("zoomLevel"); 11605 } 11606 else { 11607 this.zoomLevels.clear(); 11608 } 11609 for (let i = -20; i < 0; i++) { 11610 const _scale = 1 / Math.pow(this.options.zoom.delta, Math.abs(i)); 11611 this.zoomLevels.push({ 11612 zoomLevel: i, 11613 _scale: _scale,
11614 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 11615 }); 11616 } 11617 for (let z = 0; z <= 20; z++) { 11618 const _scale = Math.pow(this.options.zoom.delta, Math.abs(z)); 11619 this.zoomLevels.push({ 11620 zoomLevel: z, 11621 _scale: _scale, 11622 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 11623 }); 11624 } 11625 } 11626 setCursor(type) { 11627 type = type == "pointer" ? "pointer" : "default"; 11628 this.options.cursor = type; 11629 if (type == "pointer") 11630 $$A(this.containers.map).addClass("mapsvg-cursor-pointer"); 11631 else 11632 $$A(this.containers.map).removeClass("mapsvg-cursor-pointer"); 11633 } 11634 setMultiSelect(on, deselect) { 11635 this.options.multiSelect = MapSVG.parseBoolean(on); 11636 if (deselect !== false) 11637 this.deselectAllRegions(); 11638 } 11639 _new_setChoropleth(options) { 11640 options = options || this.options.choropleth; 11641 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11642 if (typeof options.coloring === "undefined" || 11643 typeof options.coloring.palette === "undefined" || 11644 typeof options.coloring.palette.colors === "undefined") { 11645 if (typeof options.sourceFieldSelect === "undefined" || 11646 typeof options.sourceFieldSelect.variants === "undefined") { 11647 $$A.extend(true, this.options.choropleth, options); 11648 } 11649 else { 11650 this.options.choropleth.sourceFieldSelect.variants = 11651 options.sourceFieldSelect.variants; 11652 } 11653 } 11654 else { 11655 const paletteColorsIndexes = Object.keys(options.coloring.palette.colors); 11656 if (paletteColorsIndexes.length > 1 || 11657 (paletteColorsIndexes[0] == "0" && 11658 Object.keys(options.coloring.palette.colors[0]).length > 1)) { 11659 this.options.choropleth.coloring.palette.colors = options.coloring.palette.colors; 11660 } 11661 else { 11662 const paletteColorIndex = Object.keys(options.coloring.palette.colors)[0]; 11663 $$A.extend(true, this.options.choropleth.coloring.palette.colors[paletteColorIndex], options.coloring.palette.colors[paletteColorIndex]); 11664 } 11665 } 11666 this.updateChoroplethMinMax(); 11667 if (this.options.choropleth.on && 11668 this.options.choropleth.sourceFieldSelect.on && 11669 this.options.choropleth.sourceFieldSelect.variants) { 11670 if (!this.containers.choroplethSourceSelect) { 11671 const sourceSelectOptions = []; 11672 this.options.choropleth.sourceFieldSelect.variants.forEac
11672h((variant) => { 11673 sourceSelectOptions.push($$A('<option value="' + 11674 variant + 11675 '" ' + 11676 (variant === this.options.choropleth.sourceField 11677 ? "selected" 11678 : "") + 11679 ">" + 11680 variant + 11681 "</option>")); 11682 }); 11683 this.containers.choroplethSourceSelect = { 11684 container: $$A('<div class="mapsvg-choropleth-source-field"></div>')[0], 11685 select: $$A('<select id="mapsvg-choropleth-source-field-select" class="mapsvg-select2"></select>')[0], 11686 options: sourceSelectOptions, 11687 }; 11688 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 11689 $$A(this.containers.choroplethSourceSelect.container).append($$A(this.containers.choroplethSourceSelect.select)); 11690 $$A(this.containers.map).append($$A(this.containers.choroplethSourceSelect.container)); 11691 $$A(this.containers.choroplethSourceSelect.select).mselect2(); 11692 $$A(this.containers.choroplethSourceSelect.select) 11693 .mselect2() 11694 .on("select2:select select2:unselecting", (e) => { 11695 if (e.cancelable) { 11696 e.preventDefault(); 11697 } 11698 e.stopPropagation(); 11699 this.setChoropleth({ sourceField: $$A(e.target).mselect2().val() }); 11700 }); 11701 } 11702 else { 11703 $$A(this.containers.choroplethSourceSelect.select).mselect2("destroy"); 11704 $$A(this.containers.choroplethSourceSelect.select).find("option").remove(); 11705 this.containers.choroplethSourceSelect.options = []; 11706 this.options.choropleth.sourceFieldSelect.variants.forEac
11706h((variant) => { 11707 this.containers.choroplethSourceSelect.options.push($$A('<option value="' + 11708 variant + 11709 '" ' + 11710 (variant === this.options.choropleth.sourceField 11711 ? "selected" 11712 : "") + 11713 ">" + 11714 variant + 11715 "</option>")[0]); 11716 }); 11717 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 11718 $$A(this.containers.choroplethSourceSelect.select).mselect2({ width: "100%" }); 11719 } 11720 } 11721 if ((!this.options.choropleth.on || !this.options.choropleth.sourceFieldSelect.on) && 11722 this.containers.choroplethSourceSelect && 11723 $$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 11724 $$A(this.containers.choroplethSourceSelect.container).hide(); 11725 } 11726 else if (this.options.choropleth.on && 11727 this.options.choropleth.sourceFieldSelect.on && 11728 this.containers.choroplethSourceSelect && 11729 !$$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 11730 $$A(this.containers.choroplethSourceSelect.container).show(); 11731 } 11732 $$A(this.containers.map).find(".mapsvg-choropleth-legend").remove(); 11733 if (this.options.choropleth.on && this.options.choropleth.coloring.legend.on) { 11734 const legend = this.options.choropleth.coloring.legend; 11735 let coloring = ""; 11736 if (this.options.choropleth.coloring.mode === "gradient") { 11737 coloring += 11738 '<div class="mapsvg-choropleth-legend-gradient-no-data">' + 11739 this.options.choropleth.coloring.noData.description + 11740 "</div>"; 11741 let legendGradient = ""; 11742 for (let chunkIdx = 1; chunkIdx < 5; chunkIdx++) { 11743 legendGradient += 11744 '<div class="mapsvg-choropleth-legend-gradient-chunk">' + 11745 ((this.options.choropleth.coloring.gradient.values.maxAdjusted * chunkIdx) / 11746 5 + 11747 this.options.choropleth.coloring.gradient.values.min) + 11748 "</div>"; 11749 } 11750 coloring += 11751 '<div class="mapsvg-choropleth-legend-gradient-colors">' + 11752 legendGradient + 11753 "</div>"; 11754 } 11755 else { 11756 coloring += 11757 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="no-data">' + 11758 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 11759 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 11760 this.options.choropleth.coloring.noData.description + 11761 "</div>" + 11762 "</div>"; 11763 coloring += 11764 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="out-of-range">' + 11765 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 11766 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 11767 this.options.choropleth.coloring.palette.outOfRange.description + 11768 "</div>" + 11769 "</div>"; 11770 const paletteColors = this.options.choropleth.coloring.palette.colors; 11771 paletteColors.forEach((paletteColor, idx) => { 11772 let paletteColorElementText = ""; 11773 if (paletteColor.description) { 11774 paletteColorElementText = paletteColor.description; 11775 } 11776 else { 11777 if (idx === 0 && !paletteColor.valueFrom && paletteColor.valueFrom !== 0) { 11778 if (legend.layout === "vertical") { 11779 paletteColorElementText = "Less then " + paletteColor.valueTo; 11780 } 11781 else { 11782 paletteColorElementText = "< " + paletteColor.valueTo; 11783 } 11784 } 11785 else if (idx === paletteColors.length - 1 && !paletteColor.valueTo) { 11786 if (legend.layout === "vertical") { 11787 paletteColorElementText = paletteColor.valueFrom + " or more"; 11788 } 11789 else { 11790 paletteColorElementText = paletteColor.valueFrom + " <"; 11791 } 11792 } 11793 else { 11794 paletteColorElementText = 11795 paletteColor.valueFrom + " ≤ " + paletteColor.valueTo; 11796 } 11797 } 11798 coloring += 11799 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="' + 11800 idx + 11801 '">' + 11802 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 11803 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 11804 paletteColorElementText + 11805 "</div>" + 11806 "</div>"; 11807 }); 11808 } 11809 this.containers.legend = { 11810 title: $$A('<div class="mapsvg-choropleth-legend-title">' + legend.title + "</div>")[0], 11811 text: $$A('<div class="mapsvg-choropleth-legend-text">' + legend.text + "</div>")[0], 11812 coloring: $$A('<div class="mapsvg-choropleth-legend-' + 11813 this.options.choropleth.coloring.mode + 11814 '">' + 11815 coloring + 11816 "</div>")[0], 11817 description: $$A('<div class="mapsvg-choropleth-legend-description">' + 11818 legend.description + 11819 "</div>")[0], 11820 container: $$A("<div />").addClass("mapsvg-choropleth-legend mapsvg-choropleth-legend-" + 11821 legend.layout + 11822 " mapsvg-choropleth-legend-container-" + 11823 legend.container)[0], 11824 }; 11825 $$A(this.containers.legend.container) 11826 .append(this.containers.legend.title) 11827 .append(this.containers.legend.text) 11828 .append(this.containers.legend.coloring) 11829 .append(this.containers.legend.description); 11830 $$A(this.containers.map).append(this.containers.legend.container); 11831 this.setChoroplethLegendCSS(); 11832 this.regionsRepository.events.on("updated", () => { 11833 this.redrawChoropleth(); 11834 }); 11835 this.objectsRepository.events.on("updated", () => { 11836 this.redrawChoropleth(); 11837 }); 11838 } 11839 if (this.options.choropleth.on && this.options.choropleth.coloring.mode === "gradient") { 11840 const colors = this.options.choropleth.coloring.gradient.colors; 11841 if (colors) { 11842 colors.lowRGB = tinycolor(colors.low).toRgb(); 11843 colors.highRGB = tinycolor(colors.high).toRgb(); 11844 colors.diffRGB = { 11845 r: colors.highRGB.r - colors.lowRGB.r, 11846 g: colors.highRGB.g - colors.lowRGB.g, 11847 b: colors.highRGB.b - colors.lowRGB.b, 11848 a: colors.highRGB.a - colors.lowRGB.a, 11849 }; 11850 this.containers.legend && this.setChoroplethLegendCSS(); 11851 } 11852 } 11853 this.redrawChoropleth(); 11854 } 11855 redrawChoropleth() { 11856 this.updateChoroplethMinMax(); 11857 this.redrawBubbles(); 11858 this.regionsRedrawColors(); 11859 } 11860 updateChoroplethMinMax() { 11861 if (this.options.choropleth.on) { 11862 const gradient = this.options.choropleth.coloring.gradient, values = []; 11863 gradient.values.min = 0; 11864 gradient.values.max = null; 11865 if (this.options.choropleth.source === "regions") { 11866 this.regions.forEach((region) => { 11867 const choropleth = region.data && region.data[this.options.choropleth.sourceField]; 11868 choropleth != undefined && choropleth !== "" && values.push(choropleth); 11869 }); 11870 } 11871 else {
11872 this.objectsRepository.objects.forEach((object) => { 11873 const choropleth = object[this.options.choropleth.sourceField]; 11874 choropleth != undefined && choropleth !== "" && values.push(choropleth); 11875 }); 11876 } 11877 if (values.length > 0) { 11878 gradient.values.min = Math.min.apply(null, values); 11879 gradient.values.max = Math.max.apply(null, values); 11880 gradient.values.maxAdjusted = gradient.values.max - gradient.values.min; 11881 } 11882 } 11883 } 11884 setChoroplethLegendCSS() { 11885 const gradient = this.options.choropleth.coloring.gradient, legend = this.options.choropleth.coloring.legend, noData = this.options.choropleth.coloring.noData, outOfRange = this.options.choropleth.coloring.palette.outOfRange; 11886 $$A(".mapsvg-choropleth-legend").css({ 11887 width: legend.width, 11888 height: legend.height, 11889 }); 11890 if (this.options.choropleth.coloring.mode === "gradient") { 11891 if (legend.layout === "horizontal") { 11892 $$A(".mapsvg-choropleth-legend-horizontal .mapsvg-choropleth-legend-gradient-colors").css({ 11893 background: "linear-gradient(to right," + 11894 gradient.colors.low + 11895 " 1%," + 11896 gradient.colors.high + 11897 " 100%)", 11898 }); 11899 } 11900 else { 11901 $$A(".mapsvg-choropleth-legend-vertical .mapsvg-choropleth-legend-gradient-colors").css({ 11902 background: "linear-gradient(to bottom," + 11903 gradient.colors.low + 11904 " 1%," + 11905 gradient.colors.high + 11906 " 100%)", 11907 }); 11908 } 11909 $$A(".mapsvg-choropleth-legend-gradient-no-data").css({ 11910 "background-color": noData.color, 11911 }); 11912 } 11913 else { 11914 const paletteColors = this.options.choropleth.coloring.palette.colors; 11915 paletteColors.forEach(function (paletteColor, idx) { 11916 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="' + 11917 idx + 11918 '"] .mapsvg-choropleth-legend-palette-color').css({ 11919 "background-color": paletteColor.color, 11920 }); 11921 }); 11922 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="no-data"] .mapsvg-choropleth-legend-palette-color').css({ 11923 "background-color": noData.color, 11924 }); 11925 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="out-of-range"] .mapsvg-choropleth-legend-palette-color').css({ 11926 "background-color": outOfRange.color, 11927 }); 11928 } 11929 } 11930 setCss(css) { 11931 this.options.css = 11932 css || (this.options.css ? this.options.css.replace(/%id%/g, "" + this.id) : ""); 11933 this.liveCss = this.liveCss || $$A("<style></style>").appendTo("head")[0]; 11934 $$A(this.liveCss).html(this.options.css); 11935 } 11936 setFilters(options) { 11937 options = options || this.options.filters; 11938 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11939 options.hide != undefined && (options.hide = MapSVG.parseBoolean(options.hide)); 11940 $$A.extend(true, this.options, { filters: options }); 11941 if (["leftSidebar", "rightSidebar", "header", "footer", "custom", "map"].indexOf(this.options.filters.location) === -1) { 11942 this.options.filters.location = "leftSidebar"; 11943 } 11944 if (this.options.filters.on) { 11945 if (this.formBuilder) { 11946 this.formBuilder.destroy(); 11947 } 11948 if (!this.containers.filters) { 11949 this.containers.filters = $$A('<div class="mapsvg-filters-wrap"></div>')[0]; 11950 } 11951 else { 11952 $$A(this.containers.filters).empty(); 11953 $$A(this.containers.filters).show(); 11954 } 11955 $$A(this.containers.filters).css({ 11956 "background-color": this.options.colors.directorySearch, 11957 }); 11958 if ($$A(this.containers.filtersModal)) { 11959 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 11960 } 11961 if (this.options.filters.location === "custom") { 11962 $$A(this.containers.filters) 11963 .removeClass("mapsvg-filter-container-custom") 11964 .addClass("mapsvg-filter-container-custom"); 11965 if ($$A("#" + this.options.filters.containerId).length) { 11966 $$A("#" + this.options.filters.containerId).append(this.containers.filters); 11967 } 11968 else { 11969 $$A(this.containers.filters).hide(); 11970 console.error("MapSVG: filter container #" + 11971 this.options.filters.containerId + 11972 " does not exists"); 11973 } 11974 } 11975 else { 11976 if (MapSVG.isPhone) { 11977 $$A(this.containers.header).append($$A(this.containers.filters)); 11978 this.setContainers({ header: { on: true } }); 11979 } 11980 else { 11981 const location = MapSVG.isPhone ? "header" : this.options.filters.location; 11982 if (this.options.menu.on && 11983 this.controllers.directory && 11984 this.options.menu.location === this.options.filters.location) { 11985 $$A(this.controllers.directory.containers.view) 11986 .find(".mapsvg-directory-filter-wrap") 11987 .append($$A(this.containers.filters)); 11988 this.controllers.directory.updateTopShift(); 11989 } 11990 else { 11991 $$A(this.containers[location]).append($$A(this.containers.filters)); 11992 this.controllers.directory && this.controllers.directory.updateTopShift(); 11993 } 11994 } 11995 } 11996 this.loadFiltersController(this.containers.filters, false); 11997 this.updateFiltersState(); 11998 } 11999 else { 12000 if ($$A(this.containers.filters)) { 12001 $$A(this.containers.filters).empty(); 12002 $$A(this.containers.filters).hide(); 12003 } 12004 } 12005 if (this.options.menu.on && 12006 this.controllers.directory && 12007 this.options.menu.location === this.options.filters.location) { 12008 this.controllers.directory.updateTopShift(); 12009 } 12010 } 12011 updateFiltersState() { 12012 if (this.options.filters && this.options.filters.on && this.controllers.filters) { 12013 this.controllers.filters.update(this.objectsRepository.query); 12014 this.updateFilterTags(); 12015 } 12016 } 12017 updateFilterTags() { 12018 $$A(this.containers.filterTags) && $$A(this.containers.filterTags).empty(); 12019 for (const field_name in this.objectsRepository.query.filters) { 12020 let field_value = this.objectsRepository.query.filters[field_name]; 12021 let _field_name = field_name; 12022 const filterField = this.filtersSchema.getField(_field_name); 12023 if (field_name == "regions") { 12024 _field_name = ""; 12025 field_value = field_value.region_ids.map((id) => this.getRegion(id).title); 12026 } 12027 else { 12028 _field_name = filterField && filterField.label; 12029 } 12030 if (field_name !== "distance") { 12031 if (!this.containers.filterTags) { 12032 this.containers.filterTags = $$A('<div class="mapsvg-filter-tags"></div>')[0]; 12033 if ($$A(this.containers.filters)) ; 12034 else { 12035 if (this.options.menu.on && this.controllers.directory) { 12036 $$A(this.controllers.directory.containers.toolbar).append(this.containers.filterTags); 12037 this.controllers.directory.updateTopShift(); 12038 } 12039 else { 12040 $$A(this.containers.map).append(this.containers.filterTags); 12041 if (this.options.zoom.buttons.on) { 12042 if (this.options.layersControl.on) { 12043 if (this.options.layersControl.position == "top-left") { 12044 $$A(this.containers.filterTags).css({ 12045 right: 0, 12046 bottom: 0, 12047 }); 12048 } 12049 else { 12050 $$A(this.containers.filterTags).css({ 12051 bottom: 0, 12052 }); 12053 } 12054 } 12055 else { 12056 if (this.options.zoom.buttons.location == "left") { 12057 $$A(this.containers.filterTags).css({ 12058 right: 0, 12059 }); 12060 } 12061 } 12062 } 12063 } 12064 } 12065 $$A(this.containers.filterTags).on("click", ".mapsvg-filter-delete", (e) => { 12066 const filterField = $$A(e.target).data("filter"); 12067 $$A(e.target).parent().remove(); 12068 this.objectsRepository.query.removeFilter(filterField); 12069 this.deselectAllRegions(); 12070 this.loadDataObjects(); 12071 }); 12072 } 12073 $$A(this.containers.filterTags).append('<div class="mapsvg-filter-tag">' + 12074 (_field_name ? _field_name + ": " : "") + 12075 field_value + 12076 ' <span class="mapsvg-filter-delete" data-filter="' + 12077 field_name + 12078 '">
12078Ã</span></div>'); 12079 } 12080 } 12081 } 12082 setContainers(options) { 12083 const _this = this; 12084 if (!this.containersCreated) { 12085 this.containers.wrapAll = document.createElement("div"); 12086 this.containers.wrapAll.classList.add("mapsvg-wrap-all"); 12087 this.containers.wrapAll.id = "mapsvg-map-" + this.id; 12088 this.containers.wrapAll.setAttribute("data-map-id", this.id ? this.id.toString() : ""); 12089 this.containers.wrap = document.createElement("div"); 12090 this.containers.wrap.classList.add("mapsvg-wrap"); 12091 this.containers.mapContainer = document.createElement("div"); 12092 this.containers.mapContainer.classList.add("mapsvg-map-container"); 12093 this.containers.leftSidebar = document.createElement("div"); 12094 this.containers.leftSidebar.className = 12095 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"; 12096 this.containers.rightSidebar = document.createElement("div"); 12097 this.containers.rightSidebar.className = 12098 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"; 12099 this.containers.header = document.createElement("div"); 12100 this.containers.header.className = "mapsvg-header mapsvg-top-container"; 12101 this.containers.footer = document.createElement("div"); 12102 this.containers.footer.className = "mapsvg-footer mapsvg-top-container"; 12103 _this.containers.wrapAll = $$A('<div class="mapsvg-wrap-all"></div>') 12104 .attr("id", "mapsvg-map-" + this.id) 12105 .attr("data-map-id", this.id)[0]; 12106 _this.containers.wrap = $$A('<div class="mapsvg-wrap"></div>')[0]; 12107 _this.containers.mapContainer = $$A('<div class="mapsvg-map-container"></div>')[0]; 12108 _this.containers.leftSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"></div>')[0]; 12109 _this.containers.rightSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"></div>')[0]; 12110 _this.containers.header = $$A('<div class="mapsvg-header mapsvg-top-container"></div>')[0]; 12111 _this.containers.footer = $$A('<div class="mapsvg-footer mapsvg-top-container"></div>')[0]; 12112 $$A(_this.containers.wrapAll).insertBefore(_this.containers.map); 12113 $$A(_this.containers.wrapAll).append(_this.containers.header); 12114 $$A(_this.containers.wrapAll).append(_this.containers.wrap); 12115 $$A(_this.containers.wrapAll).append(_this.containers.footer); 12116 $$A(_this.containers.mapContainer).append(_this.containers.map); 12117 $$A(_this.containers.wrap).append(_this.containers.leftSidebar); 12118 $$A(_this.containers.wrap).append(_this.containers.mapContainer); 12119 $$A(_this.containers.wrap).append(_this.containers.rightSidebar); 12120 _this.containersCreated = true; 12121 } 12122 options = options || _this.options.containers || {}; 12123 for (const contName in options) { 12124 if (options[contName].on !== undefined) { 12125 options[contName].on = MapSVG.parseBoolean(options[contName].on); 12126 } 12127 if (options[contName].width) { 12128 if (typeof options[contName].width != "string" || 12129 (options[contName].width.indexOf("px") === -1 && 12130 options[contName].width.indexOf("%") === -1 && 12131 options[contName].width !== "auto")) { 12132 options[contName].width = options[contName].width + "px"; 12133 } 12134 $$A(_this.containers[contName]).css({ "flex-basis": options[contName].width }); 12135 } 12136 if (options[contName].height) { 12137 if (typeof options[contName].height != "string" || 12138 (options[contName].height.indexOf("px") === -1 && 12139 options[contName].height.indexOf("%") === -1 && 12140 options[contName].height !== "auto")) { 12141 options[contName].height = options[contName].height + "px"; 12142 } 12143 $$A(_this.containers[contName]).css({ 12144 "flex-basis": options[contName].height, 12145 height: options[contName].height, 12146 }); 12147 } 12148 $$A.extend(true, _this.options, { containers: options }); 12149 let on = _this.options.containers[contName].on; 12150 if (MapSVG.isPhone && 12151 _this.options.menu.hideOnMobile && 12152 _this.options.menu.location === contName && 12153 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12154 on = false;
12155 } 12156 else if (MapSVG.isPhone && 12157 _this.options.menu.location === "custom" && 12158 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12159 on = false; 12160 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12161 } 12162 else if (MapSVG.isPhone && 12163 !_this.options.menu.hideOnMobile && 12164 _this.options.menu.location === contName && 12165 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12166 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12167 $$A(_this.containers.wrapAll).addClass("mapsvg-directory-visible"); 12168 } 12169 $$A(_this.containers[contName]).toggle(on); 12170 } 12171 _this.setDetailsView(); 12172 } 12173 shouldBeScrollable(container) { 12174 const _this = this; 12175 switch (container) { 12176 case "map": 12177 case "leftSidebar": 12178 case "rightSidebar": 12179 return true; 12180 case "custom": 12181 return false; 12182 case "header": 12183 case "footer": 12184 if (_this.options.containers[container].height && 12185 _this.options.containers[container].height !== "auto" && 12186 _this.options.containers[container].height !== "100%") { 12187 return true; 12188 } 12189 else { 12190 return false; 12191 } 12192 default: 12193 return false; 12194 } 12195 } 12196 setDirectory(options) { 12197 return this.setMenu(options); 12198 } 12199 setMenu(options) { 12200 options = options || this.options.menu; 12201 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12202 options.search != undefined && (options.search = MapSVG.parseBoolean(options.search)); 12203 options.showMapOnClick != undefined && 12204 (options.showMapOnClick = MapSVG.parseBoolean(options.showMapOnClick)); 12205 options.searchFallback != undefined && 12206 (options.searchFallback = MapSVG.parseBoolean(options.searchFallback)); 12207 options.customContainer != undefined && 12208 (options.customContainer = MapSVG.parseBoolean(options.customContainer)); 12209 $$A.extend(true, this.options, { menu: options }); 12210 this.controllers = this.controllers || {}; 12211 if (!this.containers.directory) { 12212 this.containers.directory = $$A('<div class="mapsvg-directory"></div>')[0]; 12213 } 12214 $$A(this.containers.directory).toggleClass("flex", this.shouldBeScrollable(this.options.menu.location)); 12215 if (this.options.menu.on) { 12216 if (!this.controllers.directory) { 12217 this.controllers.directory = new DirectoryController({ 12218 container: this.containers.directory, 12219 template: this.options.templates.directory, 12220 mapsvg: this, 12221 repository: this.options.menu.source === "regions" 12222 ? this.regionsRepository 12223 : this.objectsRepository, 12224 scrollable: this.shouldBeScrollable(this.options.menu.location), 12225 events: { 12226 click: (e, regionOrObject, mapsvg) => { 12227 this.events.trigger("click.directoryItem", this, [ 12228 e, 12229 regionOrObject, 12230 mapsvg, 12231 ]); 12232 }, 12233 mouseover: (e, regionOrObject, mapsvg) => { 12234 this.events.trigger("mouseover.directoryItem", this, [ 12235 e, 12236 regionOrObject, 12237 mapsvg, 12238 ]); 12239 }, 12240 mouseout: (e, regionOrObject, mapsvg) => { 12241 this.events.trigger("mouseout.directoryItem", this, [ 12242 e, 12243 regionOrObject, 12244 mapsvg, 12245 ]); 12246 }, 12247 }, 12248 }); 12249 this.controllers.directory._init(); 12250 } 12251 else { 12252 this.controllers.directory.repository = 12253 this.options.menu.source === "regions" 12254 ? this.regionsRepository 12255 : this.objectsRepository; 12256 this.controllers.directory.repository.query.update({ 12257 sort: [ 12258 { 12259 field: this.options.menu.sortBy, 12260 order: this.options.menu.sortDirection, 12261 }, 12262 ], 12263 }); 12264 if (options.filterout) { 12265 const f = {}; 12266 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 12267 this.controllers.directory.repository.query.setFilterOut(f); 12268 } 12269 this.controllers.directory.scrollable = this.shouldBeScrollable(this.options.menu.location); 12270 } 12271 let $container; 12272 if (MapSVG.isPhone && this.options.menu.hideOnMobile) { 12273 $container = $$A(this.containers.leftSidebar); 12274 } 12275 else { 12276 $container = 12277 this.options.menu.location !== "custom" 12278 ? $$A(this.containers[this.options.menu.location]) 12279 : $$A("#" + this.options.menu.containerId); 12280 } 12281 $container.append(this.containers.directory); 12282 if (this.options.colors.directory) { 12283 $$A(this.containers.directory).css({ 12284 "background-color": this.options.colors.directory, 12285 }); 12286 } 12287 this.setFilters(); 12288 this.setTemplates({ directoryItem: this.options.templates.directoryItem }); 12289 if ((this.options.menu.source === "regions" && this.regionsRepository.loaded) || 12290 (this.options.menu.source === "database" && this.objectsRepository.loaded)) { 12291 if (this.editMode && 12292 (options.sortBy || options.sortDirection || options.filterout)) { 12293 this.controllers.directory.repository.reload(); 12294 } 12295 this.loadDirectory(); 12296 } 12297 } 12298 else { 12299 this.controllers.directory && this.controllers.directory.destroy(); 12300 this.controllers.directory = null; 12301 } 12302 } 12303 setDatabase(options) { 12304 options = options || this.options.database; 12305 if (options.pagination) { 12306 if (options.pagination.on != undefined) { 12307 options.pagination.on = MapSVG.parseBoolean(options.pagination.on); 12308 } 12309 if (options.pagination.perpage != undefined) { 12310 options.pagination.perpage = parseInt(options.pagination.perpage); 12311 } 12312 } 12313 $$A.extend(true, this.options, { database: options }); 12314 if (options.pagination) { 12315 if (options.pagination.on !== undefined || options.pagination.perpage) { 12316 const query = new Query({ 12317 perpage: this.options.database.pagination.on 12318 ? this.options.database.pagination.perpage 12319 : 0, 12320 }); 12321 this.objectsRepository.find(query); 12322 } 12323 else { 12324 this.setPagination(); 12325 } 12326 } 12327 } 12328 updateGoogleMapsMaxZoom(geoPoint) { 12329 this.googleMaps.maxZoomService.getMaxZoomAtLatLng(geoPoint, (result) => { 12330 if (result.status === "OK") { 12331 this.googleMaps.currentMaxZoom = result.zoom; 12332 } 12333 }); 12334 } 12335 setGoogleMaps(options) { 12336 options = options || this.options.googleMaps; 12337 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12338 if (!this.googleMaps) { 12339 this.googleMaps = { loaded: false, initialized: false, map: null, overlay: null }; 12340 } 12341 $$A.extend(true, this.options, { googleMaps: options }); 12342 if (this.options.googleMaps.on) { 12343 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12344 if (!MapSVG.googleMapsApiLoaded) { 12345 this.events.on("googleMapsBoundsChanged", (bounds) => { 12346 this.setViewBoxByGoogleMapsOverlay(); 12347 }); 12348 this.loadGoogleMapsAPI(() => { 12349 this.setGoogleMaps(); 12350 }, () => { 12351 this.setGoogleMaps({ on: false }); 12352 }); 12353 } 12354 else { 12355 if (!this.googleMaps.map) { 12356 this.containers.googleMaps = $$A('<div class="mapsvg-layer mapsvg-layer-gm" id="mapsvg-google-maps-' + 12357 this.id + 12358 '"></div>').prependTo(this.containers.map)[0]; 12359 $$A(this.containers.googleMaps).css({ 12360 position: "absolute", 12361 top: 0, 12362 left: 0, 12363 bottom: 0, 12364 right: 0, 12365 "z-index": "0", 12366 }); 12367 this.googleMaps.map = new google.maps.Map(this.containers.googleMaps, { 12368 mapTypeId: options.type, 12369 fullscreenControl: false, 12370 keyboardShortcuts: false, 12371 mapTypeControl: false, 12372 scaleControl: false, 12373 scrollwheel: false, 12374 streetViewControl: false, 12375 zoomControl: false, 12376 styles: options.styleJSON, 12377 }); 12378 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 12379 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 12380 const bounds = new google.maps.LatLngBounds(southWest, northEast);
12381 this.googleMaps.overlay = this.createGoogleMapOverlay(bounds, this.googleMaps.map); 12382 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 12383 this.googleMaps.map.fitBounds(bounds, 0); 12384 } 12385 else { 12386 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 12387 this.googleMaps.map.setCenter(this.options.googleMaps.center); 12388 } 12389 this.googleMaps.initialized = true; 12390 this.googleMaps.maxZoomService = new google.maps.MaxZoomService(); 12391 this.googleMaps.map.addListener("idle", () => { 12392 this.isZooming = false; 12393 }); 12394 google.maps.event.addListenerOnce(this.googleMaps.map, "idle", () => { 12395 setTimeout(() => { 12396 $$A(this.containers.map).addClass("mapsvg-fade-in"); 12397 setTimeout(() => { 12398 $$A(this.containers.map).removeClass("mapsvg-google-map-loading"); 12399 $$A(this.containers.map).removeClass("mapsvg-fade-in"); 12400 if (!this.options.googleMaps.center || 12401 !this.options.googleMaps.zoom) { 12402 this.options.googleMaps.center = this.googleMaps.map 12403 .getCenter() 12404 .toJSON(); 12405 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 12406 } 12407 this.zoomDelta = this.options.googleMaps.zoom - this.zoomLevel; 12408 this.updateGoogleMapsMaxZoom(this.options.googleMaps.center); 12409 this.setInitialViewBox(this.viewBox); 12410 this.toggleSvgLayerOnZoom(); 12411 this.events.trigger("googleMapsLoaded"); 12412 }, 300); 12413 }, 1); 12414 }); 12415 } 12416 else { 12417 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12418 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).show(); 12419 if (options.type) { 12420 this.googleMaps.map.setMapTypeId(options.type); 12421 } 12422 } 12423 } 12424 } 12425 else { 12426 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", false); 12427 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).hide(); 12428 this.googleMaps.initialized = false; 12429 } 12430 if (this.converter) { 12431 this.converter.setWorldShift(this.options.googleMaps.on); 12432 } 12433 } 12434 createGoogleMapOverlay(bounds, map) { 12435 class GoogleMapsOverlay extends google.maps.OverlayView { 12436 constructor(bounds, googleMapInstance, mapsvg) { 12437 super(); 12438 this.bounds_ = bounds; 12439 this.map_ = googleMapInstance; 12440 this.mapsvg = mapsvg; 12441 this.setMap(googleMapInstance); 12442 this.prevCoords = { 12443 sw: { x: 0, y: 0 }, 12444 sw2: { x: 0, y: 0 }, 12445 ne: { x: 0, y: 0 }, 12446 ne2: { x: 0, y: 0 }, 12447 }; 12448 } 12449 draw() { 12450 this.mapsvg.events.trigger("googleMapsBoundsChanged", this.map_, [ 12451 this.getPixelBounds(), 12452 this.map_, 12453 ]); 12454 } 12455 onAdd() { 12456 this.element = document.createElement("div"); 12457 this.element.style.borderStyle = "none"; 12458 this.element.style.borderWidth = "0px"; 12459 this.element.style.position = "absolute"; 12460 const panes = this.getPanes(); 12461 panes.overlayLayer.appendChild(this.element); 12462 } 12463 getPixelBounds() { 12464 const overlayProjection = this.getProjection(); 12465 if (!overlayProjection) 12466 return;
12467 const geoSW = this.bounds_.getSouthWest(); 12468 const geoNE = this.bounds_.getNorthEast(); 12469 const coords = { 12470 sw: overlayProjection.fromLatLngToDivPixel(geoSW), 12471 ne: overlayProjection.fromLatLngToDivPixel(geoNE), 12472 sw2: overlayProjection.fromLatLngToContainerPixel(geoSW), 12473 ne2: overlayProjection.fromLatLngToContainerPixel(geoNE), 12474 }; 12475 const ww = overlayProjection.getWorldWidth(); 12476 if (this.prevCoords.sw) { 12477 if (coords.ne.x < coords.sw.x) { 12478 if (Math.abs(this.prevCoords.sw.x - coords.sw.x) > 12479 Math.abs(this.prevCoords.ne.x - coords.ne.x)) { 12480 coords.sw.x = coords.sw.x - ww; 12481 } 12482 else { 12483 coords.ne.x = coords.ne.x + ww; 12484 } 12485 if (Math.abs(this.prevCoords.sw2.x - coords.sw2.x) > 12486 Math.abs(this.prevCoords.ne2.x - coords.ne2.x)) { 12487 coords.sw2.x = coords.sw2.x - ww; 12488 } 12489 else { 12490 coords.ne2.x = coords.ne2.x + ww; 12491 } 12492 } 12493 } 12494 this.prevCoords = coords; 12495 return { sw: coords.sw2, ne: coords.ne2 }; 12496 } 12497 } 12498 return new GoogleMapsOverlay(bounds, map, this); 12499 } 12500 loadGoogleMapsAPI(callback, fail) { 12501 if (window.google !== undefined && google.maps) { 12502 MapSVG.googleMapsApiLoaded = true; 12503 } 12504 if (MapSVG.googleMapsApiLoaded) { 12505 if (typeof callback == "function") { 12506 callback(); 12507 } 12508 return; 12509 } 12510 MapSVG.googleMapsLoadCallbacks = MapSVG.googleMapsLoadCallbacks || []; 12511 if (typeof callback == "function") { 12512 MapSVG.googleMapsLoadCallbacks.push(callback); 12513 } 12514 if (MapSVG.googleMapsApiIsLoading) { 12515 return; 12516 } 12517 MapSVG.googleMapsApiIsLoading = true; 12518 window.gm_authFailure = () => { 12519 if (MapSVG.GoogleMapBadApiKey) { 12520 MapSVG.GoogleMapBadApiKey(); 12521 } 12522 else { 12523 if (this.editMode) { 12524 alert("Google maps API key is incorrect."); 12525 } 12526 else { 12527 console.error("MapSVG: Google maps API key is incorrect."); 12528 } 12529 } 12530 }; 12531 this.googleMapsScript = document.createElement("script"); 12532 this.googleMapsScript.onload = () => { 12533 MapSVG.googleMapsApiLoaded = true; 12534 MapSVG.googleMapsLoadCallbacks.forEach((_callback) => { 12535 if (typeof callback == "function") 12536 _callback(); 12537 }); 12538 }; 12539 const gmLibraries = []; 12540 if (this.options.googleMaps.drawingTools) { 12541 gmLibraries.push("drawing"); 12542 } 12543 if (this.options.googleMaps.geometry) { 12544 gmLibraries.push("geometry"); 12545 } 12546 let libraries = ""; 12547 if (gmLibraries.length > 0) { 12548 libraries = "&libraries=" + gmLibraries.join(","); 12549 } 12550 this.googleMapsScript.src = 12551 "https://maps.googleapis.com/maps/api/js?language=en&key=" + 12552 this.options.googleMaps.apiKey + 12553 libraries; 12554 document.head.appendChild(this.googleMapsScript); 12555 } 12556 loadDetailsView(obj) { 12557 this.controllers.popover && this.controllers.popover.close(); 12558 if (this.controllers.detailsView) 12559 this.controllers.detailsView.destroy(); 12560 this.controllers.detailsView = new DetailsController({ 12561 autoresize: MapSVG.isPhone && 12562 this.options.detailsView.mobileFullscreen && 12563 this.options.detailsView.location !== "custom" 12564 ? false 12565 : this.options.detailsView.autoresize, 12566 container: this.containers.detailsView, 12567 template: obj instanceof Region 12568 ? this.options.templates.detailsViewRegion 12569 : this.options.templates.detailsView, 12570 mapsvg: this, 12571 data: obj.getData(), 12572 modal: MapSVG.isPhone && 12573 this.options.detailsView.mobileFullscreen && 12574 this.options.detailsView.location !== "custom", 12575 scrollable: (MapSVG.isPhone && 12576 this.options.detailsView.mobileFullscreen && 12577 this.options.detailsView.location !== "custom") || 12578 this.shouldBeScrollable(this.options.detailsView.location), 12579 withToolbar: !(MapSVG.isPhone && 12580 this.options.detailsView.mobileFullscreen && 12581 this.options.detailsView.location !== "custom") && this.shouldBeScrollable(this.options.detailsView.location), 12582 events: { 12583 shown: (detailsController) => { 12584 this.events.trigger("shown.detailsView", this, [this, detailsController]); 12585 $$A(window).trigger("shown.detailsView", [this, detailsController]); 12586 }, 12587 closed: (detailsController) => { 12588 this.deselectAllRegions(); 12589 this.deselectAllMarkers(); 12590 this.controllers && 12591 this.controllers.directory && 12592 this.controllers.directory.deselectItems(); 12593 this.events.trigger("closed.detailsView", [this, detailsController]); 12594 }, 12595 }, 12596 }); 12597 this.controllers.detailsView._init(); 12598 } 12599 loadFiltersModal() { 12600 if (this.options.filters.modalLocation != "custom") { 12601 if (!this.containers.filtersModal) { 12602 this.containers.filtersModal = $$A('<div class="mapsvg-details-container mapsvg-filters-wrap"></div>')[0]; 12603 } 12604 this.setColors(); 12605 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 12606 if (MapSVG.isPhone) { 12607 $$A("body").append($$A(this.containers.filtersModal)); 12608 $$A(this.containers.filtersModal).css({ width: "" }); 12609 } 12610 else { 12611 $$A(this.containers[this.options.filters.modalLocation]).append($$A(this.containers.filtersModal)); 12612 } 12613 } 12614 else { 12615 this.containers.filtersModal = $$A("#" + this.options.filters.containerId)[0]; 12616 $$A(this.containers.filtersModal).css({ width: "" }); 12617 } 12618 this.loadFiltersController(this.containers.filtersModal, true); 12619 } 12620 loadFiltersController(container, modal = false) { 12621 if (this.filtersSchema.getFields().length === 0) { 12622 return; 12623 } 12624 let filtersInDirectory, filtersHide; 12625 if (MapSVG.isPhone) { 12626 filtersInDirectory = true; 12627 filtersHide = this.options.filters.hideOnMobile; 12628 } 12629 else { 12630 filtersInDirectory = 12631 this.options.menu.on && 12632 this.controllers.directory && 12633 this.options.menu.location === this.options.filters.location; 12634 filtersHide = this.options.filters.hide; 12635 } 12636 const scrollable = modal || 12637 (!filtersInDirectory && 12638 ["leftSidebar", "rightSidebar"].indexOf(this.options.filters.location) !== -1); 12639 this.filtersRepository = 12640 this.options.filters.source === "regions" 12641 ? this.regionsRepository 12642 : this.objectsRepository; 12643 if (this.options.filters.searchButton) { 12644 this.changedFields = null; 12645 this.changedSearch = null; 12646 } 12647 else { 12648 this.changedSearch = () => { 12649 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 12650 }; 12651 this.changedFields = () => { 12652 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 12653 }; 12654 } 12655 if (this.options.filters.searchButton) { 12656 this.changedFields = null; 12657 this.changedSearch = null; 12658 } 12659 else { 12660 this.changedSearch = () => { 12661 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 12662 }; 12663 this.changedFields = () => { 12664 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 12665 }; 12666 } 12667 this.controllers.filters = new FiltersController({ 12668 container: container, 12669 query: this.filtersRepository.query, 12670 mapsvg: this, 12671 schema: this.filtersSchema, 12672 template: '<div class="mapsvg-filters-container"></div>', 12673 scrollable: scrollable, 12674 modal: modal, 12675 withToolbar: MapSVG.isPhone ? false : modal, 12676 width: $$A(container).hasClass("mapsvg-map-container") 12677 ? this.options.filters.width 12678 : "100%", 12679 hide: this.options.filters.hide, 12680 hideOnMobile: this.options.filters.hideOnMobile, 12681 showButtonText: this.options.filters.showButtonText, 12682 clearButton: this.options.filters.clearButton, 12683 clearButtonText: this.options.filters.clearButtonText, 12684 searchButton: this.options.filters.searchButton, 12685 searchButtonText: this.options.filters.searchButtonText, 12686 padding: this.options.filters.padding, 12687 events: { 12688 "cleared.fields": () => { 12689 this.deselectAllRegions(); 12690 }, 12691 "changed.fields": this.changedFields, 12692 "changed.search": this.changedSearch, 12693 "click.btn.searchButton": () => { 12694 this.filtersRepository.reload(); 12695 }, 12696 loaded: () => { 12697 this.controllers.directory && this.controllers.directory.updateTopShift(); 12698 }, 12699 "click.btn.showFilters": () => { 12700 this.loadFiltersModal(); 12701 }, 12702 }, 12703 }); 12704 this.controllers.filters._init(); 12705 } 12706 textSearch(text, fallback = false) { 12707 const query = new Query({ 12708 filters: { search: text }, 12709 searchFallback: fallback, 12710 }); 12711 this.filtersRepository.find(query); 12712 } 12713 getRegion(id) { 12714 return this.regions.findById(id); 12715 } 12716 getRegions() { 12717 return this.regions; 12718 } 12719 getMarker(id) { 12720 return this.markers.findById(id); 12721 } 12722 checkId(id) { 12723 if (this.getRegion(id)) 12724 return { canUse: false, error: "This ID is already being used by a Region" }; 12725 else if (this.getMarker(id)) 12726 return { canUse: false, error: "This ID is already being used by another Marker" }; 12727 else 12728 return { canUse: true, error: "" }; 12729 } 12730 regionsRedrawColors() { 12731 this.regions.forEach((region) => { 12732 region.setFill(); 12733 }); 12734 } 12735 redrawBubbles() { 12736 $$A(this.containers.map).removeClass("bubbles-regions-on bubbles-database-on"); 12737 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 12738 $$A(this.containers.map).addClass("bubbles-" + this.options.choropleth.source + "-on"); 12739 } 12740 this.regions.forEach(function (region) { 12741 region.drawBubble(); 12742 }); 12743 const markersBubbleMode = this.options.choropleth.on && 12744 this.options.choropleth.source == "database" && 12745 this.options.choropleth.bubbleMode;
12746 this.markers.forEach(function (marker) { 12747 marker.setBubbleMode(markersBubbleMode); 12748 }); 12749 } 12750 destroy() { 12751 if (this.controllers && this.controllers.directory) { 12752 this.controllers.directory.mobileButtons.remove(); 12753 } 12754 $$A(this.containers.map) 12755 .empty() 12756 .insertBefore($$A(this.containers.wrapAll)) 12757 .attr("style", "") 12758 .removeClass("mapsvg mapsvg-responsive"); 12759 this.controllers.popover && this.controllers.popover.close(); 12760 if (this.controllers.detailsView) 12761 this.controllers.detailsView.destroy(); 12762 $$A(this.containers.wrapAll).remove(); 12763 } 12764 getData() { 12765 return { 12766 id: this.id, 12767 title: this.options.title, 12768 options: this.getOptions(false, false), 12769 }; 12770 } 12771 mayBeFitMarkers() { 12772 if (!this.lastTimeFitWas) { 12773 this.lastTimeFitWas = Date.now() - 99999; 12774 } 12775 this.fitDelta = Date.now() - this.lastTimeFitWas; 12776 if (this.fitDelta > 1000 && 12777 !this.firstDataLoad && 12778 !this.fitOnDataLoadDone && 12779 this.options.fitMarkers) { 12780 this.fitMarkers(); 12781 this.fitOnDataLoadDone = true; 12782 } 12783 if (this.firstDataLoad && 12784 (this.options.fitMarkersOnStart || 12785 (this.options.fitMarkers && this.options.database.loadOnStart === false))) { 12786 this.firstDataLoad = false; 12787 if (this.options.googleMaps.on && !this.googleMaps.map) { 12788 this.events.on("googleMapsLoaded", () => { 12789 this.fitMarkers(); 12790 }); 12791 } 12792 else { 12793 this.fitMarkers(); 12794 } 12795 } 12796 this.lastTimeFitWas = Date.now(); 12797 } 12798 fitMarkers() { 12799 const dbObjects = this.objectsRepository.getLoaded(); 12800 if (!dbObjects || dbObjects.length === 0) { 12801 return; 12802 } 12803 if (this.options.googleMaps.on && typeof google !== "undefined") { 12804 const lats = []; 12805 const lngs = []; 12806 if (dbObjects.length > 1) { 12807 dbObjects.forEach((object) => { 12808 if (object.location && object.location.geoPoint) { 12809 lats.push(object.location.geoPoint.lat); 12810 lngs.push(object.location.geoPoint.lng); 12811 } 12812 }); 12813 const minlat = Math.min.apply(null, lats), maxlat = Math.max.apply(null, lats); 12814 const minlng = Math.min.apply(null, lngs), maxlng = Math.max.apply(null, lngs); 12815 const bbox = new google.maps.LatLngBounds({ lat: minlat, lng: minlng }, { lat: maxlat, lng: maxlng }); 12816 this.googleMaps.map.fitBounds(bbox, 0); 12817 } 12818 else { 12819 if (dbObjects[0].location && 12820 dbObjects[0].location.geoPoint.lat && 12821 dbObjects[0].location.geoPoint.lng) { 12822 const coords = { 12823 lat: dbObjects[0].location.geoPoint.lat, 12824 lng: dbObjects[0].location.geoPoint.lng, 12825 }; 12826 if (this.googleMaps.map) { 12827 this.googleMaps.map.setCenter(coords); 12828 this.googleMaps.map.setZoom(this.options.fitSingleMarkerZoom); 12829 } 12830 } 12831 } 12832 } 12833 else { 12834 if (this.options.clustering.on) { 12835 const arr = []; 12836 this.markersClusters.forEach((c) => { 12837 arr.push(c); 12838 }); 12839 this.markers.forEach((m) => { 12840 arr.push(m); 12841 }); 12842 this.zoomTo(arr); 12843 return; 12844 } 12845 else { 12846 this.zoomTo(this.markers); 12847 return; 12848 } 12849 } 12850 } 12851 setFitSingleMarkerZoom(zoom) { 12852 this.options.fitSingleMarkerZoom = parseInt(zoom); 12853 } 12854 showUserLocation(callback) { 12855 this.getUserLocation((geoPoint) => { 12856 this.userLocation = null; 12857 this.userLocation = new Location({ 12858 geoPoint: geoPoint, 12859 img: MapSVG.urls.root + "/markers/user-location.svg", 12860 }); 12861 this.userLocationMarker && this.userLocationMarker.delete(); 12862 this.userLocationMarker = new Marker({ 12863 location: this.userLocation, 12864 mapsvg: this, 12865 width: 15, 12866 height: 15, 12867 }); 12868 $$A(this.userLocationMarker.element).addClass("mapsvg-user-location"); 12869 this.userLocationMarker.centered = true; 12870 this.getLayer("markers").append(this.userLocationMarker.element); 12871 this.userLocationMarker.adjustScreenPosition(); 12872 callback && callback(this.userLocation); 12873 }); 12874 } 12875 getUserLocation(callback) { 12876 if (navigator.geolocation) { 12877 navigator.geolocation.getCurrentPosition(function (position) { 12878 const pos = new GeoPoint(position.coords.latitude, position.coords.longitude); 12879 callback && callback(pos); 12880 }); 12881 } 12882 else { 12883 return false;
12884 } 12885 } 12886 getScale() { 12887 const scale2 = this.containers.map.clientWidth / this.viewBox.width; 12888 return scale2 || 1; 12889 } 12890 getViewBox() { 12891 return this.viewBox; 12892 } 12893 viewBoxSetBySize(width, height) { 12894 this.setSize(width, height); 12895 this._viewBox.update(this.viewBoxGetBySize(width, height)); 12896 this.setViewBox(this._viewBox); 12897 $$A(window).trigger("resize"); 12898 this.setSize(width, height); 12899 this.setZoomLevels(); 12900 return this.viewBox; 12901 } 12902 viewBoxGetBySize(width, height) { 12903 const new_ratio = width / height; 12904 const old_ratio = this.svgDefault.viewBox.width / this.svgDefault.viewBox.height; 12905 const vb = $$A.extend([], this.svgDefault.viewBox); 12906 if (new_ratio != old_ratio) { 12907 if (new_ratio > old_ratio) { 12908 vb[2] = this.svgDefault.viewBox.height * new_ratio; 12909 vb[0] = this.svgDefault.viewBox.x - (vb[2] - this.svgDefault.viewBox.width) / 2; 12910 } 12911 else { 12912 vb[3] = this.svgDefault.viewBox.width / new_ratio; 12913 vb[1] = this.svgDefault.viewBox.y - (vb[3] - this.svgDefault.viewBox.height) / 2; 12914 } 12915 } 12916 return vb; 12917 }
12918 viewBoxReset(toInitial) { 12919 if (this.options.googleMaps.on && this.googleMaps.map) { 12920 if (!toInitial) { 12921 this.options.googleMaps.center = null; 12922 this.options.googleMaps.zoom = null; 12923 } 12924 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 12925 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 12926 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 12927 const bounds = new google.maps.LatLngBounds(southWest, northEast); 12928 this.googleMaps.map.fitBounds(bounds, 0); 12929 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 12930 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 12931 } 12932 else { 12933 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 12934 this.googleMaps.map.setCenter(this.options.googleMaps.center); 12935 } 12936 } 12937 else { 12938 if (toInitial) { 12939 const v = this._viewBox || this.svgDefault.viewBox; 12940 this.zoomLevel = 0; 12941 this._scale = 1; 12942 this.setViewBox(v); 12943 } 12944 else { 12945 this.setViewBox(); 12946 } 12947 } 12948 return this.viewBox; 12949 } 12950 getGeoViewBox() { 12951 const v = this.viewBox; 12952 const p1 = new SVGPoint(v.x, v.y); 12953 const p2 = new SVGPoint(v.x + v.width, v.y); 12954 const p3 = new SVGPoint(v.x, v.y); 12955 const p4 = new SVGPoint(v.x, v.y + v.height); 12956 const leftLon = this.converter.convertSVGToGeo(p1).lng; 12957 const rightLon = this.converter.convertSVGToGeo(p2).lng; 12958 const topLat = this.converter.convertSVGToGeo(p3).lat; 12959 const bottomLat = this.converter.convertSVGToGeo(p4).lat; 12960 return [leftLon, topLat, rightLon, bottomLat]; 12961 } 12962 mapAdjustStrokes() { 12963 this.regions.forEach((region) => region.adjustStroke(this.scale)); 12964 } 12965 zoomIn(center) { 12966 if (this.canZoom) { 12967 this.isZooming = true; 12968 this.canZoom = false;
12969 setTimeout(() => { 12970 this.isZooming = false; 12971 this.canZoom = true; 12972 }, 700); 12973 this.zoom(1, center); 12974 } 12975 } 12976 zoomOut(center) { 12977 if (this.canZoom) { 12978 this.isZooming = true; 12979 this.canZoom = false; 12980 setTimeout(() => { 12981 this.isZooming = false; 12982 this.canZoom = true; 12983 }, 700); 12984 this.zoom(-1, center); 12985 } 12986 } 12987 zoomTo(mapObjects, zoomToLevel) { 12988 const convertedObjects = !Array.isArray(mapObjects) ? [mapObjects] : mapObjects; 12989 const bbox = this.getGroupBBox(convertedObjects); 12990 return this.fitViewBox(bbox, zoomToLevel); 12991 } 12992 getGroupBBox(mapObjects) { 12993 let _bbox; 12994 const xmax = []; 12995 const ymax = []; 12996 const xmin = []; 12997 const ymin = []; 12998 for (let i = 0; i < mapObjects.length; i++) { 12999 _bbox = mapObjects[i].getBBox(); 13000 xmin.push(_bbox.x); 13001 ymin.push(_bbox.y); 13002 const _w = _bbox.x + _bbox.width; 13003 const _h = _bbox.y + _bbox.height; 13004 xmax.push(_w); 13005 ymax.push(_h); 13006 } 13007 const _xmin = Math.min(...xmin); 13008 const _ymin = Math.min(...ymin); 13009 const width = Math.max(...xmax) - _xmin; 13010 const height = Math.max(...ymax) - _ymin; 13011 let padding = 10; 13012 const point1 = new ScreenPoint(padding, 0); 13013 const point2 = new ScreenPoint(0, 0); 13014 padding = 13015 this.converter.convertPixelToSVG(point1).x - this.converter.convertPixelToSVG(point2).x; 13016 return new ViewBox(_xmin - padding, _ymin - padding, width + padding * 2, height + padding * 2); 13017 } 13018 fitViewBox(fitViewBox, forceZoomLevel) { 13019 let viewBoxPrev; 13020 let foundZoomLevelNumber = 0; 13021 let foundZoomLevel; 13022 let newViewBox;
13023 this.zoomLevels.forEach((zoomLevel) => { 13024 if (viewBoxPrev && viewBoxPrev.x !== undefined) { 13025 if (fitViewBox.fitsInViewBox(viewBoxPrev) && 13026 zoomLevel.viewBox.fitsInViewBox(fitViewBox, true)) { 13027 foundZoomLevelNumber = forceZoomLevel ? forceZoomLevel : zoomLevel.zoomLevel; 13028 foundZoomLevel = this.zoomLevels.get(foundZoomLevelNumber); 13029 newViewBox = new ViewBox(fitViewBox.x - foundZoomLevel.viewBox.width / 2 + fitViewBox.width / 2, fitViewBox.y - foundZoomLevel.viewBox.height / 2 + fitViewBox.height / 2, foundZoomLevel.viewBox.width, foundZoomLevel.viewBox.height); 13030 } 13031 } 13032 viewBoxPrev = zoomLevel && zoomLevel.viewBox; 13033 }); 13034 if (foundZoomLevel) { 13035 if (this.canZoom) { 13036 this.isZooming = true; 13037 this.canZoom = false; 13038 setTimeout(() => { 13039 this.isZooming = false; 13040 this.canZoom = true; 13041 }, 700); 13042 this.zoomLevel = foundZoomLevelNumber; 13043 this._scale = foundZoomLevel._scale; 13044 this.setViewBox(newViewBox); 13045 return true; 13046 } 13047 } 13048 else { 13049 return false; 13050 } 13051 } 13052 zoomToRegion(region, zoomToLevel) { 13053 this.fitViewBox(region.getBBox(), zoomToLevel); 13054 return true; 13055 } 13056 zoomToMarkerOrCluster(mapObject, zoomToLevel) { 13057 this.zoomLevel = zoomToLevel || 1; 13058 const vb = this.zoomLevels.get(this.zoomLevel).viewBox; 13059 const newViewBox = new ViewBox(mapObject.svgPoint.x - vb.width / 2, mapObject.svgPoint.y - vb.height / 2, vb.width, vb.height); 13060 this.setViewBox(newViewBox); 13061 this._scale = this.zoomLevels.get(this.zoomLevel)._scale; 13062 } 13063 centerOn(region, yShift) { 13064 if (this.options.googleMaps.on) { 13065 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13066 $$A(this.containers.map).addClass("scrolling"); 13067 const latLng = region.getCenterLatLng(yShift); 13068 this.googleMaps.map.panTo(latLng); 13069 setTimeout(() => { 13070 $$A(this.containers.map).removeClass("scrolling"); 13071 }, 100); 13072 } 13073 else { 13074 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13075 const bbox = region.getBBox(); 13076 const vb = this.viewBox; 13077 const newViewBox = new ViewBox(bbox.x - vb.width / 2 + bbox.width / 2, bbox.y - vb.height / 2 + bbox.height / 2 - yShift, vb.width, vb.height); 13078 this.setViewBox(newViewBox); 13079 } 13080 } 13081 zoom(delta, center) { 13082 let newViewBox = new ViewBox(0, 0, 0, 0); 13083 const d = delta > 0 ? 1 : -1; 13084 if (!this.zoomLevels.get(this.zoomLevel + d)) 13085 return;
13086 const newZoomLevel = this.zoomLevel + d; 13087 const zoomIn = d > 0; 13088 const zoomOut = d < 0; 13089 const zoomRange = this.getZoomRange(); 13090 const isInZoomRange = this.zoomLevel >= zoomRange.min && this.zoomLevel <= zoomRange.max; 13091 const goingOutOfZoomRange = isInZoomRange && (newZoomLevel > zoomRange.max || newZoomLevel < zoomRange.min); 13092 const outOfRangeAndMovingAway = !isInZoomRange && 13093 ((zoomIn && newZoomLevel > zoomRange.max) || (zoomOut && newZoomLevel < zoomRange.min)); 13094 if (goingOutOfZoomRange || outOfRangeAndMovingAway) { 13095 return; 13096 } 13097 this.zoomLevel = newZoomLevel; 13098 const z = this.zoomLevels.get(this.zoomLevel); 13099 this._scale = z._scale; 13100 newViewBox = z.viewBox; 13101 let shift = []; 13102 if (center) { 13103 const koef = zoomIn ? 0.5 : -1; 13104 newViewBox.x = this.viewBox.x + (center.x - this.viewBox.x) * koef; 13105 newViewBox.y = this.viewBox.y + (center.y - this.viewBox.y) * koef; 13106 } 13107 else { 13108 shift = [ 13109 (this.viewBox.width - newViewBox.width) / 2, 13110 (this.viewBox.height - newViewBox.height) / 2, 13111 ]; 13112 newViewBox.x = this.viewBox.x + shift[0]; 13113 newViewBox.y = this.viewBox.y + shift[1]; 13114 } 13115 this.shiftViewBoxToScrollBoundaries(newViewBox); 13116 this.setViewBox(newViewBox); 13117 } 13118 toggleSvgLayerOnZoom() { 13119 if (this.options.googleMaps.on && 13120 this.googleMaps.map && 13121 this.options.zoom.hideSvg && 13122 this.googleMaps.map.getZoom() >= this.options.zoom.hideSvgZoomLevel) { 13123 if (!$$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13124 $$A(this.containers.svg).animate({ opacity: 0 }, 400, "linear", () => { 13125 $$A(this.containers.svg).addClass("mapsvg-invisible"); 13126 }); 13127 } 13128 } 13129 else { 13130 if ($$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13131 $$A(this.containers.svg).animate({ opacity: 1 }, 400, "linear", () => { 13132 $$A(this.containers.svg).removeClass("mapsvg-invisible"); 13133 }); 13134 } 13135 } 13136 } 13137 shiftViewBoxToScrollBoundaries(newViewBox) { 13138 if (this.options.scroll.limit) { 13139 if (newViewBox.x < this.svgDefault.viewBox.x) 13140 newViewBox.x = this.svgDefault.viewBox.x; 13141 else if (newViewBox.x + newViewBox.width > 13142 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13143 newViewBox.x = 13144 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - newViewBox.width; 13145 if (newViewBox.y < this.svgDefault.viewBox.y) 13146 newViewBox.y = this.svgDefault.viewBox.y; 13147 else if (newViewBox.y + newViewBox.height > 13148 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13149 newViewBox.y = 13150 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height - newViewBox.height; 13151 } 13152 return newViewBox; 13153 } 13154 markerDelete(marker) { 13155 if (this.editingMarker && this.editingMarker.id == marker.id) { 13156 this.unsetEditingMarker(); 13157 } 13158 if (this.markers.findById(marker.id)) { 13159 this.markers.delete(marker.id); 13160 } 13161 marker.delete(); 13162 marker = null; 13163 if (this.markers.length === 0) 13164 this.options.markerLastID = 0; 13165 } 13166 markersClusterAdd(markersCluster) { 13167 this.layers.markers.append(markersCluster.elem); 13168 this.markersClusters.push(markersCluster); 13169 markersCluster.adjustScreenPosition(); 13170 } 13171 markerAdd(marker) { 13172 $$A(marker.element).hide(); 13173 marker.adjustScreenPosition(); 13174 this.layers.markers.append(marker.element); 13175 this.markers.push(marker); 13176 marker.mapped = true; 13177 setTimeout(function () { 13178 $$A(marker.element).show(); 13179 }, 100); 13180 } 13181 markerRemove(marker) { 13182 if (this.editingMarker && this.editingMarker.id == marker.id) { 13183 this.editingMarker = null; 13184 delete this.editingMarker; 13185 } 13186 if (this.markers.findById(marker.id)) { 13187 this.markers.findById(marker.id).element.remove(); 13188 this.markers.delete(marker.id); 13189 marker = null; 13190 } 13191 if (this.markers.length === 0) 13192 this.options.markerLastID = 0; 13193 } 13194 markerId() { 13195 this.options.markerLastID = this.options.markerLastID + 1; 13196 const id = "marker_" + this.options.markerLastID; 13197 if (this.getMarker(id)) 13198 return this.markerId(); 13199 else 13200 return id; 13201 } 13202 movingItemsAdjustScreenPosition() { 13203 this.markersAdjustScreenPosition(); 13204 this.popoverAdjustScreenPosition(); 13205 this.bubblesRegionsAdjustScreenPosition(); 13206 this.labelsRegionsAdjustScreenPosition(); 13207 } 13208 movingItemsMoveScreenPositionBy(deltaX, deltaY) { 13209 this.markersMoveScreenPositionBy(deltaX, deltaY); 13210 this.popoverMoveScreenPositionBy(deltaX, deltaY); 13211 this.bubblesRegionsMoveScreenPositionBy(deltaX, deltaY); 13212 this.labelsRegionsMoveScreenPositionBy(deltaX, deltaY); 13213 } 13214 labelsRegionsAdjustScreenPosition() { 13215 if ($$A(this.containers.map).is(":visible")) { 13216 this.regions.forEach(function (region) { 13217 region.adjustLabelScreenPosition(); 13218 }); 13219 } 13220 } 13221 bubblesRegionsAdjustScreenPosition() { 13222 if ($$A(this.containers.map).is(":visible")) { 13223 this.regions.forEach(function (region) { 13224 region.adjustBubbleScreenPosition(); 13225 }); 13226 } 13227 } 13228 labelsRegionsMoveScreenPositionBy(deltaX, deltaY) { 13229 if ($$A(this.containers.map).is(":visible")) { 13230 this.regions.forEach(function (region) { 13231 region.moveLabelScreenPositionBy(deltaX, deltaY); 13232 }); 13233 } 13234 } 13235 bubblesRegionsMoveScreenPositionBy(deltaX, deltaY) { 13236 if ($$A(this.containers.map).is(":visible")) { 13237 this.regions.forEach((region) => { 13238 region.moveBubbleScreenPositionBy(deltaX, deltaY); 13239 }); 13240 } 13241 } 13242 markersAdjustScreenPosition() {
13243 this.markers.forEach((marker) => { 13244 marker.adjustScreenPosition(); 13245 }); 13246 this.markersClusters.forEach((cluster) => { 13247 cluster.adjustScreenPosition(); 13248 }); 13249 if (this.userLocationMarker) { 13250 this.userLocationMarker.adjustScreenPosition(); 13251 } 13252 } 13253 markersMoveScreenPositionBy(deltaX, deltaY) { 13254 this.markers.forEach((marker) => { 13255 marker.moveSrceenPositionBy(deltaX, deltaY); 13256 }); 13257 this.markersClusters.forEach((cluster) => { 13258 cluster.moveSrceenPositionBy(deltaX, deltaY); 13259 }); 13260 if (this.userLocationMarker) { 13261 this.userLocationMarker.moveSrceenPositionBy(deltaX, deltaY); 13262 } 13263 } 13264 setEditingMarker(marker) { 13265 this.editingMarker = marker; 13266 if (!this.editingMarker.mapped) { 13267 this.editingMarker.needToRemove = true; 13268 this.markerAdd(this.editingMarker); 13269 } 13270 } 13271 unsetEditingMarker() { 13272 if (this.editingMarker && this.editingMarker.needToRemove) { 13273 this.markerRemove(this.editingMarker); 13274 } 13275 this.editingMarker = null; 13276 } 13277 getEditingMarker() { 13278 return this.editingMarker; 13279 } 13280 scrollStart(e, mapsvg) { 13281 if ($$A(e.target).hasClass("mapsvg-btn-map") || 13282 $$A(e.target).closest(".mapsvg-choropleth").length) 13283 return; 13284 if (this.editMarkers.on && $$A(e.target).hasClass("mapsvg-marker")) 13285 return; 13286 e.preventDefault(); 13287 $$A(this.containers.map).addClass("no-transitions"); 13288 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13289 ? e.originalEvent.touches[0] 13290 : e; 13291 this.scrollStarted = true; 13292 this.scroll = { 13293 tx: this.scroll.tx || 0, 13294 ty: this.scroll.ty || 0, 13295 vxi: this.viewBox.x, 13296 vyi: this.viewBox.y, 13297 x: ce.clientX, 13298 y: ce.clientY, 13299 dx: 0, 13300 dy: 0, 13301 vx: 0, 13302 vy: 0, 13303 gx: ce.clientX, 13304 gy: ce.clientY, 13305 touchScrollStart: 0, 13306 }; 13307 if (e.type.indexOf("mouse") === 0) { 13308 $$A(document).on("mousemove.scroll.mapsvg", (e) => { 13309 this.scrollMove(e); 13310 }); 13311 if (this.options.scroll.spacebar) { 13312 $$A(document).on("keyup.scroll.mapsvg", (e) => { 13313 if (e.keyCode == 32) { 13314 this.scrollEnd(e, mapsvg); 13315 } 13316 }); 13317 } 13318 else { 13319 $$A(document).on("mouseup.scroll.mapsvg", (e) => { 13320 this.scrollEnd(e, mapsvg); 13321 }); 13322 } 13323 } 13324 } 13325 scrollMove(e) { 13326 e.preventDefault(); 13327 if (!this.isScrolling) { 13328 this.isScrolling = true; 13329 $$A(this.containers.map).addClass("scrolling"); 13330 } 13331 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13332 ? e.originalEvent.touches[0] 13333 : e; 13334 this.panBy(this.scroll.gx - ce.clientX, this.scroll.gy - ce.clientY); 13335 this.scroll.gx = ce.clientX; 13336 this.scroll.gy = ce.clientY; 13337 this.scroll.dx = this.scroll.x - ce.clientX; 13338 this.scroll.dy = this.scroll.y - ce.clientY; 13339 let vx = this.scroll.vxi + this.scroll.dx / this.scale; 13340 let vy = this.scroll.vyi + this.scroll.dy / this.scale; 13341 if (this.options.scroll.limit) { 13342 if (vx < this.svgDefault.viewBox.x) 13343 vx = this.svgDefault.viewBox.x; 13344 else if (this.viewBox.width + vx > 13345 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13346 vx = this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - this.viewBox.width; 13347 if (vy < this.svgDefault.viewBox.y) 13348 vy = this.svgDefault.viewBox.y; 13349 else if (this.viewBox.height + vy > 13350 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13351 vy = 13352 this.svgDefault.viewBox.y + 13353 this.svgDefault.viewBox.height - 13354 this.viewBox.height; 13355 } 13356 this.scroll.vx = vx; 13357 this.scroll.vy = vy; 13358 } 13359 scrollEnd(e, mapsvg, noClick) { 13360 setTimeout(() => { 13361 this.enableTransitions(); 13362 this.scrollStarted = false;
13363 this.isScrolling = false; 13364 }, 100); 13365 if (this.googleMaps && this.googleMaps.overlay) { 13366 this.googleMaps.overlay.draw(); 13367 } 13368 $$A(this.containers.map).removeClass("scrolling"); 13369 $$A(document).off("keyup.scroll.mapsvg"); 13370 $$A(document).off("mousemove.scroll.mapsvg"); 13371 $$A(document).off("mouseup.scroll.mapsvg"); 13372 if (noClick !== true && Math.abs(this.scroll.dx) < 5 && Math.abs(this.scroll.dy) < 5) { 13373 if (this.editMarkers.on) 13374 this.clickAddsMarker && this.markerAddClickHandler(e); 13375 else if (this.objectClickedBeforeScroll) 13376 if (this.objectClickedBeforeScroll instanceof Marker) { 13377 this.markerClickHandler(e, this.objectClickedBeforeScroll); 13378 } 13379 else if (this.objectClickedBeforeScroll instanceof Region) { 13380 this.regionClickHandler(e, this.objectClickedBeforeScroll); 13381 } 13382 else if (this.objectClickedBeforeScroll instanceof MarkerCluster) { 13383 this.markerClusterClickHandler(e, this.objectClickedBeforeScroll); 13384 } 13385 } 13386 this.viewBox.x = this.scroll.vx || this.viewBox.x; 13387 this.viewBox.y = this.scroll.vy || this.viewBox.y; 13388 } 13389 setViewBoxByGoogleMapsOverlay() { 13390 const bounds = this.googleMaps.overlay.getPixelBounds(); 13391 const scale = (bounds.ne.x - bounds.sw.x) / this.svgDefault.viewBox.width; 13392 const vb = new ViewBox(this.svgDefault.viewBox.x - bounds.sw.x / scale, this.svgDefault.viewBox.y - bounds.ne.y / scale, this.containers.map.offsetWidth / scale, this.containers.map.offsetHeight / scale); 13393 this.setViewBox(vb, false); 13394 } 13395 panBy(x, y) { 13396 let tx = this.scroll.tx - x; 13397 let ty = this.scroll.ty - y; 13398 const scrolled = { x: true, y: true }; 13399 if (this.options.scroll.limit) { 13400 const svg = $$A(this.containers.svg)[0].getBoundingClientRect(); 13401 const bounds = $$A(this.containers.map)[0].getBoundingClientRect(); 13402 if ((svg.left - x > bounds.left && x < 0) || (svg.right - x < bounds.right && x > 0)) { 13403 tx = this.scroll.tx; 13404 scrolled.x = false; 13405 } 13406 if ((svg.top - y > bounds.top && y < 0) || (svg.bottom - y < bounds.bottom && y > 0)) { 13407 ty = this.scroll.ty; 13408 scrolled.y = false; 13409 } 13410 } 13411 $$A(this.containers.scrollpane).css({ 13412 transform: "translate(" + tx + "px," + ty + "px)", 13413 }); 13414 this.scroll.tx = tx; 13415 this.scroll.ty = ty; 13416 if (scrolled.x || scrolled.y) { 13417 const moveX = scrolled.x ? x : 0; 13418 const moveY = scrolled.y ? y : 0; 13419 this.movingItemsMoveScreenPositionBy(moveX, moveY); 13420 if (this.googleMaps.map) { 13421 let point = this.googleMaps.map.getCenter(); 13422 const projection = this.googleMaps.overlay.getProjection(); 13423 const pixelpoint = projection.fromLatLngToDivPixel(point); 13424 pixelpoint.x += moveX; 13425 pixelpoint.y += moveY; 13426 point = projection.fromDivPixelToLatLng(pixelpoint); 13427 this.googleMaps.map.setCenter(point); 13428 } 13429 } 13430 return scrolled; 13431 } 13432 setObjectClickedBeforeScroll(object) { 13433 this.objectClickedBeforeScroll = object; 13434 } 13435 touchStart(_e, mapsvg) { 13436 _e.preventDefault(); 13437 if (this.scrollStarted) { 13438 this.scrollEnd(_e, mapsvg, true); 13439 } 13440 const e = _e.originalEvent; 13441 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13442 this.touchZoomStart = true; 13443 this.scaleDistStart = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY); 13444 } 13445 else if (e.touches && e.touches.length == 1) { 13446 this.scrollStart(_e, mapsvg); 13447 } 13448 $$A(document) 13449 .on("touchmove.scroll.mapsvg", (e) => { 13450 e.preventDefault(); 13451 this.touchMove(e, this); 13452 }) 13453 .on("touchend.scroll.mapsvg", (e) => { 13454 e.preventDefault(); 13455 this.touchEnd(e, this); 13456 }); 13457 } 13458 touchMove(_e, mapsvg) { 13459 _e.preventDefault(); 13460 const e = _e.originalEvent; 13461 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13462 if (!MapSVG.ios) { 13463 e.scale = 13464 Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY) / this.scaleDistStart; 13465 } 13466 if (e.scale != 1 && this.canZoom) { 13467 const d = e.scale > 1 ? 1 : -1; 13468 const cx = e.touches[0].pageX >= e.touches[1].pageX 13469 ? e.touches[0].pageX - 13470 (e.touches[0].pageX - e.touches[1].pageX) / 2 - 13471 $$A(this.containers.map).offset().left 13472 : e.touches[1].pageX - 13473 (e.touches[1].pageX - e.touches[0].pageX) / 2 - 13474 $$A(this.containers.map).offset().left; 13475 const cy = e.touches[0].pageY >= e.touches[1].pageY 13476 ? e.touches[0].pageY - 13477 (e.touches[0].pageY - e.touches[1].pageY) - 13478 $$A(this.containers.map).offset().top 13479 : e.touches[1].pageY - 13480 (e.touches[1].pageY - e.touches[0].pageY) - 13481 $$A(this.containers.map).offset().top; 13482 const center = this.converter.convertPixelToSVG(new ScreenPoint(cx, cy)); 13483 if (d > 0) 13484 this.zoomIn(center); 13485 else 13486 this.zoomOut(center); 13487 } 13488 } 13489 else if (e.touches && e.touches.length == 1) { 13490 this.scrollMove(_e); 13491 } 13492 } 13493 touchEnd(_e, mapsvg) { 13494 _e.preventDefault(); 13495 const e = _e.originalEvent; 13496 if (this.touchZoomStart) { 13497 this.touchZoomStart = false;
13498 } 13499 else if (this.scrollStarted) { 13500 this.scrollEnd(_e, mapsvg); 13501 } 13502 $$A(document).off("touchmove.scroll.mapsvg"); 13503 $$A(document).off("touchend.scroll.mapsvg"); 13504 } 13505 getSelected() { 13506 return this.selected_id; 13507 } 13508 selectRegion(id, skipDirectorySelection) { 13509 let region; 13510 if (typeof id == "string") { 13511 region = this.getRegion(id); 13512 } 13513 else { 13514 region = id; 13515 } 13516 if (!region) 13517 return; 13518 let ids; 13519 if (this.options.multiSelect && !this.editRegions.on) { 13520 if (region.selected) { 13521 this.deselectRegion(region); 13522 if (!skipDirectorySelection && this.options.menu.on) { 13523 if (this.options.menu.source == "database") { 13524 if (region.objects && region.objects.length) { 13525 ids = region.objects.map((obj) => { 13526 return obj.id.toString(); 13527 }); 13528 } 13529 } 13530 else { 13531 ids = [region.id]; 13532 } 13533 this.controllers.directory.deselectItems(); 13534 } 13535 return; 13536 } 13537 } 13538 else if (this.selected_id.length > 0) { 13539 this.deselectAllRegions(); 13540 if (!skipDirectorySelection && this.options.menu.on) { 13541 if (this.options.menu.source == "database") { 13542 if (region.objects && region.objects.length) { 13543 ids = region.objects.map((obj) => { 13544 return obj.id.toString(); 13545 }); 13546 } 13547 } 13548 else { 13549 ids = [region.id]; 13550 } 13551 this.controllers.directory.deselectItems(); 13552 } 13553 } 13554 this.selected_id.push(region.id); 13555 region.select(); 13556 const skip = this.options.actions.region.click.filterDirectory; 13557 if (!skip && 13558 !skipDirectorySelection && 13559 this.options.menu.on && 13560 this.controllers && 13561 this.controllers.directory) { 13562 if (this.options.menu.source == "database") { 13563 if (region.objects && region.objects.length) { 13564 ids = region.objects.map((obj) => { 13565 return obj.id.toString(); 13566 }); 13567 } 13568 else { 13569 ids = [region.id]; 13570 } 13571 } 13572 else { 13573 ids = [region.id]; 13574 } 13575 this.controllers.directory.selectItems(ids); 13576 } 13577 if (this.options.actions.region.click.addIdToUrl && 13578 !this.options.actions.region.click.showAnotherMap) { 13579 window.location.hash = "/m/" + region.id; 13580 } 13581 } 13582 deselectAllRegions() { 13583 $$A.each(this.selected_id, (index, id) => { 13584 this.deselectRegion(this.getRegion(id)); 13585 }); 13586 } 13587 deselectRegion(region) { 13588 if (!region) 13589 region = this.getRegion(this.selected_id[0]); 13590 if (region) { 13591 region.deselect(); 13592 const i = $$A.inArray(region.id, this.selected_id); 13593 this.selected_id.splice(i, 1); 13594 } 13595 if (this.options.actions.region.click.addIdToUrl) { 13596 if (window.location.hash.indexOf(region.id) !== -1) { 13597 history.replaceState(null, null, " "); 13598 } 13599 } 13600 } 13601 highlightRegions(regions) { 13602 regions.forEach((region) => { 13603 if (region && !region.selected && !region.disabled) { 13604 this.highlightedRegions.push(region); 13605 region.highlight(); 13606 } 13607 }); 13608 } 13609 unhighlightRegions() { 13610 this.highlightedRegions.forEach((region) => { 13611 if (region && !region.selected && !region.disabled) 13612 region.unhighlight(); 13613 }); 13614 this.highlightedRegions = []; 13615 } 13616 selectMarker(marker) { 13617 if (!(marker instanceof Marker)) 13618 return; 13619 this.deselectAllMarkers(); 13620 marker.select(); 13621 this.selected_marker = marker; 13622 $$A(this.layers.markers).addClass("mapsvg-with-marker-active"); 13623 if (this.options.menu.on && this.options.menu.source == "database") { 13624 this.controllers.directory.deselectItems(); 13625 this.controllers.directory.selectItems(marker.object.id); 13626 } 13627 } 13628 deselectAllMarkers() { 13629 this.selected_marker && this.selected_marker.deselect(); 13630 $$A(this.layers.markers).removeClass("mapsvg-with-marker-active"); 13631 } 13632 deselectMarker(marker) { 13633 if (marker) { 13634 marker.deselect(); 13635 } 13636 } 13637 highlightMarker(marker) { 13638 $$A(this.layers.markers).addClass("mapsvg-with-marker-hover"); 13639 marker.highlight(); 13640 this.highlighted_marker = marker; 13641 } 13642 unhighlightMarker() { 13643 $$A(this.layers.markers).removeClass("mapsvg-with-marker-hover"); 13644 this.highlighted_marker && this.highlighted_marker.unhighlight(); 13645 } 13646 convertMouseToSVG(e) { 13647 const mc = MapSVG.mouseCoords(e); 13648 const x = mc.x - $$A(this.containers.map).offset().left; 13649 const y = mc.y - $$A(this.containers.map).offset().top; 13650 const screenPoint = new ScreenPoint(x, y); 13651 return this.converter.convertPixelToSVG(screenPoint); 13652 } 13653 pickChoroplethColor(choroplethValue) { 13654 const w = (choroplethValue - this.options.choropleth.coloring.gradient.values.min) / 13655 this.options.choropleth.coloring.gradient.values.maxAdjusted; 13656 const rgba = { 13657 r: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.r * w + 13658 this.options.choropleth.coloring.gradient.colors.lowRGB.r), 13659 g: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.g * w + 13660 this.options.choropleth.coloring.gradient.colors.lowRGB.g), 13661 b: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.b * w + 13662 this.options.choropleth.coloring.gradient.colors.lowRGB.b), 13663 a: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.a * w + 13664 this.options.choropleth.coloring.gradient.colors.lowRGB.a), 13665 }; 13666 return rgba; 13667 } 13668 isRegionDisabled(id, svgfill) { 13669 if (this.options.regions[id] && (this.options.regions[id].disabled || svgfill == "none")) { 13670 return true; 13671 } 13672 else if ((this.options.regions[id] == undefined || 13673 MapSVG.parseBoolean(this.options.regions[id].disabled)) && 13674 (this.options.disableAll || svgfill == "none" || id == "labels" || id == "Labels")) { 13675 return true; 13676 } 13677 else { 13678 return false;
13679 } 13680 } 13681 loadMap(id, container) { 13682 if (!(container instanceof HTMLElement)) { 13683 console.error("Can't load a new map: container was not provided."); 13684 return; 13685 } 13686 const previousMapsIds = [...this.options.previousMapsIds]; 13687 const currentMapId = this.id; 13688 if (previousMapsIds[previousMapsIds.length - 1] !== id) { 13689 previousMapsIds.push(currentMapId); 13690 } 13691 else { 13692 previousMapsIds.pop(); 13693 } 13694 let showPreviousMapButton; 13695 if (this.options.actions.region.click.region.showAnotherMapContainerId !== "undefined") { 13696 showPreviousMapButton = false; 13697 } 13698 else { 13699 showPreviousMapButton = this.options.controls.previousMap; 13700 } 13701 const mapsRepo = new MapsRepository(); 13702 mapsRepo.findById(id).done((map) => { 13703 this.destroy(); 13704 const newMap = new MapSVGMap(container.getAttribute("id"), map); 13705 newMap.options.previousMapsIds = previousMapsIds; 13706 newMap.options.controls.previousMap = showPreviousMapButton; 13707 newMap.setControls(newMap.options.controls); 13708 }); 13709 } 13710 loadPreviousMap() { 13711 const previousMapId = this.options.previousMapsIds[this.options.previousMapsIds.length - 1]; 13712 const container = document.getElementById(this.containerId); 13713 this.loadMap(previousMapId, container); 13714 } 13715 markerClusterClickHandler(e, markerCluster) { 13716 this.objectClickedBeforeScroll = null; 13717 if (this.eventsPreventList["click"]) 13718 return; 13719 this.zoomTo(markerCluster.markers); 13720 return; 13721 } 13722 regionClickHandler(e, region) { 13723 this.objectClickedBeforeScroll = null; 13724 if (this.eventsPreventList["click"]) 13725 return; 13726 this.selectRegion(region.id); 13727 if (this.editRegions.on) { 13728 this.regionEditHandler.call(region); 13729 return; 13730 } 13731 const actions = this.options.actions; 13732 if (actions.region.click.zoom) { 13733 this.zoomTo(region, parseInt(actions.region.click.zoomToLevel)); 13734 } 13735 if (actions.region.click.filterDirectory) { 13736 const query = new Query({ 13737 filters: { 13738 regions: { 13739 table_name: this.regionsRepository.getSchema().name, 13740 region_ids: [region.id], 13741 }, 13742 }, 13743 }); 13744 this.objectsRepository.find(query).done(() => { 13745 if (this.controllers.popover) { 13746 this.controllers.popover.redraw(region.forTemplate()); 13747 } 13748 if (this.controllers.detailsView) { 13749 this.controllers.detailsView.redraw(region.forTemplate()); 13750 } 13751 }); 13752 this.updateFiltersState(); 13753 }
13754 if (actions.region.click.showDetails) { 13755 this.loadDetailsView(region); 13756 } 13757 if (actions.region.click.showPopover) { 13758 if (actions.region.click.zoom) { 13759 setTimeout(() => { 13760 this.showPopover(region); 13761 }, 400); 13762 } 13763 else { 13764 this.showPopover(region); 13765 } 13766 } 13767 else if (e && e.type.indexOf("touch") !== -1 && actions.region.touch.showPopover) { 13768 if (actions.region.click.zoom) { 13769 setTimeout(() => { 13770 this.showPopover(region); 13771 }, 400); 13772 } 13773 else { 13774 this.showPopover(region); 13775 } 13776 } 13777 if (actions.region.click.goToLink) { 13778 const linkParts = actions.region.click.linkField.split("."); 13779 let url; 13780 if (linkParts.length > 1) { 13781 const obj = linkParts.shift(); 13782 const attr = "." + linkParts.join("."); 13783 if (obj == "Region") { 13784 if (region.data) { 13785 try { 13786 url = eval("region.data" + attr); 13787 } 13788 catch (err) { 13789 console.log("No such field as region.data" + attr); 13790 } 13791 } 13792 } 13793 else { 13794 if (region.objects && region.objects[0]) { 13795 try { 13796 url = eval("region.objects[0]" + attr); 13797 } 13798 catch (err) { 13799 console.log("No such field as region.objects[0]" + attr); 13800 } 13801 } 13802 } 13803 if (url && !this.disableLinks) { 13804 if (this.editMode) { 13805 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 13806 return; 13807 } 13808 if (actions.region.click.newTab) { 13809 const win = window.open(url, "_blank"); 13810 win.focus(); 13811 } 13812 else { 13813 window.location.href = url; 13814 } 13815 } 13816 } 13817 } 13818 if (actions.region.click.showAnotherMap) { 13819 if (this.editMode) { 13820 alert('"Show another map" action is disabled in the preview'); 13821 return; 13822 } 13823 const linkParts = actions.region.click.showAnotherMapField.split("."); 13824 if (linkParts.length > 1) { 13825 const obj = linkParts.shift(); 13826 const attr = "." + linkParts.join("."); 13827 let map_id; 13828 if (obj == "Region") { 13829 if (region.data) 13830 map_id = eval("region.data" + attr); 13831 } 13832 else { 13833 if (region.objects && region.objects[0]) 13834 map_id = eval("region.objects[0]" + attr); 13835 } 13836 if (map_id) { 13837 const container = actions.region.click.showAnotherMapContainerId 13838 ? $$A("#" + actions.region.click.showAnotherMapContainerId)[0] 13839 : $$A(this.containers.map)[0]; 13840 this.loadMap(map_id, container); 13841 } 13842 } 13843 } 13844 this.events.trigger("click.region", region, [e, region, this]); 13845 } 13846 markerClickHandler(e, marker) { 13847 this.objectClickedBeforeScroll = null; 13848 if (this.eventsPreventList["click"]) 13849 return; 13850 const actions = this.options.actions; 13851 this.selectMarker(marker); 13852 const passingObject = marker.object; 13853 if (actions.marker.click.zoom) { 13854 this.zoomTo(marker, parseInt(actions.marker.click.zoomToLevel)); 13855 } 13856 if (actions.marker.click.filterDirectory) { 13857 const query = new Query({ filters: { id: marker.object.id } }); 13858 this.objectsRepository.find(query); 13859 this.updateFiltersState(); 13860 }
13861 if (actions.marker.click.showDetails) 13862 this.loadDetailsView(passingObject); 13863 if (actions.marker.click.showPopover) { 13864 if (actions.marker.click.zoom) { 13865 setTimeout(() => { 13866 this.showPopover(passingObject); 13867 }, 500); 13868 } 13869 else { 13870 this.showPopover(passingObject); 13871 } 13872 } 13873 else if (e && e.type.indexOf("touch") !== -1 && actions.marker.touch.showPopover) { 13874 if (actions.marker.click.zoom) { 13875 setTimeout(() => { 13876 this.showPopover(passingObject); 13877 }, 500); 13878 } 13879 else { 13880 this.showPopover(passingObject); 13881 } 13882 } 13883 if (actions.marker.click.goToLink) { 13884 const linkParts = actions.marker.click.linkField.split("."); 13885 let url; 13886 if (linkParts.length > 1) { 13887 const obj = linkParts.shift(); 13888 const attr = "." + linkParts.join("."); 13889 try { 13890 url = eval("passingObject" + attr); 13891 } 13892 catch (err) { 13893 console.log("MapSVG: No such field as passingObject" + attr); 13894 } 13895 if (url && !this.disableLinks) 13896 if (this.editMode) { 13897 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 13898 return; 13899 } 13900 if (actions.marker.click.newTab) { 13901 const win = window.open(url, "_blank"); 13902 win.focus(); 13903 } 13904 else { 13905 window.location.href = url; 13906 } 13907 } 13908 } 13909 this.events.trigger("click.marker", marker, [e, marker, this]); 13910 } 13911 fileExists(url) { 13912 if (url.substr(0, 4) == "data") 13913 return true; 13914 const http = new XMLHttpRequest(); 13915 http.open("HEAD", url, false); 13916 http.send(); 13917 return http.status != 404; 13918 } 13919 hideMarkers() { 13920 this.markers.forEach(function (marker) { 13921 marker.hide(); 13922 }); 13923 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 13924 } 13925 hideMarkersExceptOne(id) { 13926 this.markers.forEach(function (marker) { 13927 if (typeof id === "undefined" || (marker.object && id != marker.object.id)) { 13928 marker.hide(); 13929 } 13930 }); 13931 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 13932 } 13933 showMarkers() { 13934 this.markers.forEach(function (m) { 13935 m.show(); 13936 }); 13937 this.deselectAllMarkers(); 13938 $$A(this.containers.wrap).removeClass("mapsvg-edit-marker-mode"); 13939 } 13940 markerAddClickHandler(e) { 13941 if ($$A(e.target).hasClass("mapsvg-marker")) 13942 return; 13943 const svgPoint = this.getSvgPointAtClick(e); 13944 const geoPoint = this.isGeo() ? this.converter.convertSVGToGeo(svgPoint) : null; 13945 if (!$$A.isNumeric(svgPoint.x) || !$$A.isNumeric(svgPoint.y)) 13946 return; 13947 if (this.editingMarker) { 13948 if (geoPoint) { 13949 this.editingMarker.location.setGeoPoint(geoPoint); 13950 } 13951 else { 13952 this.editingMarker.location.setSvgPoint(svgPoint); 13953 } 13954 return; 13955 } 13956 const location = new Location({ 13957 svgPoint: svgPoint, 13958 geoPoint: geoPoint, 13959 img: this.options.defaultMarkerImage, 13960 }); 13961 const marker = new Marker({ 13962 location: location, 13963 mapsvg: this, 13964 }); 13965 this.markerAdd(marker); 13966 this.markerEditHandler && this.markerEditHandler.call(location, location); 13967 } 13968 getSvgPointAtClick(e) { 13969 const mc = MapSVG.mouseCoords(e); 13970 const x = mc.x - $$A(this.containers.map).offset().left; 13971 const y = mc.y - $$A(this.containers.map).offset().top; 13972 const screenPoint = new ScreenPoint(x, y); 13973 return this.converter.convertPixelToSVG(screenPoint); 13974 } 13975 setDefaultMarkerImage(src) { 13976 this.options.defaultMarkerImage = src; 13977 } 13978 setMarkerImagesDependency() { 13979 this.locationField = this.objectsRepository.schema.getFieldByType("location"); 13980 if (this.locationField.markersByFieldEnabled && 13981 this.locationField.markerField && 13982 Object.values(this.locationField.markersByField).length > 0) { 13983 this.setMarkersByField = true; 13984 } 13985 else { 13986 this.setMarkersByField = false;
13987 } 13988 } 13989 getMarkerImage(fieldValueOrObject, location) { 13990 let fieldValue; 13991 if (this.setMarkersByField) { 13992 if (typeof fieldValueOrObject === "object") { 13993 fieldValue = fieldValueOrObject[this.locationField.markerField]; 13994 } 13995 else { 13996 fieldValue = fieldValueOrObject; 13997 } 13998 if (this.locationField.markersByField[fieldValue]) { 13999 return this.locationField.markersByField[fieldValue]; 14000 } 14001 } 14002 return location && location.img 14003 ? location.img 14004 : this.options.defaultMarkerImage 14005 ? this.options.defaultMarkerImage 14006 : MapSVG.urls.root + "markers/_pin_default.png"; 14007 } 14008 setMarkersEditMode(on, clickAddsMarker) { 14009 this.editMarkers.on = MapSVG.parseBoolean(on); 14010 this.clickAddsMarker = this.editMarkers.on; 14011 this.setEventHandlers(); 14012 } 14013 setRegionsEditMode(on) { 14014 this.editRegions.on = MapSVG.parseBoolean(on); 14015 this.deselectAllRegions(); 14016 this.setEventHandlers(); 14017 } 14018 setEditMode(on) { 14019 this.editMode = on; 14020 } 14021 setDataEditMode(on) { 14022 this.editData.on = MapSVG.parseBoolean(on); 14023 this.deselectAllRegions(); 14024 this.setEventHandlers(); 14025 } 14026 popoverAdjustScreenPosition() { 14027 if (this.controllers.popover instanceof PopoverController) { 14028 this.controllers.popover.adjustScreenPosition(); 14029 } 14030 } 14031 popoverMoveScreenPositionBy(deltaX, deltaY) { 14032 if (this.controllers.popover instanceof PopoverController) { 14033 this.controllers.popover.moveSrceenPositionBy(deltaX, deltaY); 14034 } 14035 } 14036 showPopover(object) { 14037 const mapObject = object instanceof Region 14038 ? object 14039 : object.location && object.location.marker 14040 ? object.location.marker 14041 : null; 14042 if (!mapObject) 14043 return; 14044 let point; 14045 if (mapObject instanceof Marker) { 14046 point = mapObject.svgPoint; 14047 } 14048 else { 14049 point = mapObject.getCenterSVG(); 14050 } 14051 this.controllers.popover && this.controllers.popover.destroy(); 14052 this.controllers.popover = new PopoverController({ 14053 container: this.containers.popover, 14054 point: point, 14055 yShift: mapObject instanceof Marker ? mapObject.height : 0, 14056 template: object instanceof Region 14057 ? this.options.templates.popoverRegion 14058 : this.options.templates.popoverMarker, 14059 mapsvg: this, 14060 data: object.getData(), 14061 mapObject: mapObject, 14062 scrollable: true, 14063 withToolbar: !(MapSVG.isPhone && this.options.popovers.mobileFullscreen), 14064 events: { 14065 shown: (popover) => { 14066 if (this.options.popovers.centerOn) { 14067 const shift = popover.containers.main.offsetHeight / 2; 14068 if (this.options.popovers.centerOn && 14069 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14070 this.centerOn(mapObject, shift); 14071 } 14072 } 14073 this.popoverShowingFor = mapObject; 14074 this.events.trigger("shown.popover", this, [this, popover]); 14075 $$A(window).trigger("shown.popover", [this, popover]); 14076 }, 14077 closed: (popover) => { 14078 this.options.popovers.resetViewboxOnClose && this.viewBoxReset(true); 14079 this.popoverShowingFor = null; 14080 this.events.trigger("closed.popover", this, [this, popover]); 14081 }, 14082 resize: (popover) => { 14083 if (this.options.popovers.centerOn) { 14084 const shift = popover.containers.main.offsetHeight / 2; 14085 if (this.options.popovers.centerOn && 14086 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14087 this.centerOn(mapObject, shift); 14088 } 14089 } 14090 }, 14091 }, 14092 }); 14093 this.controllers.popover._init(); 14094 } 14095 hidePopover() { 14096 this.controllers.popover && this.controllers.popover.close(); 14097 } 14098 popoverOffHandler(e) { 14099 if (this.isScrolling || 14100 $$A(e.target).closest(".mapsvg-popover").length || 14101 $$A(e.target).hasClass("mapsvg-btn-map")) 14102 return; 14103 this.controllers.popover && this.controllers.popover.close(); 14104 } 14105 mouseOverHandler(e, object) { 14106 if (this.eventsPreventList["mouseover"]) { 14107 return; 14108 } 14109 if (object instanceof Marker) { 14110 if (this.options.actions.marker.mouseover.showTooltip) { 14111 this.showTooltip(object); 14112 } 14113 } 14114 if (object instanceof Region) { 14115 if (this.options.actions.region.mouseover.showTooltip) { 14116 this.showTooltip(object); 14117 } 14118 } 14119 let ids; 14120 if (this.options.menu.on) { 14121 if (this.options.menu.source == "database") { 14122 if (object instanceof Region && object.objects.length) { 14123 ids = object.objects.map((obj) => { 14124 return obj.id; 14125 }); 14126 } 14127 if (object instanceof Marker) { 14128 ids = object.object ? [object.object.id] : []; 14129 } 14130 } 14131 else { 14132 if (object instanceof Region) { 14133 ids = [object.id]; 14134 } 14135 if (this instanceof Marker && 14136 object.object.regions && 14137 object.object.regions.length) { 14138 ids = object.object.regions.map((obj) => { 14139 return obj.id; 14140 }); 14141 } 14142 } 14143 this.controllers.directory.highlightItems(ids); 14144 } 14145 if (object instanceof Region) { 14146 if (!object.selected) 14147 object.highlight(); 14148 this.events.trigger("mouseover.region", object, [e, this]); 14149 } 14150 else { 14151 this.highlightMarker(object); 14152 this.events.trigger("mouseover.marker", object, [e, this]); 14153 } 14154 } 14155 showTooltip(object) { 14156 let name, _object; 14157 if (object instanceof Region) { 14158 name = "tooltipRegion"; 14159 _object = object; 14160 } 14161 else if (object instanceof Marker) { 14162 name = "tooltipMarker"; 14163 _object = object.object; 14164 } 14165 else { 14166 name = "tooltipMarker"; 14167 _object = object; 14168 } 14169 if (_object != null && this.popoverShowingFor !== object) { 14170 this.controllers.tooltip.setMainTemplate(this.options.templates[name]); 14171 this.controllers.tooltip.redraw(_object.getData()); 14172 this.controllers.tooltip.show(); 14173 } 14174 } 14175 mouseOutHandler(e, object) { 14176 if (this.eventsPreventList["mouseout"]) { 14177 return; 14178 } 14179 if (this.controllers.tooltip) 14180 this.controllers.tooltip.hide(); 14181 if (object instanceof Region) { 14182 if (!object.selected) 14183 object.unhighlight(); 14184 this.events.trigger("mouseout.region", object, [e, this]); 14185 } 14186 else { 14187 this.unhighlightMarker(); 14188 this.events.trigger("mouseout.marker", object, [e, this]); 14189 } 14190 let ids; 14191 if (this.options.menu.on) { 14192 if (this.options.menu.source == "database") { 14193 if (object instanceof Marker) { 14194 const marker = object; 14195 ids = marker.object ? [marker.object.id] : []; 14196 } 14197 } 14198 this.controllers.directory.unhighlightItems(); 14199 } 14200 } 14201 eventsPrevent(event) { 14202 this.eventsPreventList[event] = true; 14203 } 14204 eventsRestore(event) { 14205 if (event) { 14206 this.eventsPreventList[event] = false;
14207 } 14208 else { 14209 this.eventsPreventList = {}; 14210 } 14211 } 14212 setEventHandlers() { 14213 const _this = this; 14214 $$A(_this.containers.map).off(".common.mapsvg"); 14215 $$A(_this.containers.scrollpane).off(".common.mapsvg"); 14216 $$A(document).off("keydown.scroll.mapsvg"); 14217 $$A(document).off("mousemove.scrollInit.mapsvg"); 14218 $$A(document).off("mouseup.scrollInit.mapsvg"); 14219 if (_this.editMarkers.on) { 14220 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", ".mapsvg-marker", function (e) { 14221 e.originalEvent.preventDefault(); 14222 const marker = _this.getMarker($$A(this).attr("id")); 14223 const startCoords = MapSVG.mouseCoords(e); 14224 marker.drag(startCoords, _this.scale); 14225 }); 14226 } 14227 if (!_this.editMarkers.on) { 14228 $$A(_this.containers.map) 14229 .on("mouseover.common.mapsvg", ".mapsvg-region", function (e) { 14230 const id = $$A(this).attr("id"); 14231 _this.mouseOverHandler.call(_this, e, _this.getRegion(id)); 14232 }) 14233 .on("mouseleave.common.mapsvg", ".mapsvg-region", function (e) { 14234 const id = $$A(this).attr("id"); 14235 _this.mouseOutHandler.call(_this, e, _this.getRegion(id)); 14236 }); 14237 } 14238 if (!_this.editRegions.on) { 14239 $$A(_this.containers.map) 14240 .on("mouseover.common.mapsvg", ".mapsvg-marker", function (e) { 14241 const id = $$A(this).attr("id"); 14242 _this.mouseOverHandler.call(_this, e, _this.getMarker(id)); 14243 }) 14244 .on("mouseleave.common.mapsvg", ".mapsvg-marker", function (e) { 14245 const id = $$A(this).attr("id"); 14246 _this.mouseOutHandler.call(_this, e, _this.getMarker(id)); 14247 }); 14248 } 14249 if (_this.options.scroll.spacebar) { 14250 $$A(document).on("keydown.scroll.mapsvg", function (e) { 14251 if (document.activeElement.tagName !== "INPUT" && 14252 !_this.isScrolling && 14253 e.keyCode == 32) { 14254 e.preventDefault(); 14255 $$A(_this.containers.map).addClass("mapsvg-scrollable"); 14256 $$A(document) 14257 .on("mousemove.scrollInit.mapsvg", function (e) { 14258 _this.isScrolling = true; 14259 $$A(document).off("mousemove.scrollInit.mapsvg"); 14260 _this.scrollStart(e, _this); 14261 }) 14262 .on("keyup.scroll.mapsvg", function (e) { 14263 if (e.keyCode == 32) { 14264 $$A(document).off("mousemove.scrollInit.mapsvg"); 14265 $$A(_this.containers.map).removeClass("mapsvg-scrollable"); 14266 } 14267 }); 14268 } 14269 }); 14270 } 14271 else if (!_this.options.scroll.on) { 14272 if (!_this.editMarkers.on) { 14273 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-region", function (e) { 14274 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14275 }); 14276 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-marker", function (e) { 14277 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14278 }); 14279 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-region", function (e) { 14280 if (e.cancelable) { 14281 e.preventDefault(); 14282 } 14283 if (!_this.scroll.touchScrollStart || 14284 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14285 _this.regionClickHandler(e, _this.getRegion($$A(this).attr("id"))); 14286 } 14287 }); 14288 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker", function (e) { 14289 if (e.cancelable) { 14290 e.preventDefault(); 14291 } 14292 if (!_this.scroll.touchScrollStart || 14293 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14294 _this.markerClickHandler.call(_this, e, _this.getMarker($$A(this).attr("id"))); 14295 } 14296 }); 14297 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker-cluster", function (e) { 14298 if (e.cancelable) { 14299 e.preventDefault(); 14300 } 14301 if (!_this.scroll.touchScrollStart || 14302 _this.scroll.touchScrollStart == $$A(window).scrollTop()) { 14303 const cluster = $$A(this).data("cluster"); 14304 _this.zoomTo(cluster.markers); 14305 } 14306 }); 14307 } 14308 else { 14309 if (_this.clickAddsMarker) 14310 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", function (e) { 14311 if (e.cancelable) { 14312 e.preventDefault(); 14313 } 14314 _this.markerAddClickHandler(e); 14315 }); 14316 } 14317 } 14318 else { 14319 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", function (e) { 14320 if ($$A(e.target).hasClass("mapsvg-popover") || 14321 $$A(e.target).closest(".mapsvg-popover").length) { 14322 if ($$A(e.target).hasClass("mapsvg-popover-close")) { 14323 if (e.type == "touchstart") { 14324 if (e.cancelable) { 14325 e.preventDefault(); 14326 } 14327 } 14328 } 14329 return; 14330 } 14331 if (e.type == "touchstart") { 14332 if (e.cancelable) { 14333 e.preventDefault(); 14334 } 14335 } 14336 let obj; 14337 if (e.target && 14338 $$A(e.target).attr("class") && 14339 $$A(e.target).attr("class").indexOf("mapsvg-region") != -1) { 14340 obj = _this.getRegion($$A(e.target).attr("id")); 14341 _this.setObjectClickedBeforeScroll(obj); 14342 } 14343 else if (e.target && 14344 $$A(e.target).attr("class") && 14345 $$A(e.target).attr("class").indexOf("mapsvg-marker") != -1 && 14346 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster")
14346=== -1) { 14347 if (_this.editMarkers.on) { 14348 return; 14349 } 14350 obj = _this.getMarker($$A(e.target).attr("id")); 14351 _this.setObjectClickedBeforeScroll(obj); 14352 } 14353 else if (e.target && 14354 $$A(e.target).attr("class") && 14355 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster") != -1) { 14356 if (_this.editMarkers.on) { 14357 return; 14358 } 14359 obj = $$A(e.target).data("cluster"); 14360 _this.setObjectClickedBeforeScroll(obj); 14361 } 14362 if (e.type == "mousedown") { 14363 _this.scrollStart(e, _this); 14364 } 14365 else { 14366 _this.touchStart(e, _this); 14367 } 14368 }); 14369 } 14370 $$A(_this.containers.map).on("mouseleave.common.mapsvg", ".mapsvg-choropleth-gradient-wrap", (e) => { 14371 this.controllers.tooltip.hide(); 14372 }); 14373 } 14374 setLabelsRegions(options) { 14375 options = options || this.options.labelsRegions; 14376 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14377 $$A.extend(true, this.options, { labelsRegions: options }); 14378 if (this.options.labelsRegions.on) { 14379 this.regions.forEach((region) => { 14380 if (!region.label) { 14381 region.label = jQuery('<div class="mapsvg-region-label" />')[0]; 14382 $$A(this.layers.labels).append(region.label); 14383 } 14384 try { 14385 $$A(region.label).html(this.templates.labelRegion(region.forTemplate())); 14386 } 14387 catch (err) { 14388 console.error('MapSVG: Error in the "Region Label" template'); 14389 } 14390 }); 14391 this.labelsRegionsAdjustScreenPosition(); 14392 } 14393 else { 14394 this.regions.forEach((region) => { 14395 if (region.label) { 14396 $$A(region.label).remove(); 14397 region.label = null; 14398 delete region.label; 14399 } 14400 }); 14401 } 14402 } 14403 setLabelsMarkers(options) { 14404 options = options || this.options.labelsMarkers; 14405 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14406 $$A.extend(true, this.options, { labelsMarkers: options }); 14407 if (this.options.labelsMarkers.on) { 14408 this.markers.forEach((marker) => { 14409 try { 14410 marker.setLabel(this.templates.labelMarker(marker.object)); 14411 } 14412 catch (err) { 14413 console.error('MapSVG: Error in the "Marker Label" template'); 14414 } 14415 }); 14416 } 14417 } 14418 addLayer(name) { 14419 this.layers[name] = $$A('<div class="mapsvg-layer mapsvg-layer-' + name + '"></div>')[0]; 14420 this.containers.layers.appendChild(this.layers[name]); 14421 return this.layers[name]; 14422 } 14423 getLayer(name) { 14424 return this.layers[name]; 14425 } 14426 getDb() { 14427 return this.objectsRepository; 14428 } 14429 getDbRegions() { 14430 return this.regionsRepository; 14431 } 14432 regionAdd(svgObject) { 14433 const region = new Region(svgObject, this); 14434 region.setStatus(1); 14435 this.regions.push(region); 14436 this.regions.sort(function (a, b) { 14437 return a.id == b.id ? 0 : +(a.id > b.id) || -1; 14438 }); 14439 return region; 14440 } 14441 regionDelete(id) { 14442 if (this.regions.findById(id)) { 14443 this.regions.findById(id).elem.remove(); 14444 this.regions.delete(id); 14445 } 14446 else if ($$A("#" + id).length) { 14447 $$A("#" + id).remove(); 14448 } 14449 } 14450 reloadRegions() { 14451 this.regions.clear(); 14452 $$A(this.containers.svg).find(".mapsvg-region").removeClass("mapsvg-region"); 14453 $$A(this.containers.svg) 14454 .find(".mapsvg-region-disabled") 14455 .removeClass("mapsvg-region-disabled"); 14456 $$A(this.containers.svg) 14457 .find("path, polygon, circle, ellipse, rect") 14458 .each((index, element) => { 14459 const elem = element; 14460 if ($$A(elem).closest("defs").length) 14461 return; 14462 if (elem.getAttribute("id")) { 14463 if (!this.options.regionPrefix || 14464 (this.options.regionPrefix && 14465 elem.getAttribute("id").indexOf(this.options.regionPrefix) === 0)) { 14466 const region = new Region(elem, this); 14467 this.regions.push(region); 14468 } 14469 } 14470 }); 14471 } 14472 reloadRegionsFull() { 14473 const statuses = this.regionsRepository.getSchema().getFieldByType("status"); 14474 this.regions.forEach((region) => { 14475 const _region = this.regionsRepository.getLoaded().findById(region.id); 14476 if (_region) { 14477 region.setData(_region); 14478 if (statuses && _region.status !== undefined && _region.status !== null) { 14479 region.setStatus(_region.status); 14480 } 14481 } 14482 else { 14483 if (this.options.filters.filteredRegionsStatus || 14484 this.options.filters.filteredRegionsStatus === 0) { 14485 region.setStatus(this.options.filters.filteredRegionsStatus); 14486 } 14487 } 14488 }); 14489 this.loadDirectory(); 14490 this.setChoropleth(); 14491 this.setLayersControl(); 14492 this.setGroups(); 14493 if (this.options.labelsRegions.on) { 14494 this.setLabelsRegions(); 14495 } 14496 } 14497 fixMarkersWorldScreen() { 14498 if (this.googleMaps.map) 14499 setTimeout(() => { 14500 const markers = { left: 0, right: 0 }; 14501 if (this.markers.length > 1) {
14502 this.markers.forEach((m) => { 14503 if (m.node.offset().left < 14504 $$A(this.containers.map).offset().left + 14505 this.containers.map.clientWidth / 2) { 14506 markers.left++; 14507 } 14508 else { 14509 markers.right++; 14510 } 14511 }); 14512 if (markers.left === 0 || markers.right === 0) { 14513 const k = markers.left === 0 ? 1 : -1; 14514 const ww = (this.svgDefault.viewBox.width / this.mapLonDelta) * 14515 360 * 14516 this.getScale(); 14517 this.googleMaps.map.panBy(k * ww, 0); 14518 } 14519 } 14520 }, 600); 14521 } 14522 updateOutdatedOptions(options) { 14523 if (options.menu && (options.menu.position || options.menu.customContainer)) { 14524 if (options.menu.customContainer) { 14525 options.menu.location = "custom"; 14526 } 14527 else { 14528 options.menu.position = options.menu.position === "left" ? "left" : "right"; 14529 options.menu.location = 14530 options.menu.position === "left" ? "leftSidebar" : "rightSidebar"; 14531 if (!options.containers || !options.containers[options.menu.location]) { 14532 options.containers = options.containers || {}; 14533 options.containers[options.menu.location] = { on: false, width: "200px" }; 14534 } 14535 options.containers[options.menu.location].width = options.menu.width; 14536 if (MapSVG.parseBoolean(options.menu.on)) { 14537 options.containers[options.menu.location].on = true; 14538 } 14539 } 14540 delete options.menu.position; 14541 delete options.menu.width; 14542 delete options.menu.customContainer; 14543 } 14544 if (options.detailsView && 14545 (options.detailsView.location === "mapContainer" || 14546 options.detailsView.location === "near" || 14547 options.detailsView.location === "top")) { 14548 options.detailsView.location = "map"; 14549 } 14550 if (!options.controls) { 14551 options.controls = {}; 14552 options.controls.zoom = 14553 options.zoom && 14554 options.zoom.on && 14555 (!options.zoom.buttons || options.zoom.buttons.location !== "hide"); 14556 options.controls.location = 14557 options.zoom && options.zoom.buttons && options.zoom.buttons.location !== "hide" 14558 ? options.zoom.buttons.location 14559 : "right"; 14560 } 14561 if (options.colors && !options.colors.markers) { 14562 options.colors.markers = { 14563 base: { opacity: 100, saturation: 100 }, 14564 hovered: { opacity: 100, saturation: 100 }, 14565 unhovered: { opacity: 100, saturation: 100 }, 14566 active: { opacity: 100, saturation: 100 }, 14567 inactive: { opacity: 100, saturation: 100 }, 14568 }; 14569 } 14570 if (options.tooltipsMode) { 14571 options.tooltips.mode = options.tooltipsMode; 14572 delete options.tooltipsMode; 14573 } 14574 if (options.popover) { 14575 options.popovers = options.popover; 14576 delete options.popover; 14577 } 14578 } 14579 init() { 14580 if (this.options.source === "") { 14581 throw new Error("MapSVG: please provide SVG file source."); 14582 } 14583 this.disableCssAnimations(); 14584 this.setEvents(this.options.events); 14585 this.events.trigger("beforeLoad"); 14586 this.containers.map.classList.add("mapsvg"); 14587 this.setCss(); 14588 if (this.options.colors && this.options.colors.background) { 14589 this.containers.map.style.background = this.options.colors.background; 14590 }
14591 this.setContainers(this.options.containers); 14592 this.setColors(); 14593 this.addLoadingMessage(); 14594 this.addLayer("markers"); 14595 this.addLayer("labels"); 14596 this.addLayer("bubbles"); 14597 this.addLayer("popovers"); 14598 this.addLayer("scrollpane"); 14599 this.loadExtensions(); 14600 $$A.ajax({ url: this.options.source + "?v=" + this.svgFileLastChanged }) 14601 .fail((resp) => { 14602 this.svgLoadingFailed(resp); 14603 }) 14604 .done((xmlData) => { 14605 this.renderSvgData(xmlData); 14606 }); 14607 return this; 14608 } 14609 getContainer(name) { 14610 return this.containers[name]; 14611 } 14612 renderSvgData(xmlData) { 14613 const svgTag = $$A(xmlData).find("svg"); 14614 this.containers.svg = svgTag[0]; 14615 if (svgTag.attr("width") && svgTag.attr("height")) { 14616 this.svgDefault.width = parseFloat(svgTag.attr("width").replace(/px/g, "")); 14617 this.svgDefault.height = parseFloat(svgTag.attr("height").replace(/px/g, "")); 14618 this.svgDefault.viewBox = svgTag.attr("viewBox") 14619 ? new ViewBox(svgTag.attr("viewBox").split(" ")) 14620 : new ViewBox(0, 0, this.svgDefault.width, this.svgDefault.height); 14621 } 14622 else if (svgTag.attr("viewBox")) { 14623 this.svgDefault.viewBox = new ViewBox(svgTag.attr("viewBox").split(" ")); 14624 this.svgDefault.width = this.svgDefault.viewBox.width; 14625 this.svgDefault.height = this.svgDefault.viewBox.height; 14626 } 14627 else { 14628 const msg = "MapSVG: width/height and viewBox are missing in the SVG file. Can't parse the file because of that."; 14629 if (this.editMode) { 14630 alert(msg); 14631 } 14632 else { 14633 console.error(msg); 14634 } 14635 return false; 14636 } 14637 this.geoViewBox = this.getGeoViewBoxFromSvgTag(this.containers.svg); 14638 if (this.options.viewBox && this.options.viewBox.length == 4) { 14639 this._viewBox = new ViewBox(this.options.viewBox); 14640 } 14641 else { 14642 this._viewBox = new ViewBox(this.svgDefault.viewBox); 14643 } 14644 svgTag.attr("preserveAspectRatio", "xMidYMid meet"); 14645 svgTag.removeAttr("width"); 14646 svgTag.removeAttr("height"); 14647 $$A(this.containers.scrollpane).append(svgTag); 14648 this.reloadRegions(); 14649 this.setSize(this.options.width, this.options.height, this.options.responsive); 14650 if (this.options.disableAll) { 14651 this.setDisableAll(true); 14652 } 14653 this.setViewBox(this._viewBox); 14654 this.converter = new Converter(this.containers.map, this.svgDefault.viewBox, this.viewBox); 14655 if (this.geoViewBox) { 14656 this.converter.setGeoViewBox(this.geoViewBox); 14657 } 14658 this.setResponsive(this.options.responsive); 14659 this.setScroll(this.options.scroll, true); 14660 this.setZoom(this.options.zoom); 14661 this.setControls(this.options.controls); 14662 this.setGoogleMaps(); 14663 this.setTooltips(this.options.tooltips); 14664 this.setPopovers(this.options.popovers); 14665 if (this.options.cursor) 14666 this.setCursor(this.options.cursor); 14667 this.setTemplates(this.options.templates); 14668 this.loadExtensions(); 14669 this.filtersSchema = new Schema({ fields: this.options.filtersSchema }); 14670 this.objectsRepository.events.on("load", () => { 14671 this.showLoadingMessage(); 14672 }); 14673 this.objectsRepository.events.on("loaded", () => { 14674 this.fitOnDataLoadDone = false; 14675 this.addLocations(); 14676 this.fixMarkersWorldScreen(); 14677 this.attachDataToRegions(); 14678 this.loadDirectory(); 14679 if (this.options.labelsMarkers.on) { 14680 this.setLabelsMarkers(); 14681 } 14682 if (this.options.templates.labelRegion.indexOf("{{objects") !== -1) { 14683 this.setLabelsRegions(); 14684 } 14685 if (this.options.filters.on && 14686 this.options.filters.source === "database" && 14687 this.controllers.filters && 14688 this.controllers.filters.hideFilters) { 14689 this.controllers.filters.setFiltersCounter(); 14690 } 14691 this.hideLoadingMessage(); 14692 this.events.trigger("dataLoaded"); 14693 this.updateFiltersState(); 14694 this.setChoropleth(); 14695 }); 14696 this.objectsRepository.events.on("schemaChanged", () => { 14697 this.objectsRepository.reload(); 14698 }); 14699 this.objectsRepository.events.on("updated", (obj) => {
14700 this.attachDataToRegions(obj); 14701 this.reloadRegionsFull(); 14702 }); 14703 this.objectsRepository.events.on("created", (obj) => { 14704 this.attachDataToRegions(obj); 14705 this.reloadRegionsFull(); 14706 }); 14707 this.objectsRepository.events.on("deleted", (id) => { 14708 this.attachDataToRegions(); 14709 this.reloadRegionsFull(); 14710 }); 14711 this.regionsRepository.events.on("load", () => { 14712 this.showLoadingMessage(); 14713 }); 14714 this.regionsRepository.events.on("loaded", () => { 14715 this.hideLoadingMessage(); 14716 this.reloadRegionsFull(); 14717 if (this.options.filters.on && 14718 this.options.filters.source === "regions" && 14719 this.controllers.filters && 14720 this.controllers.filters.hideFilters) { 14721 this.controllers.filters.setFiltersCounter(); 14722 } 14723 this.events.trigger("regionsLoaded"); 14724 }); 14725 this.regionsRepository.events.on("updated", (regionData) => { 14726 this.reloadRegionsFull(); 14727 }); 14728 this.regionsRepository.events.on("created", (regionData) => { 14729 this.reloadRegionsFull(); 14730 }); 14731 this.regionsRepository.events.on("deleted", (regionData) => { 14732 this.reloadRegionsFull(); 14733 }); 14734 this.setMenu(); 14735 this.setFilters(); 14736 if (this.options.menu.filterout.field) { 14737 const f = {}; 14738 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 14739 if (this.options.menu.source == "regions") ; 14740 else { 14741 this.objectsRepository.query.setFilterOut(f); 14742 } 14743 } 14744 this.setEventHandlers(); 14745 if (!this.id) { 14746 this.finalizeMapLoading(); 14747 return; 14748 } 14749 if (!this.options.data_regions || !this.options.data_objects) { 14750 this.regionsRepository.find({ withSchema: true }).done((regions) => { 14751 if (this.options.database.loadOnStart || this.editMode) { 14752 this.objectsRepository.find({ withSchema: true }).done((data) => { 14753 this.finalizeMapLoading(); 14754 }); 14755 } 14756 else { 14757 this.finalizeMapLoading(); 14758 } 14759 }); 14760 } 14761 else { 14762 this.regionsRepository.loadDataFromResponse(this.options.data_regions); 14763 if (this.editMode || this.options.database.loadOnStart) { 14764 this.objectsRepository.loadDataFromResponse(this.options.data_objects); 14765 } 14766 delete this.options.data_regions; 14767 delete this.options.data_objects; 14768 } 14769 this.finalizeMapLoading(); 14770 } 14771 getGeoViewBoxFromSvgTag(svgTag) { 14772 const geo = $$A(svgTag).attr("mapsvg:geoViewBox") || $$A(svgTag).attr("mapsvg:geoviewbox"); 14773 if (geo) { 14774 const geoParts = geo.split(" ").map((p) => parseFloat(p)); 14775 if (geoParts.length == 4) { 14776 this.mapIsGeo = true; 14777 this.geoCoordinates = true; 14778 const sw = new GeoPoint(geoParts[3], geoParts[0]); 14779 const ne = new GeoPoint(geoParts[1], geoParts[2]); 14780 return new GeoViewBox(sw, ne); 14781 } 14782 } 14783 else { 14784 return null; 14785 } 14786 } 14787 svgLoadingFailed(resp) { 14788 if (resp.status == 404) { 14789 let msg = "MapSVG: file not found - " + 14790 this.options.source + 14791 "\n\nIf you moved MapSVG from another server please read the following docs page: https://mapsvg.com/docs/installation/moving"; 14792 if (this.editMode) { 14793 msg += 14794 "\n\nIf you know the correct path for the SVG file, please write it and press OK:"; 14795 const oldSvgPath = this.options.source; 14796 const userSvgPath = prompt(msg, oldSvgPath); 14797 if (userSvgPath !== null) { 14798 $$A.ajax({ url: userSvgPath + "?v=" + this.svgFileLastChanged }) 14799 .fail(function () { 14800 location.reload(); 14801 }) 14802 .done((xmlData) => { 14803 this.options.source = userSvgPath; 14804 this.renderSvgData(xmlData); 14805 const mapsRepo = new MapsRepository(); 14806 mapsRepo.update(this); 14807 }); 14808 } 14809 else { 14810 location.reload(); 14811 } 14812 } 14813 else { 14814 console.error(msg); 14815 } 14816 } 14817 else { 14818 const msg = "MapSVG: can't load SVG file for unknown reason. Please contact support: https://mapsvg.ticksy.com"; 14819 if (this.editMode) { 14820 alert(msg); 14821 } 14822 else { 14823 console.error(msg); 14824 } 14825 } 14826 } 14827 addLoadingMessage() { 14828 this.containers.loading = document.createElement("div"); 14829 this.containers.loading.className = "mapsvg-loading"; 14830 const loadingTextBlock = document.createElement("div"); 14831 loadingTextBlock.className = "mapsvg-loading-text"; 14832 loadingTextBlock.innerHTML = this.options.loadingText; 14833 const spinner = document.createElement("div"); 14834 spinner.className = "spinner-border spinner-border-sm"; 14835 this.containers.loading.appendChild(spinner); 14836 this.containers.loading.appendChild(loadingTextBlock); 14837 this.containers.map.appendChild(this.containers.loading); 14838 if (this.options.googleMaps.on) { 14839 $$A(this.containers.map).addClass("mapsvg-google-map-loading"); 14840 } 14841 } 14842 hideLoadingMessage() { 14843 $$A(this.containers.loading).hide(); 14844 } 14845 showLoadingMessage() { 14846 $$A(this.containers.loading).show(); 14847 } 14848 disableCssAnimations() { 14849 this.containers.map.classList.add("no-transitions"); 14850 } 14851 enableTransitions() { 14852 $$A(this.containers.map).removeClass("no-transitions"); 14853 } 14854 loadExtensions() { 14855 if (this.options.extension && 14856 $$A().mapSvg.extensions && 14857 $$A().mapSvg.extensions[_this.options.extension]) { 14858 const ext = $$A().mapSvg.extensions[_this.options.extension]; 14859 ext && ext.common(this); 14860 } 14861 } 14862 finalizeMapLoading() { 14863 if (this.options.googleMaps.on && !this.googleMaps.map) { 14864 this.events.on("googleMapsLoaded", () => { 14865 this.finalizeMapLoading(); 14866 }); 14867 return; 14868 } 14869 this.selectRegionByIdFromUrl(); 14870 setTimeout(() => { 14871 this.movingItemsAdjustScreenPosition(); 14872 this.mapAdjustStrokes(); 14873 setTimeout(() => { 14874 this.hideLoadingMessage(); 14875 $$A(this.containers.loading).find(".mapsvg-loading-text").hide(); 14876 this.enableTransitions(); 14877 }, 200); 14878 }, 100); 14879 this.events.trigger("afterLoad"); 14880 MapSVG.addInstance(this); 14881 } 14882 selectRegionByIdFromUrl() { 14883 const match = RegExp("[?&]mapsvg_select=([^&]*)").exec(window.location.search); 14884 if (match) { 14885 const select = decodeURIComponent(match[1].replace(/\+/g, " ")); 14886 this.selectRegion(select); 14887 } 14888 if (window.location.hash) { 14889 const query = window.location.hash.replace("#/m/", ""); 14890 const region = this.getRegion(query); 14891 if (region && this.options.actions.map.afterLoad.selectRegion) { 14892 this.regionClickHandler(null, region); 14893 } 14894 } 14895 } 14896 createForm(options) { 14897 return new FormBuilder(options); 14898 } 14899 getApiUrl(path) { 14900 const server = new Server(); 14901 return server.getUrl(path); 14902 } 14903 getConverter() { 14904 return this.converter; 14905 } 14906 setChoropleth(options) { 14907 const _this = this; 14908 options = options || _this.options.choropleth; 14909 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14910 $$A.extend(true, _this.options, { choropleth: options }); 14911 let needsRedraw = false;
14912 if (!_this.$gauge) { 14913 _this.$gauge = {}; 14914 _this.$gauge.gradient = $$A("<td> </td>").addClass("mapsvg-gauge-gradient"); 14915 _this.setGaugeGradientCSS(); 14916 _this.$gauge.container = $$A("<div />").addClass("mapsvg-gauge").hide(); 14917 _this.$gauge.table = $$A("<table />"); 14918 const tr = $$A("<tr />"); 14919 _this.$gauge.labelLow = $$A("<td>" + _this.options.choropleth.labels.low + "</td>"); 14920 _this.$gauge.labelHigh = $$A("<td>" + _this.options.choropleth.labels.high + "</td>"); 14921 tr.append(_this.$gauge.labelLow); 14922 tr.append(_this.$gauge.gradient); 14923 tr.append(_this.$gauge.labelHigh); 14924 _this.$gauge.table.append(tr); 14925 _this.$gauge.container.append(_this.$gauge.table); 14926 $$A(_this.containers.map).append(_this.$gauge.container); 14927 } 14928 if (!_this.options.choropleth.on && _this.$gauge.container.is(":visible")) { 14929 _this.$gauge.container.hide(); 14930 needsRedraw = true; 14931 } 14932 else if (_this.options.choropleth.on && !_this.$gauge.container.is(":visible")) { 14933 _this.$gauge.container.show(); 14934 needsRedraw = true; 14935 _this.regionsRepository.events.on("change", function () { 14936 _this.redrawGauge(); 14937 }); 14938 } 14939 if (options.colors) { 14940 _this.options.choropleth.colors.lowRGB = tinycolor(_this.options.choropleth.colors.low).toRgb(); 14941 _this.options.choropleth.colors.highRGB = tinycolor(_this.options.choropleth.colors.high).toRgb(); 14942 _this.options.choropleth.colors.diffRGB = { 14943 r: _this.options.choropleth.colors.highRGB.r - 14944 _this.options.choropleth.colors.lowRGB.r, 14945 g: _this.options.choropleth.colors.highRGB.g - 14946 _this.options.choropleth.colors.lowRGB.g, 14947 b: _this.options.choropleth.colors.highRGB.b - 14948 _this.options.choropleth.colors.lowRGB.b, 14949 a: _this.options.choropleth.colors.highRGB.a - 14950 _this.options.choropleth.colors.lowRGB.a, 14951 }; 14952 needsRedraw = true; 14953 _this.$gauge && _this.setGaugeGradientCSS(); 14954 } 14955 if (options.labels) { 14956 _this.$gauge.labelLow.html(_this.options.choropleth.labels.low); 14957 _this.$gauge.labelHigh.html(_this.options.choropleth.labels.high); 14958 } 14959 needsRedraw && _this.redrawGauge(); 14960 } 14961 redrawGauge() { 14962 const _this = this; 14963 _this.updateGaugeMinMax(); 14964 _this.regionsRedrawColors(); 14965 } 14966 updateGaugeMinMax() { 14967 const _this = this; 14968 _this.options.choropleth.min = 0; 14969 _this.options.choropleth.max = false; 14970 const values = []; 14971 _this.regions.forEach(function (r) { 14972 const gauge = r.data && r.data[_this.options.regionChoroplethField]; 14973 gauge != undefined && values.push(gauge); 14974 }); 14975 if (values.length > 0) { 14976 _this.options.choropleth.min = values.length == 1 ? 0 : Math.min.apply(null, values); 14977 _this.options.choropleth.max = Math.max.apply(null, values); 14978 _this.options.choropleth.maxAdjusted = 14979 _this.options.choropleth.max - _this.options.choropleth.min; 14980 } 14981 } 14982 setGaugeGradientCSS() { 14983 const _this = this; 14984 _this.$gauge.gradient.css({ 14985 background: "linear-gradient(to right," + 14986 _this.options.choropleth.colors.low + 14987 " 1%," + 14988 _this.options.choropleth.colors.high + 14989 " 100%)", 14990 filter: 'progid:DXImageTransform.Microsoft.gradient( startColorstr="' + 14991 _this.options.choropleth.colors.low + 14992 '", endColorstr="' + 14993 _this.options.choropleth.colors.high + 14994 '",GradientType=1 )', 14995 }); 14996 } 14997 get $map() { 14998 return $$A(this.getContainer("map")); 14999 } 15000 get $svg() { 15001 return $$A(this.getContainer("svg")); 15002 } 15003 get $popover() { 15004 return $$A(this.getContainer("popover")); 15005 } 15006 get $details() { 15007 return $$A(this.getContainer("detailsView")); 15008 } 15009 get $directory() { 15010 return $$A(this.getContainer("directory")); 15011 } 15012 get database() { 15013 return this.objectsRepository; 15014 } 15015 get regionsDatabase() { 15016 return this.regionsRepository; 15017 } 15018 } 15019 15020 exports.MapSVGMap = MapSVGMap; 15021 exports.arrayIndexed = ArrayIndexed; 15022 exports.formBuilder = FormBuilder; 15023 exports.geoPoint = GeoPoint; 15024 exports.globals = MapSVG; 15025 exports.location = Location; 15026 exports.map = MapSVGMap; 15027 exports.mapsRepository = MapsRepository; 15028 exports.mapsV2Repository = MapsV2Repository; 15029 exports.marker = Marker; 15030 exports.query = Query; 15031 exports.repository = Repository; 15032 exports.schema = Schema; 15033 exports.schemaRepository = SchemaRepository; 15034 exports.screenPoint = ScreenPoint; 15035 exports.server = Server; 15036 exports.svgPoint = SVGPoint; 15037 15038 Object.defineProperty(exports, '__esModule', { value: true }); 15039 15040}))); 15041//# sourceMappingURL=mapsvg-front.umd.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.