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 let value; 315 try { 316 value = toElement.getScreenCTM().inverse().multiply(this.getScreenCTM()); 317 } catch (e) { 318 return; 319 } 320 return value; 321 }; 322 323 Map.prototype.toArray = function () { 324 return Array.from(this, ([name, value]) => value); 325 }; 326 327 MapSVG.ResizeSensor = class ResizeSensor { 328 constructor(element, callback) { 329 var _this = this; 330 _this.element = element; 331 _this.callback = callback; 332 var style = getComputedStyle(element); 333 var zIndex = parseInt(style.zIndex); 334 if (isNaN(zIndex)) { 335 zIndex = 0; 336 } 337 zIndex--; 338 _this.expand = document.createElement("div"); 339 _this.expand.style.position = "absolute";
340 _this.expand.style.left = "0px"; 341 _this.expand.style.top = "0px"; 342 _this.expand.style.right = "0px"; 343 _this.expand.style.bottom = "0px"; 344 _this.expand.style.overflow = "hidden"; 345 _this.expand.style.zIndex = zIndex.toString(); 346 _this.expand.style.visibility = "hidden"; 347 var expandChild = document.createElement("div"); 348 expandChild.style.position = "absolute"; 349 expandChild.style.left = "0px"; 350 expandChild.style.top = "0px"; 351 expandChild.style.width = "10000000px"; 352 expandChild.style.height = "10000000px"; 353 _this.expand.appendChild(expandChild); 354 _this.shrink = document.createElement("div"); 355 _this.shrink.style.position = "absolute"; 356 _this.shrink.style.left = "0px"; 357 _this.shrink.style.top = "0px"; 358 _this.shrink.style.right = "0px"; 359 _this.shrink.style.bottom = "0px"; 360 _this.shrink.style.overflow = "hidden"; 361 _this.shrink.style.zIndex = zIndex.toString(); 362 _this.shrink.style.visibility = "hidden"; 363 var shrinkChild = document.createElement("div"); 364 shrinkChild.style.position = "absolute"; 365 shrinkChild.style.left = "0px"; 366 shrinkChild.style.top = "0px"; 367 shrinkChild.style.width = "200%"; 368 shrinkChild.style.height = "200%"; 369 _this.shrink.appendChild(shrinkChild); 370 _this.element.appendChild(_this.expand); 371 _this.element.appendChild(_this.shrink); 372 var size = element.getBoundingClientRect(); 373 _this.currentWidth = size.width; 374 _this.currentHeight = size.height; 375 _this.setScroll(); 376 _this.expand.addEventListener("scroll", function () { 377 _this.onScroll(); 378 }); 379 _this.shrink.addEventListener("scroll", function () { 380 _this.onScroll(); 381 }); 382 } 383 onScroll() { 384 var _this = this; 385 var size = _this.element.getBoundingClientRect(); 386 var newWidth = size.width; 387 var newHeight = size.height; 388 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 389 _this.currentWidth = newWidth; 390 _this.currentHeight = newHeight; 391 _this.callback(); 392 } 393 this.setScroll(); 394 } 395 setScroll() { 396 this.expand.scrollLeft = 10000000; 397 this.expand.scrollTop = 10000000; 398 this.shrink.scrollLeft = 10000000; 399 this.shrink.scrollTop = 10000000; 400 } 401 destroy() { 402 this.expand.remove(); 403 this.shrink.remove(); 404 } 405 }; 406 407 MapSVG.nonce = function () { 408 return mapsvg_runtime_vars.nonce; 409 }; 410 411 /** 412 * Adds # hash at the beginning of HEX color value 413 * @param {String} color 414 * @returns {String} 415 * @private 416 */ 417 MapSVG.fixColorHash = (color) => { 418 const hexColorNoHash = new RegExp(/^([0-9a-f]{3}|[0-9a-f]{6})$/i); 419 if (color && color.match(hexColorNoHash) !== null) { 420 color = "#" + color; 421 } 422 return color; 423 }; 424 425 /** 426 * Delays method execution. 427 * For example, it can be used in search input fields to prevent sending 428 * an ajax request on each key press. 429 * @param {Function} method 430 * @param {number} delay 431 * @param {object} scope 432 * @param {array} params 433 * @private 434 */ 435 MapSVG.throttle = (method, delay, scope, params) => { 436 clearTimeout(method._tId); 437 method._tId = setTimeout(function () { 438 method.apply(scope, params); 439 }, delay); 440 }; 441 MapSVG.geocode = (query, callback) => { 442 if (!window.google) { 443 console.error("MapSVG: can't do Geocoding - Google Maps API is not loaded."); 444 jQuery.growl.error({ 445 title: "Error", 446 message: "Google Maps API files are not loaded", 447 }); 448 return false;
449 } 450 // if (!MapSVG.options.google_api_key) { 451 // jQuery.growl.error({ 452 // title: "Error", 453 // message: "Google Maps API key is not provided", 454 // }); 455 // return false; 456 // } 457 if (!MapSVG.geocoder) { 458 MapSVG.geocoder = new google.maps.Geocoder(); 459 } 460 461 MapSVG.throttle(MapSVG.geocoder.geocode, 500, MapSVG.geocoder, [ 462 query, 463 function (results, status) { 464 if (status === "OK") { 465 callback(results); 466 } else { 467 jQuery.growl.error({ 468 title: "Error: " + status, 469 message: 470 "There is some problem with Google API keys. See browser's console for more details", 471 }); 472 } 473 }, 474 ]); 475 }; 476 477 MapSVG.handleFailedRequest = (response) => { 478 var message = ""; 479 480 if (response.status === 403) { 481 if (response.responseText.indexOf("Wordfence") !== -1) { 482 message += 483 "The request has been blocked by Wordfence. " + 484 'Switch Wordfence to "Learning mode", and save the map settings again. ' + 485 "If the settings are saved successfully, you can switch Wordfence back to normal mode."; 486 } else { 487 message += 488 "The request has been blocked by your server. " + 489 "Do you have mod_sec Apache's module enabled? If that's the case you need to change its settings."; 490 } 491 } else { 492 if (response && response.responseText) { 493 try { 494 var _response = JSON.parse(response.responseText); 495 if (_response && _response.data && _response.data.error) { 496 message = _response.data.error; 497 } 498 } catch (e) { 499 } 500 } 501 } 502 503 $.growl.error({ 504 title: "Error: " + response.status + " " + response.statusText, 505 message: message, 506 duration: 30000, 507 }); 508 }; 509 510 if (!Object.values) { 511 Object.values = function (object) { 512 return Object.keys(object).map(function (k) { 513 return object[k]; 514 }); 515 }; 516 } 517 518 window.MapSVG = MapSVG; 519 520 const defRegionTemplate = "<div>\n" + 521 " <p>This is the demo content of the <strong>Region %templateType%</strong>.</p>\n" + 522 ' <p>How to edit it: if you are in mapsvg control panel now, click on the following link to open the template editor for this view: <a href="#" class="mapsvg-template-link" data-template="%templateTypeSnake%Region">Menu > Templates > Region %templateType%</a>.</p>\n' + 523 ' <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' + 524 "</div>\n" + 525 "<hr />\n\n" + 526 "<!-- Region fields are available in this template -->\n" + 527 "<h5>{{#if title}} {{title}} {{else}} {{id}} {{/if}}</h5>\n" + 528 "<p>Status: {{status_text}}</p>\n\n" + 529 "<!-- Show all linked Database Objects: -->\n" + 530 "{{#each objects}}\n\n" + 531 " <!-- DB Object are available inside of this block -->\n\n" + 532 " <h5>{{title}}</h5>\n" + 533 " <!-- When you need to render a field as HTML, use 3 curly braces instead of 2:-->\n" + 534 " <p>{{{description}}}</p>\n" + 535 " <p><em>{{location.address.formatted}}</em></p>\n\n" + 536 " <!-- Show all images: -->\n" + 537 " {{#each images}}\n" + 538 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 539 " <!-- are available in this block -->\n" + 540 ' <img src="{{thumbnail}}" />\n' + 541 " {{/each}}\n\n" + 542 "{{/each}}"; 543 const defDBTemplate = "<div>\n" + 544 " <p>This is the demo content of the <strong>DB Object %templateType%</strong>.</p>\n" + 545 ' <p>How to edit it: if you are in mapsvg control panel now, click on the following link to open the template editor for this view: <a href="#" class="mapsvg-template-link" data-template="%templateTypeSnake%">Menu > Templates > DB Object %templateType%</a>.</p>\n' + 546 ' <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' + 547 "</div>\n" + 548 "<hr />\n\n" + 549 "<!-- DB Object fields are available in this template. -->\n" + 550 "<h5>{{title}}</h5>\n" + 551 "<!-- When you need to render a fields as HTML, use 3 curly braces instead of 2:-->\n" + 552 "<p>{{{description}}}</p>\n" + 553 "<p><em>{{location.address.formatted}}</em></p>\n\n" + 554 "<!-- Show all images: -->\n" + 555 "{{#each images}}\n" + 556 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 557 " <!-- are available in this block -->\n" + 558 ' <img src="{{thumbnail}}" />\n' + 559 "{{/each}}\n\n" + 560 "<!-- Show all linked Regions, comma-separated: -->\n" + 561 "<p> Regions: \n" + 562 " {{#each regions}}\n" + 563 " <!-- Region fields are available in this block -->\n" + 564 " {{#if title}}\n" + 565 " {{title}}\n" + 566 " {{else}}\n" + 567 " {{id}}\n" + 568 " {{/if}}{{#unless @last}}, {{/unless}}\n" + 569 " {{/each}}\n" + 570 "</p>"; 571 const dirItemItemTemplate = "<!-- If Directory Source = Database: DB Object fields are available in this template -->\n" + 572 "<!-- If Directory Source = Regions: Region fields are available in this template -->\n" + 573 "{{title}}"; 574 const DefaultOptions = { 575 source: "", 576 markerLastID: 0, 577 regionLastID: 0, 578 dataLastID: 1, 579 disableAll: false, 580 width: null, 581 height: null, 582 lockAspectRatio: false, 583 padding: { top: 0, left: 0, right: 0, bottom: 0 }, 584 maxWidth: null, 585 maxHeight: null, 586 minWidth: null, 587 minHeight: null, 588 loadingText: "Loading map...", 589 colorsIgnore: false, 590 colors: { 591 baseDefault: "#000000", 592 background: "#eeeeee", 593 selected: 40, 594 hover: 20, 595 directory: "#fafafa", 596 detailsView: "", 597 status: {},
598 clusters: "", 599 clustersBorders: "", 600 clustersText: "", 601 clustersHover: "", 602 clustersHoverBorders: "", 603 clustersHoverText: "", 604 markers: { 605 base: { opacity: 100, saturation: 100 }, 606 hovered: { opacity: 100, saturation: 100 }, 607 unhovered: { opacity: 40, saturation: 100 }, 608 active: { opacity: 100, saturation: 100 }, 609 inactive: { opacity: 40, saturation: 100 }, 610 }, 611 }, 612 regions: {}, 613 clustering: { on: false }, 614 viewBox: [], 615 cursor: "default", 616 manualRegions: false, 617 onClick: null, 618 mouseOver: null, 619 mouseOut: null, 620 menuOnClick: null, 621 beforeLoad: null, 622 afterLoad: null, 623 zoom: { 624 on: true, 625 limit: [0, 22], 626 delta: 2, 627 buttons: { on: true, location: "right" }, 628 mousewheel: true, 629 fingers: true, 630 hideSvg: false, 631 hideSvgZoomLevel: 7, 632 }, 633 scroll: { on: true, limit: false, background: false, spacebar: false }, 634 responsive: true, 635 tooltips: { on: false, position: "bottom-right", template: "", maxWidth: "", minWidth: 100 }, 636 popovers: { 637 on: false, 638 position: "top", 639 template: "", 640 centerOn: true, 641 width: 300, 642 maxWidth: 50, 643 maxHeight: 50, 644 }, 645 multiSelect: false, 646 regionStatuses: { 647 "1": { label: "Enabled", value: "1", color: "", disabled: false }, 648 "0": { label: "Disabled", value: "0", color: "", disabled: true }, 649 }, 650 events: { 651 afterLoad: "function(){\n" + 652 " // var mapsvg = this;\n" + 653 " // var regions = mapsvg.regions;\n" + 654 " // var dbObjects = mapsvg.database.getLoaded();\n" + 655 "}", 656 beforeLoad: "function(){\n" + 657 " // var mapsvg = this;\n" + 658 " // var settings = mapsvg.options;\n" + 659 " // console.log(settings);\n" + 660 "}", 661 databaseLoaded: "function (){\n" + 662 " // var mapsvg = this;\n" + 663 " // var dbObjects = mapsvg.database.getLoaded();\n" + 664 "}", 665 "click.region": "function (e, mapsvg){\n" + 666 " // var region = this;\n" + 667 " // console.log(region);\n" + 668 "}", 669 "mouseover.region": "function (e, mapsvg){\n" + 670 " // var region = this;\n" + 671 " // console.log(region);\n" + 672 "}", 673 "mouseout.region": "function (e, mapsvg){\n" + 674 " // var region = this;\n" + 675 " // console.log(region);\n" + 676 "}", 677 "click.marker": "function (e, mapsvg){\n" + 678 " // var marker = this;\n" + 679 " // console.log(marker);\n" + 680 "}", 681 "mouseover.marker": "function (e, mapsvg){\n" + 682 " // var marker = this;\n" + 683 " // console.log(marker);\n" + 684 "}", 685 "mouseout.marker": "function (e, mapsvg){\n" + 686 " // var marker = this;\n" + 687 " // console.log(marker);\n" + 688 "}", 689 "click.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 690 "mouseover.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 691 "mouseout.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 692 "shown.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 693 "closed.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 694 "closed.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 695 "shown.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 696 }, 697 css: "#mapsvg-map-%id% .mapsvg-tooltip {\n\n}\n" + 698 "#mapsvg-map-%id% .mapsvg-popover {\n\n}\n" + 699 "#mapsvg-map-%id% .mapsvg-details-container {\n\n}\n" + 700 "#mapsvg-map-%id% .mapsvg-directory-item {\n\n}\n" + 701 "#mapsvg-map-%id% .mapsvg-region-label {\n" + 702 " /* background-color: rgba(255,255,255,.6); */\n" + 703 " font-size: 11px;\n" + 704 " padding: 3px 5px;\n" + 705 " border-radius: 4px;\n" + 706 "}\n" + 707 "#mapsvg-map-%id% .mapsvg-marker-label {\n" + 708 " padding: 3px 5px;\n" + 709 " /*\n" + 710 " border-radius: 4px;\n" + 711 " background-color: white;\n" + 712 " margin-top: -4px;\n" + 713 " */\n}\n" + 714 "#mapsvg-map-%id% .mapsvg-filters-wrap {\n\n}\n" + 715 "\n\n\n\n\n\n", 716 templates: { 717 popoverRegion: defRegionTemplate 718 .replace(/%templateType%/g, "Popover") 719 .replace(/%templateTypeSnake%/g, "popover"), 720 popoverMarker: defDBTemplate 721 .replace(/%templateType%/g, "Popover") 722 .replace(/%templateTypeSnake%/g, "popover"), 723 tooltipRegion: "<!-- Region fields are available in this template -->\n{{id}} - {{title}}", 724 tooltipMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 725 directoryItem: dirItemItemTemplate, 726 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>', 727 detailsView: defDBTemplate 728 .replace(/%templateType%/g, "Details View") 729 .replace(/%templateTypeSnake%/g, "detailsView"), 730 detailsViewRegion: defRegionTemplate 731 .replace(/%templateType%/g, "Details View") 732 .replace(/%templateTypeSnake%/g, "detailsView"), 733 labelMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 734 labelRegion: "<!-- Region fields are available in this template -->\n{{title}}", 735 labelLocation: "You are here!", 736 }, 737 choropleth: { 738 on: false, 739 source: "regions", 740 sourceFieldSelect: { 741 on: false, 742 variants: [], 743 }, 744 bubbleMode: false, 745 bubbleSize: { 746 min: 20, 747 max: 40, 748 }, 749 labels: { low: "low", high: "high" }, 750 colors: { lowRGB: null, highRGB: null, low: "#550000", high: "#ee0000", noData: "#333333" }, 751 min: 0, 752 max: 0, 753 coloring: { 754 mode: "gradient", 755 noData: { 756 color: "#999999", 757 description: "No data", 758 }, 759 gradient: { 760 colors: { 761 lowRGB: null, 762 highRGB: null, 763 diffRGB: null, 764 low: "#550000", 765 high: "#ee0000", 766 }, 767 labels: { 768 low: "low", 769 high: "high", 770 }, 771 values: { 772 min: null, 773 max: null, 774 maxAdjusted: null, 775 }, 776 }, 777 palette: { 778 outOfRange: { 779 color: "#ececec", 780 description: "Out of range", 781 }, 782 colors: [ 783 { 784 color: "#550000", 785 valueFrom: 0, 786 valueTo: 50, 787 description: "", 788 }, 789 ], 790 }, 791 legend: { 792 on: true, 793 layout: "vertical", 794 container: "bottom-left", 795 title: "Choropleth map", 796 text: "", 797 description: "", 798 width: "20%", 799 height: "20%", 800 }, 801 }, 802 }, 803 filters: { 804 on: true, 805 source: "database", 806 location: "header", 807 modalLocation: "map", 808 width: "100%", 809 hide: false, 810 showButtonText: "Filters", 811 clearButtonText: "Clear all",
812 clearButton: false, 813 searchButton: false, 814 searchButtonText: "Search", 815 padding: "", 816 }, 817 menu: { 818 on: false, 819 hideOnMobile: true, 820 location: "leftSidebar", 821 locationMobile: "leftSidebar", 822 search: false, 823 containerId: "", 824 searchPlaceholder: "Search...", 825 searchFallback: false, 826 source: "database", 827 showFirst: "map", 828 showMapOnClick: true, 829 minHeight: "400", 830 sortBy: "id", 831 sortDirection: "desc", 832 categories: { 833 on: false, 834 groupBy: "", 835 hideEmpty: true, 836 collapse: true, 837 collapseOther: true, 838 }, 839 clickActions: { 840 region: "default", 841 marker: "default", 842 directoryItem: { 843 triggerClick: true, 844 showPopover: false, 845 showDetails: true, 846 }, 847 }, 848 detailsViewLocation: "overDirectory", 849 noResultsText: "No results found", 850 filterout: { field: "", cond: "=", val: "" }, 851 }, 852 database: { 853 pagination: { 854 on: true, 855 perpage: 30, 856 next: "Next", 857 prev: "Prev.", 858 showIn: "both", 859 }, 860 loadOnStart: true, 861 table: "", 862 }, 863 actions: { 864 map: { 865 afterLoad: { 866 selectRegion: false, 867 }, 868 }, 869 region: { 870 mouseover: { 871 showTooltip: false, 872 }, 873 click: { 874 addIdToUrl: false, 875 showDetails: true, 876 showDetailsFor: "region", 877 filterDirectory: false, 878 loadObjects: false, 879 showPopover: false, 880 showPopoverFor: "region", 881 goToLink: false, 882 linkField: "Region.link", 883 }, 884 touch: { 885 showPopover: false, 886 }, 887 }, 888 marker: { 889 mouseover: { 890 showTooltip: false, 891 }, 892 click: { 893 showDetails: true, 894 showPopover: false, 895 goToLink: false, 896 linkField: "Object.link", 897 }, 898 touch: { 899 showPopover: false, 900 }, 901 }, 902 directoryItem: { 903 click: { 904 showDetails: true, 905 showPopover: false, 906 goToLink: false, 907 selectRegion: true, 908 fireRegionOnClick: true, 909 linkField: "Object.link", 910 }, 911 hover: { 912 centerOnMarker: false, 913 }, 914 }, 915 }, 916 detailsView: { 917 location: "map", 918 containerId: "", 919 width: "100%", 920 mobileFullscreen: true, 921 }, 922 mobileView: { 923 labelMap: "Map", 924 labelList: "List", 925 labelClose: "Close", 926 }, 927 googleMaps: { 928 on: false, 929 apiKey: "", 930 loaded: false, 931 center: "auto", 932 type: "roadmap", 933 minZoom: 1, 934 style: "default", 935 styleJSON: [], 936 language: "en", 937 }, 938 groups: [], 939 floors: [], 940 layersControl: { 941 on: false, 942 position: "top-left", 943 label: "Show on map", 944 expanded: true, 945 maxHeight: "100%", 946 }, 947 floorsControl: { 948 on: false, 949 position: "top-left", 950 label: "Floors", 951 expanded: false, 952 maxHeight: "100%", 953 }, 954 containers: { 955 leftSidebar: { on: false, width: "250px" }, 956 rightSidebar: { on: false, width: "250px" }, 957 header: { on: true, height: "auto" }, 958 footer: { on: false, height: "auto" }, 959 }, 960 labelsMarkers: { on: false }, 961 labelsRegions: { on: false }, 962 svgFileVersion: 1, 963 fitMarkers: false, 964 fitMarkersOnStart: false, 965 fitSingleMarkerZoom: 20, 966 controls: { 967 location: "right", 968 zoom: true, 969 zoomReset: false, 970 userLocation: false, 971 previousMap: false, 972 }, 973 previousMapsIds: [], 974 }; 975 976 // TinyColor v1.4.1 977 // https://github.com/bgrins/TinyColor 978 // Brian Grinstead, MIT License 979 980 //(function(Math) { 981 982 var trimLeft = /^\s+/, 983 trimRight = /\s+$/, 984 tinyCounter = 0, 985 mathRound = Math.round, 986 mathMin = Math.min, 987 mathMax = Math.max, 988 mathRandom = Math.random; 989 990 function tinycolor(color, opts) { 991 color = color ? color : ""; 992 opts = opts || {}; 993 994 // If input is already a tinycolor, return itself 995 if (color instanceof tinycolor) { 996 return color; 997 } 998 // If we are called as a function, call using new instead 999 if (!(this instanceof tinycolor)) { 1000 return new tinycolor(color, opts); 1001 } 1002 1003 var rgb = inputToRGB(color); 1004 (this._originalInput = color), 1005 (this._r = rgb.r), 1006 (this._g = rgb.g), 1007 (this._b = rgb.b), 1008 (this._a = rgb.a), 1009 (this._roundA = mathRound(100 * this._a) / 100), 1010 (this._format = opts.format || rgb.format); 1011 this._gradientType = opts.gradientType; 1012 1013 // Don't let the range of [0,255] come back in [0,1]. 1014 // Potentially lose a little bit of precision here, but will fix issues where 1015 // .5 gets interpreted as half of the total, instead of half of 1 1016 // If it was supposed to be 128, this was already taken care of b
vendor: 11,167 bytes, lines 1016-1334
1016y `inputToRgb` 1017 if (this._r < 1) { 1018 this._r = mathRound(this._r); 1019 } 1020 if (this._g < 1) { 1021 this._g = mathRound(this._g); 1022 } 1023 if (this._b < 1) { 1024 this._b = mathRound(this._b); 1025 } 1026 1027 this._ok = rgb.ok; 1028 this._tc_id = tinyCounter++; 1029 } 1030 1031 tinycolor.prototype = { 1032 isDark: function () { 1033 return this.getBrightness() < 128; 1034 }, 1035 isLight: function () { 1036 return !this.isDark(); 1037 }, 1038 isValid: function () { 1039 return this._ok; 1040 }, 1041 getOriginalInput: function () { 1042 return this._originalInput; 1043 }, 1044 getFormat: function () { 1045 return this._format; 1046 }, 1047 getAlpha: function () { 1048 return this._a; 1049 }, 1050 getBrightness: function () { 1051 //http://www.w3.org/TR/AERT#color-contrast 1052 var rgb = this.toRgb(); 1053 return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; 1054 }, 1055 getLuminance: function () { 1056 //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef 1057 var rgb = this.toRgb(); 1058 var RsRGB, GsRGB, BsRGB, R, G, B; 1059 RsRGB = rgb.r / 255; 1060 GsRGB = rgb.g / 255; 1061 BsRGB = rgb.b / 255; 1062 1063 if (RsRGB <= 0.03928) { 1064 R = RsRGB / 12.92; 1065 } else { 1066 R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); 1067 } 1068 if (GsRGB <= 0.03928) { 1069 G = GsRGB / 12.92; 1070 } else { 1071 G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); 1072 } 1073 if (BsRGB <= 0.03928) { 1074 B = BsRGB / 12.92; 1075 } else { 1076 B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); 1077 } 1078 return 0.2126 * R + 0.7152 * G + 0.0722 * B; 1079 }, 1080 setAlpha: function (value) { 1081 this._a = boundAlpha(value); 1082 this._roundA = mathRound(100 * this._a) / 100; 1083 return this; 1084 }, 1085 toHsv: function () { 1086 var hsv = rgbToHsv(this._r, this._g, this._b); 1087 return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; 1088 }, 1089 toHsvString: function () { 1090 var hsv = rgbToHsv(this._r, this._g, this._b); 1091 var h = mathRound(hsv.h * 360), 1092 s = mathRound(hsv.s * 100), 1093 v = mathRound(hsv.v * 100); 1094 return this._a == 1 1095 ? "hsv(" + h + ", " + s + "%, " + v + "%)" 1096 : "hsva(" + h + ", " + s + "%, " + v + "%, " + this._roundA + ")"; 1097 }, 1098 toHsl: function () { 1099 var hsl = rgbToHsl(this._r, this._g, this._b); 1100 return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; 1101 }, 1102 toHslString: function () { 1103 var hsl = rgbToHsl(this._r, this._g, this._b); 1104 var h = mathRound(hsl.h * 360), 1105 s = mathRound(hsl.s * 100), 1106 l = mathRound(hsl.l * 100); 1107 return this._a == 1 1108 ? "hsl(" + h + ", " + s + "%, " + l + "%)" 1109 : "hsla(" + h + ", " + s + "%, " + l + "%, " + this._roundA + ")"; 1110 }, 1111 toHex: function (allow3Char) { 1112 return rgbToHex(this._r, this._g, this._b, allow3Char); 1113 }, 1114 toHexString: function (allow3Char) { 1115 return "#" + this.toHex(allow3Char); 1116 }, 1117 toHex8: function (allow4Char) { 1118 return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char); 1119 }, 1120 toHex8String: function (allow4Char) { 1121 return "#" + this.toHex8(allow4Char); 1122 }, 1123 toRgb: function () { 1124 return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a }; 1125 }, 1126 toRgbString: function () { 1127 return this._a == 1 1128 ? "rgb(" + 1129 mathRound(this._r) + 1130 ", " + 1131 mathRound(this._g) + 1132 ", " + 1133 mathRound(this._b) + 1134 ")" 1135 : "rgba(" + 1136 mathRound(this._r) + 1137 ", " + 1138 mathRound(this._g) + 1139 ", " + 1140 mathRound(this._b) + 1141 ", " + 1142 this._roundA + 1143 ")"; 1144 }, 1145 toPercentageRgb: function () { 1146 return { 1147 r: mathRound(bound01(this._r, 255) * 100) + "%", 1148 g: mathRound(bound01(this._g, 255) * 100) + "%", 1149 b: mathRound(bound01(this._b, 255) * 100) + "%", 1150 a: this._a, 1151 }; 1152 }, 1153 toPercentageRgbString: function () { 1154 return this._a == 1 1155 ? "rgb(" + 1156 mathRound(bound01(this._r, 255) * 100) + 1157 "%, " + 1158 mathRound(bound01(this._g, 255) * 100) + 1159 "%, " + 1160 mathRound(bound01(this._b, 255) * 100) + 1161 "%)" 1162 : "rgba(" + 1163 mathRound(bound01(this._r, 255) * 100) + 1164 "%, " + 1165 mathRound(bound01(this._g, 255) * 100) + 1166 "%, " + 1167 mathRound(bound01(this._b, 255) * 100) + 1168 "%, " + 1169 this._roundA + 1170 ")"; 1171 }, 1172 toName: function () { 1173 if (this._a === 0) { 1174 return "transparent"; 1175 } 1176 1177 if (this._a < 1) { 1178 return false; 1179 } 1180 1181 return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; 1182 }, 1183 toFilter: function (secondColor) { 1184 var hex8String = "#" + rgbaToArgbHex(this._r, this._g, this._b, this._a); 1185 var secondHex8String = hex8String; 1186 var gradientType = this._gradientType ? "GradientType = 1, " : ""; 1187 1188 if (secondColor) { 1189 var s = tinycolor(secondColor); 1190 secondHex8String = "#" + rgbaToArgbHex(s._r, s._g, s._b, s._a); 1191 } 1192 1193 return ( 1194 "progid:DXImageTransform.Microsoft.gradient(" + 1195 gradientType + 1196 "startColorstr=" + 1197 hex8String + 1198 ",endColorstr=" + 1199 secondHex8String + 1200 ")" 1201 ); 1202 }, 1203 toString: function (format) { 1204 var formatSet = !!format; 1205 format = format || this._format; 1206 1207 var formattedString = false; 1208 var hasAlpha = this._a < 1 && this._a >= 0; 1209 var needsAlphaFormat = 1210 !formatSet && 1211 hasAlpha && 1212 (format === "hex" || 1213 format === "hex6" || 1214 format === "hex3" || 1215 format === "hex4" || 1216 format === "hex8" || 1217 format === "name"); 1218 1219 if (needsAlphaFormat) { 1220 // Special case for "transparent", all other non-alpha formats 1221 // will return rgba when there is transparency. 1222 if (format === "name" && this._a === 0) { 1223 return this.toName(); 1224 } 1225 return this.toRgbString(); 1226 } 1227 if (format === "rgb") { 1228 formattedString = this.toRgbString(); 1229 } 1230 if (format === "prgb") { 1231 formattedString = this.toPercentageRgbString(); 1232 } 1233 if (format === "hex" || format === "hex6") { 1234 formattedString = this.toHexString(); 1235 } 1236 if (format === "hex3") { 1237 formattedString = this.toHexString(true); 1238 } 1239 if (format === "hex4") { 1240 formattedString = this.toHex8String(true); 1241 } 1242 if (format === "hex8") { 1243 formattedString = this.toHex8String(); 1244 } 1245 if (format === "name") { 1246 formattedString = this.toName(); 1247 } 1248 if (format === "hsl") { 1249 formattedString = this.toHslString(); 1250 } 1251 if (format === "hsv") { 1252 formattedString = this.toHsvString(); 1253 } 1254 1255 return formattedString || this.toHexString(); 1256 }, 1257 clone: function () { 1258 return tinycolor(this.toString()); 1259 }, 1260 1261 _applyModification: function (fn, args) { 1262 var color = fn.apply(null, [this].concat([].slice.call(args))); 1263 this._r = color._r; 1264 this._g = color._g; 1265 this._b = color._b; 1266 this.setAlpha(color._a); 1267 return this; 1268 }, 1269 lighten: function () { 1270 return this._applyModification(lighten, arguments); 1271 }, 1272 brighten: function () { 1273 return this._applyModification(brighten, arguments); 1274 }, 1275 darken: function () { 1276 return this._applyModification(darken, arguments); 1277 }, 1278 desaturate: function () { 1279 return this._applyModification(desaturate, arguments); 1280 }, 1281 saturate: function () { 1282 return this._applyModification(saturate, arguments); 1283 }, 1284 greyscale: function () { 1285 return this._applyModification(greyscale, arguments); 1286 }, 1287 spin: function () { 1288 return this._applyModification(spin, arguments); 1289 }, 1290 1291 _applyCombination: function (fn, args) { 1292 return fn.apply(null, [this].concat([].slice.call(args))); 1293 }, 1294 analogous: function () { 1295 return this._applyCombination(analogous, arguments); 1296 }, 1297 complement: function () { 1298 return this._applyCombination(complement, arguments); 1299 }, 1300 monochromatic: function () { 1301 return this._applyCombination(monochromatic, arguments); 1302 }, 1303 splitcomplement: function () { 1304 return this._applyCombination(splitcomplement, arguments); 1305 }, 1306 triad: function () { 1307 return this._applyCombination(triad, arguments); 1308 }, 1309 tetrad: function () { 1310 return this._applyCombination(tetrad, arguments); 1311 }, 1312 }; 1313 1314 // If input is an object, force 1 into "1.0" to handle ratios properly 1315 // String input requires "1.0" as input, so 1 will be treated as 1 1316 tinycolor.fromRatio = function (color, opts) { 1317 if (typeof color == "object") { 1318 var newColor = {}; 1319 for (var i in color) { 1320 if (color.hasOwnProperty(i)) { 1321 if (i === "a") { 1322 newColor[i] = color[i]; 1323 } else { 1324 newColor[i] = convertToPercentage(color[i]); 1325 } 1326 } 1327 } 1328 color = newColor; 1329 } 1330 1331 return tinycolor(color, opts); 1332 }; 1333 1334 // Given a string or object, convert that input to RGB
vendor: 8,705 bytes, lines 1335-1615
1335 // Possible string inputs: 1336 // 1337 // "red" 1338 // "#f00" or "f00" 1339 // "#ff0000" or "ff0000" 1340 // "#ff000000" or "ff000000" 1341 // "rgb 255 0 0" or "rgb (255, 0, 0)" 1342 // "rgb 1.0 0 0" or "rgb (1, 0, 0)" 1343 // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" 1344 // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" 1345 // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" 1346 // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" 1347 // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" 1348 // 1349 function inputToRGB(color) { 1350 var rgb = { r: 0, g: 0, b: 0 }; 1351 var a = 1; 1352 var s = null; 1353 var v = null; 1354 var l = null; 1355 var ok = false; 1356 var format = false; 1357 1358 if (typeof color == "string") { 1359 color = stringInputToObject(color); 1360 } 1361 1362 if (typeof color == "object") { 1363 if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) { 1364 rgb = rgbToRgb(color.r, color.g, color.b); 1365 ok = true; 1366 format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; 1367 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) { 1368 s = convertToPercentage(color.s); 1369 v = convertToPercentage(color.v); 1370 rgb = hsvToRgb(color.h, s, v); 1371 ok = true; 1372 format = "hsv"; 1373 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) { 1374 s = convertToPercentage(color.s); 1375 l = convertToPercentage(color.l); 1376 rgb = hslToRgb(color.h, s, l); 1377 ok = true; 1378 format = "hsl"; 1379 } 1380 1381 if (color.hasOwnProperty("a")) { 1382 a = color.a; 1383 } 1384 } 1385 1386 a = boundAlpha(a); 1387 1388 return { 1389 ok: ok, 1390 format: color.format || format, 1391 r: mathMin(255, mathMax(rgb.r, 0)), 1392 g: mathMin(255, mathMax(rgb.g, 0)), 1393 b: mathMin(255, mathMax(rgb.b, 0)), 1394 a: a, 1395 }; 1396 } 1397 1398 // Conversion Functions 1399 // -------------------- 1400 1401 // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: 1402 // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript> 1403 1404 // `rgbToRgb` 1405 // Handle bounds / percentage checking to conform to CSS color spec 1406 // <http://www.w3.org/TR/css3-color/> 1407 // *Assumes:* r, g, b in [0, 255] or [0, 1] 1408 // *Returns:* { r, g, b } in [0, 255] 1409 function rgbToRgb(r, g, b) { 1410 return { 1411 r: bound01(r, 255) * 255, 1412 g: bound01(g, 255) * 255, 1413 b: bound01(b, 255) * 255, 1414 }; 1415 } 1416 1417 // `rgbToHsl` 1418 // Converts an RGB color value to HSL. 1419 // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] 1420 // *Returns:* { h, s, l } in [0,1] 1421 function rgbToHsl(r, g, b) { 1422 r = bound01(r, 255); 1423 g = bound01(g, 255); 1424 b = bound01(b, 255); 1425 1426 var max = mathMax(r, g, b), 1427 min = mathMin(r, g, b); 1428 var h, 1429 s, 1430 l = (max + min) / 2; 1431 1432 if (max == min) { 1433 h = s = 0; // achromatic 1434 } else { 1435 var d = max - min; 1436 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 1437 switch (max) { 1438 case r: 1439 h = (g - b) / d + (g < b ? 6 : 0); 1440 break; 1441 case g: 1442 h = (b - r) / d + 2; 1443 break; 1444 case b: 1445 h = (r - g) / d + 4; 1446 break; 1447 } 1448 1449 h /= 6; 1450 } 1451 1452 return { h: h, s: s, l: l }; 1453 } 1454 1455 // `hslToRgb` 1456 // Converts an HSL color value to RGB. 1457 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] 1458 // *Returns:* { r, g, b } in the set [0, 255] 1459 function hslToRgb(h, s, l) { 1460 var r, g, b; 1461 1462 h = bound01(h, 360); 1463 s = bound01(s, 100); 1464 l = bound01(l, 100); 1465 1466 function hue2rgb(p, q, t) { 1467 if (t < 0) t += 1; 1468 if (t > 1) t -= 1; 1469 if (t < 1 / 6) return p + (q - p) * 6 * t; 1470 if (t < 1 / 2) return q; 1471 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; 1472 return p; 1473 } 1474 1475 if (s === 0) { 1476 r = g = b = l; // achromatic 1477 } else { 1478 var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 1479 var p = 2 * l - q; 1480 r = hue2rgb(p, q, h + 1 / 3); 1481 g = hue2rgb(p, q, h); 1482 b = hue2rgb(p, q, h - 1 / 3); 1483 } 1484 1485 return { r: r * 255, g: g * 255, b: b * 255 }; 1486 } 1487 1488 // `rgbToHsv` 1489 // Converts an RGB color value to HSV 1490 // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] 1491 // *Returns:* { h, s, v } in [0,1] 1492 function rgbToHsv(r, g, b) { 1493 r = bound01(r, 255); 1494 g = bound01(g, 255); 1495 b = bound01(b, 255); 1496 1497 var max = mathMax(r, g, b), 1498 min = mathMin(r, g, b); 1499 var h, 1500 s, 1501 v = max; 1502 1503 var d = max - min; 1504 s = max === 0 ? 0 : d / max; 1505 1506 if (max == min) { 1507 h = 0; // achromatic 1508 } else { 1509 switch (max) { 1510 case r: 1511 h = (g - b) / d + (g < b ? 6 : 0); 1512 break; 1513 case g: 1514 h = (b - r) / d + 2; 1515 break; 1516 case b: 1517 h = (r - g) / d + 4; 1518 break; 1519 } 1520 h /= 6; 1521 } 1522 return { h: h, s: s, v: v }; 1523 } 1524 1525 // `hsvToRgb` 1526 // Converts an HSV color value to RGB. 1527 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] 1528 // *Returns:* { r, g, b } in the set [0, 255] 1529 function hsvToRgb(h, s, v) { 1530 h = bound01(h, 360) * 6; 1531 s = bound01(s, 100); 1532 v = bound01(v, 100); 1533 1534 var i = Math.floor(h), 1535 f = h - i, 1536 p = v * (1 - s), 1537 q = v * (1 - f * s), 1538 t = v * (1 - (1 - f) * s), 1539 mod = i % 6, 1540 r = [v, q, p, p, t, v][mod], 1541 g = [t, v, v, q, p, p][mod], 1542 b = [p, p, t, v, v, q][mod]; 1543 1544 return { r: r * 255, g: g * 255, b: b * 255 }; 1545 } 1546 1547 // `rgbToHex` 1548 // Converts an RGB color to hex 1549 // Assumes r, g, and b are contained in the set [0, 255] 1550 // Returns a 3 or 6 character hex 1551 function rgbToHex(r, g, b, allow3Char) { 1552 var hex = [ 1553 pad2(mathRound(r).toString(16)), 1554 pad2(mathRound(g).toString(16)), 1555 pad2(mathRound(b).toString(16)), 1556 ]; 1557 1558 // Return a 3 character hex if possible 1559 if ( 1560 allow3Char && 1561 hex[0].charAt(0) == hex[0].charAt(1) && 1562 hex[1].charAt(0) == hex[1].charAt(1) && 1563 hex[2].charAt(0) == hex[2].charAt(1) 1564 ) { 1565 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); 1566 } 1567 1568 return hex.join(""); 1569 } 1570 1571 // `rgbaToHex` 1572 // Converts an RGBA color plus alpha transparency to hex 1573 // Assumes r, g, b are contained in the set [0, 255] and 1574 // a in [0, 1]. Returns a 4 or 8 character rgba hex 1575 function rgbaToHex(r, g, b, a, allow4Char) { 1576 var hex = [ 1577 pad2(mathRound(r).toString(16)), 1578 pad2(mathRound(g).toString(16)), 1579 pad2(mathRound(b).toString(16)), 1580 pad2(convertDecimalToHex(a)), 1581 ]; 1582 1583 // Return a 4 character hex if possible 1584 if ( 1585 allow4Char && 1586 hex[0].charAt(0) == hex[0].charAt(1) && 1587 hex[1].charAt(0) == hex[1].charAt(1) && 1588 hex[2].charAt(0) == hex[2].charAt(1) && 1589 hex[3].charAt(0) == hex[3].charAt(1) 1590 ) { 1591 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0); 1592 } 1593 1594 return hex.join(""); 1595 } 1596 1597 // `rgbaToArgbHex` 1598 // Converts an RGBA color to an ARGB Hex8 string 1599 // Rarely used, but required for "toFilter()" 1600 function rgbaToArgbHex(r, g, b, a) { 1601 var hex = [ 1602 pad2(convertDecimalToHex(a)), 1603 pad2(mathRound(r).toString(16)), 1604 pad2(mathRound(g).toString(16)), 1605 pad2(mathRound(b).toString(16)), 1606 ]; 1607 1608 return hex.join(""); 1609 } 1610 1611 // `equals` 1612 // Can be called with any tinycolor input 1613 tinycolor.equals = function (color1, color2) { 1614 if (!color1 || !color2) { 1615 return false;
vendor: 4,315 bytes, lines 1616-1753
1616 } 1617 return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); 1618 }; 1619 1620 tinycolor.random = function () { 1621 return tinycolor.fromRatio({ 1622 r: mathRandom(), 1623 g: mathRandom(), 1624 b: mathRandom(), 1625 }); 1626 }; 1627 1628 // Modification Functions 1629 // ---------------------- 1630 // Thanks to less.js for some of the basics here 1631 // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js> 1632 1633 function desaturate(color, amount) { 1634 amount = amount === 0 ? 0 : amount || 10; 1635 var hsl = tinycolor(color).toHsl(); 1636 hsl.s -= amount / 100; 1637 hsl.s = clamp01(hsl.s); 1638 return tinycolor(hsl); 1639 } 1640 1641 function saturate(color, amount) { 1642 amount = amount === 0 ? 0 : amount || 10; 1643 var hsl = tinycolor(color).toHsl(); 1644 hsl.s += amount / 100; 1645 hsl.s = clamp01(hsl.s); 1646 return tinycolor(hsl); 1647 } 1648 1649 function greyscale(color) { 1650 return tinycolor(color).desaturate(100); 1651 } 1652 1653 function lighten(color, amount) { 1654 amount = amount === 0 ? 0 : amount || 10; 1655 var hsl = tinycolor(color).toHsl(); 1656 hsl.l += amount / 100; 1657 hsl.l = clamp01(hsl.l); 1658 return tinycolor(hsl); 1659 } 1660 1661 function brighten(color, amount) { 1662 amount = amount === 0 ? 0 : amount || 10; 1663 var rgb = tinycolor(color).toRgb(); 1664 rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * -(amount / 100)))); 1665 rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * -(amount / 100)))); 1666 rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * -(amount / 100)))); 1667 return tinycolor(rgb); 1668 } 1669 1670 function darken(color, amount) { 1671 amount = amount === 0 ? 0 : amount || 10; 1672 var hsl = tinycolor(color).toHsl(); 1673 hsl.l -= amount / 100; 1674 hsl.l = clamp01(hsl.l); 1675 return tinycolor(hsl); 1676 } 1677 1678 // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. 1679 // Values outside of this range will be wrapped into this range. 1680 function spin(color, amount) { 1681 var hsl = tinycolor(color).toHsl(); 1682 var hue = (hsl.h + amount) % 360; 1683 hsl.h = hue < 0 ? 360 + hue : hue; 1684 return tinycolor(hsl); 1685 } 1686 1687 // Combination Functions 1688 // --------------------- 1689 // Thanks to jQuery xColor for some of the ideas behind these 1690 // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js> 1691 1692 function complement(color) { 1693 var hsl = tinycolor(color).toHsl(); 1694 hsl.h = (hsl.h + 180) % 360; 1695 return tinycolor(hsl); 1696 } 1697 1698 function triad(color) { 1699 var hsl = tinycolor(color).toHsl(); 1700 var h = hsl.h; 1701 return [ 1702 tinycolor(color), 1703 tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), 1704 tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }), 1705 ]; 1706 } 1707 1708 function tetrad(color) { 1709 var hsl = tinycolor(color).toHsl(); 1710 var h = hsl.h; 1711 return [ 1712 tinycolor(color), 1713 tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), 1714 tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), 1715 tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }), 1716 ]; 1717 } 1718 1719 function splitcomplement(color) { 1720 var hsl = tinycolor(color).toHsl(); 1721 var h = hsl.h; 1722 return [ 1723 tinycolor(color), 1724 tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }), 1725 tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l }), 1726 ]; 1727 } 1728 1729 function analogous(color, results, slices) { 1730 results = results || 6; 1731 slices = slices || 30; 1732 1733 var hsl = tinycolor(color).toHsl(); 1734 var part = 360 / slices; 1735 var ret = [tinycolor(color)]; 1736 1737 for (hsl.h = (hsl.h - ((part * results) >> 1) + 720) % 360; --results; ) { 1738 hsl.h = (hsl.h + part) % 360; 1739 ret.push(tinycolor(hsl)); 1740 } 1741 return ret; 1742 } 1743 1744 function monochromatic(color, results) { 1745 results = results || 6; 1746 var hsv = tinycolor(color).toHsv(); 1747 var h = hsv.h, 1748 s = hsv.s, 1749 v = hsv.v; 1750 var ret = []; 1751 var modification = 1 / results; 1752 1753 while (results--) {
vendor: 4,157 bytes, lines 1754-1862
1754 ret.push(tinycolor({ h: h, s: s, v: v })); 1755 v = (v + modification) % 1; 1756 } 1757 1758 return ret; 1759 } 1760 1761 // Utility Functions 1762 // --------------------- 1763 1764 tinycolor.mix = function (color1, color2, amount) { 1765 amount = amount === 0 ? 0 : amount || 50; 1766 1767 var rgb1 = tinycolor(color1).toRgb(); 1768 var rgb2 = tinycolor(color2).toRgb(); 1769 1770 var p = amount / 100; 1771 1772 var rgba = { 1773 r: (rgb2.r - rgb1.r) * p + rgb1.r, 1774 g: (rgb2.g - rgb1.g) * p + rgb1.g, 1775 b: (rgb2.b - rgb1.b) * p + rgb1.b, 1776 a: (rgb2.a - rgb1.a) * p + rgb1.a, 1777 }; 1778 1779 return tinycolor(rgba); 1780 }; 1781 1782 // Readability Functions 1783 // --------------------- 1784 // <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2) 1785 1786 // `contrast` 1787 // Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) 1788 tinycolor.readability = function (color1, color2) { 1789 var c1 = tinycolor(color1); 1790 var c2 = tinycolor(color2); 1791 return ( 1792 (Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / 1793 (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05) 1794 ); 1795 }; 1796 1797 // `isReadable` 1798 // Ensure that foreground and background color combinations meet WCAG2 guidelines. 1799 // The third argument is an optional Object. 1800 // the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA'; 1801 // the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'. 1802 // If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}. 1803 1804 // *Example* 1805 // tinycolor.isReadable("#000", "#111") => false 1806 // tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false 1807 tinycolor.isReadable = function (color1, color2, wcag2) { 1808 var readability = tinycolor.readability(color1, color2); 1809 var wcag2Parms, out; 1810 1811 out = false; 1812 1813 wcag2Parms = validateWCAG2Parms(wcag2); 1814 switch (wcag2Parms.level + wcag2Parms.size) { 1815 case "AAsmall": 1816 case "AAAlarge": 1817 out = readability >= 4.5; 1818 break; 1819 case "AAlarge": 1820 out = readability >= 3; 1821 break; 1822 case "AAAsmall": 1823 out = readability >= 7; 1824 break; 1825 } 1826 return out; 1827 }; 1828 1829 // `mostReadable` 1830 // Given a base color and a list of possible foreground or background 1831 // colors for that base, returns the most readable color. 1832 // Optionally returns Black or White if the most readable color is unreadable. 1833 // *Example* 1834 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" 1835 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" 1836 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" 1837 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" 1838 tinycolor.mostReadable = function (baseColor, colorList, args) { 1839 var bestColor = null; 1840 var bestScore = 0; 1841 var readability; 1842 var includeFallbackColors, level, size; 1843 args = args || {}; 1844 includeFallbackColors = args.includeFallbackColors; 1845 level = args.level; 1846 size = args.size; 1847 1848 for (var i = 0; i < colorList.length; i++) { 1849 readability = tinycolor.readability(baseColor, colorList[i]); 1850 if (readability > bestScore) { 1851 bestScore = readability; 1852 bestColor = tinycolor(colorList[i]); 1853 } 1854 } 1855 1856 if ( 1857 tinycolor.isReadable(baseColor, bestColor, { level: level, size: size }) || 1858 !includeFallbackColors 1859 ) { 1860 return bestColor; 1861 } else { 1862 args.includeFallbackColors = false;
vendor: 12,185 bytes, lines 1863-2236
1863 return tinycolor.mostReadable(baseColor, ["#fff", "#000"], args); 1864 } 1865 }; 1866 1867 // Big List of Colors 1868 // ------------------ 1869 // <http://www.w3.org/TR/css3-color/#svg-color> 1870 var names = (tinycolor.names = { 1871 aliceblue: "f0f8ff", 1872 antiquewhite: "faebd7", 1873 aqua: "0ff", 1874 aquamarine: "7fffd4", 1875 azure: "f0ffff", 1876 beige: "f5f5dc", 1877 bisque: "ffe4c4", 1878 black: "000", 1879 blanchedalmond: "ffebcd", 1880 blue: "00f", 1881 blueviolet: "8a2be2", 1882 brown: "a52a2a", 1883 burlywood: "deb887", 1884 burntsienna: "ea7e5d", 1885 cadetblue: "5f9ea0", 1886 chartreuse: "7fff00", 1887 chocolate: "d2691e", 1888 coral: "ff7f50", 1889 cornflowerblue: "6495ed", 1890 cornsilk: "fff8dc", 1891 crimson: "dc143c", 1892 cyan: "0ff", 1893 darkblue: "00008b", 1894 darkcyan: "008b8b", 1895 darkgoldenrod: "b8860b", 1896 darkgray: "a9a9a9", 1897 darkgreen: "006400", 1898 darkgrey: "a9a9a9", 1899 darkkhaki: "bdb76b", 1900 darkmagenta: "8b008b", 1901 darkolivegreen: "556b2f", 1902 darkorange: "ff8c00", 1903 darkorchid: "9932cc", 1904 darkred: "8b0000", 1905 darksalmon: "e9967a", 1906 darkseagreen: "8fbc8f", 1907 darkslateblue: "483d8b", 1908 darkslategray: "2f4f4f", 1909 darkslategrey: "2f4f4f", 1910 darkturquoise: "00ced1", 1911 darkviolet: "9400d3", 1912 deeppink: "ff1493", 1913 deepskyblue: "00bfff", 1914 dimgray: "696969", 1915 dimgrey: "696969", 1916 dodgerblue: "1e90ff", 1917 firebrick: "b22222", 1918 floralwhite: "fffaf0", 1919 forestgreen: "228b22", 1920 fuchsia: "f0f", 1921 gainsboro: "dcdcdc", 1922 ghostwhite: "f8f8ff", 1923 gold: "ffd700", 1924 goldenrod: "daa520", 1925 gray: "808080", 1926 green: "008000", 1927 greenyellow: "adff2f", 1928 grey: "808080", 1929 honeydew: "f0fff0", 1930 hotpink: "ff69b4", 1931 indianred: "cd5c5c", 1932 indigo: "4b0082", 1933 ivory: "fffff0", 1934 khaki: "f0e68c", 1935 lavender: "e6e6fa", 1936 lavenderblush: "fff0f5", 1937 lawngreen: "7cfc00", 1938 lemonchiffon: "fffacd", 1939 lightblue: "add8e6", 1940 lightcoral: "f08080", 1941 lightcyan: "e0ffff", 1942 lightgoldenrodyellow: "fafad2", 1943 lightgray: "d3d3d3", 1944 lightgreen: "90ee90", 1945 lightgrey: "d3d3d3", 1946 lightpink: "ffb6c1", 1947 lightsalmon: "ffa07a", 1948 lightseagreen: "20b2aa", 1949 lightskyblue: "87cefa", 1950 lightslategray: "789", 1951 lightslategrey: "789", 1952 lightsteelblue: "b0c4de", 1953 lightyellow: "ffffe0", 1954 lime: "0f0", 1955 limegreen: "32cd32", 1956 linen: "faf0e6", 1957 magenta: "f0f", 1958 maroon: "800000", 1959 mediumaquamarine: "66cdaa", 1960 mediumblue: "0000cd", 1961 mediumorchid: "ba55d3", 1962 mediumpurple: "9370db", 1963 mediumseagreen: "3cb371", 1964 mediumslateblue: "7b68ee", 1965 mediumspringgreen: "00fa9a", 1966 mediumturquoise: "48d1cc", 1967 mediumvioletred: "c71585", 1968 midnightblue: "191970", 1969 mintcream: "f5fffa", 1970 mistyrose: "ffe4e1", 1971 moccasin: "ffe4b5", 1972 navajowhite: "ffdead", 1973 navy: "000080", 1974 oldlace: "fdf5e6", 1975 olive: "808000", 1976 olivedrab: "6b8e23", 1977 orange: "ffa500", 1978 orangered: "ff4500", 1979 orchid: "da70d6", 1980 palegoldenrod: "eee8aa", 1981 palegreen: "98fb98", 1982 paleturquoise: "afeeee", 1983 palevioletred: "db7093", 1984 papayawhip: "ffefd5", 1985 peachpuff: "ffdab9", 1986 peru: "cd853f", 1987 pink: "ffc0cb", 1988 plum: "dda0dd", 1989 powderblue: "b0e0e6", 1990 purple: "800080", 1991 rebeccapurple: "663399", 1992 red: "f00", 1993 rosybrown: "bc8f8f", 1994 royalblue: "4169e1", 1995 saddlebrown: "8b4513", 1996 salmon: "fa8072", 1997 sandybrown: "f4a460", 1998 seagreen: "2e8b57", 1999 seashell: "fff5ee", 2000 sienna: "a0522d", 2001 silver: "c0c0c0", 2002 skyblue: "87ceeb", 2003 slateblue: "6a5acd", 2004 slategray: "708090", 2005 slategrey: "708090", 2006 snow: "fffafa", 2007 springgreen: "00ff7f", 2008 steelblue: "4682b4", 2009 tan: "d2b48c", 2010 teal: "008080", 2011 thistle: "d8bfd8", 2012 tomato: "ff6347", 2013 turquoise: "40e0d0", 2014 violet: "ee82ee", 2015 wheat: "f5deb3", 2016 white: "fff", 2017 whitesmoke: "f5f5f5", 2018 yellow: "ff0", 2019 yellowgreen: "9acd32", 2020 }); 2021 2022 // Make it easy to access colors via `hexNames[hex]` 2023 var hexNames = (tinycolor.hexNames = flip(names)); 2024 2025 // Utilities 2026 // --------- 2027 2028 // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` 2029 function flip(o) { 2030 var flipped = {}; 2031 for (var i in o) { 2032 if (o.hasOwnProperty(i)) { 2033 flipped[o[i]] = i; 2034 } 2035 } 2036 return flipped; 2037 } 2038 2039 // Return a valid alpha value [0,1] with all invalid values being set to 1 2040 function boundAlpha(a) { 2041 a = parseFloat(a); 2042 2043 if (isNaN(a) || a < 0 || a > 1) { 2044 a = 1; 2045 } 2046 2047 return a; 2048 } 2049 2050 // Take input from [0, n] and return it as [0, 1] 2051 function bound01(n, max) { 2052 if (isOnePointZero(n)) { 2053 n = "100%"; 2054 } 2055 2056 var processPercent = isPercentage(n); 2057 n = mathMin(max, mathMax(0, parseFloat(n))); 2058 2059 // Automatically convert percentage into number 2060 if (processPercent) { 2061 n = parseInt(n * max, 10) / 100; 2062 } 2063 2064 // Handle floating point rounding errors 2065 if (Math.abs(n - max) < 0.000001) { 2066 return 1; 2067 } 2068 2069 // Convert into [0, 1] range if it isn't already 2070 return (n % max) / parseFloat(max); 2071 } 2072 2073 // Force a number between 0 and 1 2074 function clamp01(val) { 2075 return mathMin(1, mathMax(0, val)); 2076 } 2077 2078 // Parse a base-16 hex value into a base-10 integer 2079 function parseIntFromHex(val) { 2080 return parseInt(val, 16); 2081 } 2082 2083 // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 2084 // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0> 2085 function isOnePointZero(n) { 2086 return typeof n == "string" && n.indexOf(".") != -1 && parseFloat(n) === 1; 2087 } 2088 2089 // Check to see if string passed in is a percentage 2090 function isPercentage(n) { 2091 return typeof n === "string" && n.indexOf("%") != -1; 2092 } 2093 2094 // Force a hex value to have 2 characters 2095 function pad2(c) { 2096 return c.length == 1 ? "0" + c : "" + c; 2097 } 2098 2099 // Replace a decimal with it's percentage value 2100 function convertToPercentage(n) { 2101 if (n <= 1) { 2102 n = n * 100 + "%"; 2103 } 2104 2105 return n; 2106 } 2107 2108 // Converts a decimal to a hex value 2109 function convertDecimalToHex(d) { 2110 return Math.round(parseFloat(d) * 255).toString(16); 2111 } 2112 // Converts a hex value to a decimal 2113 function convertHexToDecimal(h) { 2114 return parseIntFromHex(h) / 255; 2115 } 2116 2117 var matchers = (function () { 2118 // <http://www.w3.org/TR/css3-values/#integers> 2119 var CSS_INTEGER = "[-\\+]?\\d+%?"; 2120 2121 // <http://www.w3.org/TR/css3-values/#number-value> 2122 var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; 2123 2124 // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. 2125 var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; 2126 2127 // Actual matching. 2128 // Parentheses and commas are optional, but not required. 2129 // Whitespace can take the place of commas or opening paren 2130 var PERMISSIVE_MATCH3 = 2131 "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; 2132 var PERMISSIVE_MATCH4 = 2133 "[\\s|\\(]+(" + 2134 CSS_UNIT + 2135 ")[,|\\s]+(" + 2136 CSS_UNIT + 2137 ")[,|\\s]+(" + 2138 CSS_UNIT + 2139 ")[,|\\s]+(" + 2140 CSS_UNIT + 2141 ")\\s*\\)?"; 2142 2143 return { 2144 CSS_UNIT: new RegExp(CSS_UNIT), 2145 rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), 2146 rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), 2147 hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), 2148 hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), 2149 hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), 2150 hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), 2151 hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2152 hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2153 hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2154 hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2155 }; 2156 })(); 2157 2158 // `isValidCSSUnit` 2159 // Take in a single string / number and check to see if it looks like a CSS unit 2160 // (see `matchers` above for definition). 2161 function isValidCSSUnit(color) { 2162 return !!matchers.CSS_UNIT.exec(color); 2163 } 2164 2165 // `stringInputToObject` 2166 // Permissive string parsing. Take in a number of formats, and output an object 2167 // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` 2168 function stringInputToObject(color) { 2169 color = color.replace(trimLeft, "").replace(trimRight, "").toLowerCase(); 2170 var named = false; 2171 if (names[color]) { 2172 color = names[color]; 2173 named = true; 2174 } else if (color == "transparent") { 2175 return { r: 0, g: 0, b: 0, a: 0, format: "name" }; 2176 } 2177 2178 // Try to match string input using regular expressions. 2179 // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] 2180 // Just return an object and let the conversion functions handle that. 2181 // This way the result will be the same whether the tinycolor is initialized with string or object. 2182 var match; 2183 if ((match = matchers.rgb.exec(color))) { 2184 return { r: match[1], g: match[2], b: match[3] }; 2185 } 2186 if ((match = matchers.rgba.exec(color))) { 2187 return { r: match[1], g: match[2], b: match[3], a: match[4] }; 2188 } 2189 if ((match = matchers.hsl.exec(color))) { 2190 return { h: match[1], s: match[2], l: match[3] }; 2191 } 2192 if ((match = matchers.hsla.exec(color))) { 2193 return { h: match[1], s: match[2], l: match[3], a: match[4] }; 2194 } 2195 if ((match = matchers.hsv.exec(color))) { 2196 return { h: match[1], s: match[2], v: match[3] }; 2197 } 2198 if ((match = matchers.hsva.exec(color))) { 2199 return { h: match[1], s: match[2], v: match[3], a: match[4] }; 2200 } 2201 if ((match = matchers.hex8.exec(color))) { 2202 return { 2203 r: parseIntFromHex(match[1]), 2204 g: parseIntFromHex(match[2]), 2205 b: parseIntFromHex(match[3]), 2206 a: convertHexToDecimal(match[4]), 2207 format: named ? "name" : "hex8", 2208 }; 2209 } 2210 if ((match = matchers.hex6.exec(color))) { 2211 return { 2212 r: parseIntFromHex(match[1]), 2213 g: parseIntFromHex(match[2]), 2214 b: parseIntFromHex(match[3]), 2215 format: named ? "name" : "hex", 2216 }; 2217 } 2218 if ((match = matchers.hex4.exec(color))) { 2219 return { 2220 r: parseIntFromHex(match[1] + "" + match[1]), 2221 g: parseIntFromHex(match[2] + "" + match[2]), 2222 b: parseIntFromHex(match[3] + "" + match[3]), 2223 a: convertHexToDecimal(match[4] + "" + match[4]), 2224 format: named ? "name" : "hex8", 2225 }; 2226 } 2227 if ((match = matchers.hex3.exec(color))) { 2228 return { 2229 r: parseIntFromHex(match[1] + "" + match[1]), 2230 g: parseIntFromHex(match[2] + "" + match[2]), 2231 b: parseIntFromHex(match[3] + "" + match[3]), 2232 format: named ? "name" : "hex", 2233 }; 2234 } 2235 2236 return false;
2237 } 2238 2239 function validateWCAG2Parms(parms) { 2240 // return valid WCAG2 parms for isReadable. 2241 // If input parms are invalid, return {"level":"AA", "size":"small"} 2242 var level, size; 2243 parms = parms || { level: "AA", size: "small" }; 2244 level = (parms.level || "AA").toUpperCase(); 2245 size = (parms.size || "small").toLowerCase(); 2246 if (level !== "AA" && level !== "AAA") { 2247 level = "AA"; 2248 } 2249 if (size !== "small" && size !== "large") { 2250 size = "small"; 2251 } 2252 return { level: level, size: size }; 2253 } 2254 2255 const $$1 = jQuery; 2256 class Server { 2257 constructor() { 2258 this.apiUrl = MapSVG.urls.api; 2259 } 2260 getUrl(path) { 2261 return this.apiUrl + path; 2262 } 2263 get(path, data) { 2264 return $$1.ajax({ 2265 url: this.apiUrl + path, 2266 type: "GET", 2267 data: data, 2268 beforeSend: function (xhr) { 2269 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2270 }, 2271 }); 2272 } 2273 post(path, data) { 2274 const ajaxParams = { 2275 url: this.apiUrl + path, 2276 type: "POST", 2277 data: data, 2278 beforeSend: function (xhr) { 2279 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2280 }, 2281 }; 2282 if (data instanceof FormData) { 2283 ajaxParams["processData"] = false; 2284 ajaxParams["contentType"] = false; 2285 } 2286 return $$1.ajax(ajaxParams); 2287 } 2288 put(path, data) { 2289 const ajaxParams = { 2290 url: this.apiUrl + path, 2291 type: "POST", 2292 data: data, 2293 beforeSend: function (xhr) { 2294 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2295 xhr.setRequestHeader("X-HTTP-Method-Override", "PUT"); 2296 }, 2297 }; 2298 if (data instanceof FormData) { 2299 ajaxParams["processData"] = false; 2300 ajaxParams["contentType"] = false; 2301 } 2302 return $$1.ajax(ajaxParams); 2303 } 2304 delete(path, data) { 2305 return $$1.ajax({ 2306 url: this.apiUrl + path, 2307 type: "POST", 2308 data: data, 2309 beforeSend: function (xhr) { 2310 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2311 xhr.setRequestHeader("X-HTTP-Method-Override", "DELETE"); 2312 }, 2313 }); 2314 } 2315 ajax(path, data) { 2316 data.url = this.getUrl(path); 2317 data.beforeSend = function (xhr) { 2318 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2319 }; 2320 return $$1.ajax(data); 2321 } 2322 } 2323 2324 class Events { 2325 constructor(context) { 2326 this.events = {}; 2327 this.context = context; 2328 } 2329 on(event, callbackOrObjectType, callback) { 2330 if (!this.events[event]) 2331 this.events[event] = []; 2332 let callbackFunction; 2333 if (typeof callbackOrObjectType === "string") { 2334 callbackFunction = callback; 2335 } 2336 else { 2337 callbackFunction = callbackOrObjectType; 2338 } 2339 this.events[event].push(callbackFunction); 2340 return this; 2341 } 2342 off(event, callback) { 2343 const _this = this; 2344 if (this.events[event] && this.events[event].length) { 2345 this.events[event].forEach(function (_callback, index) { 2346 if (typeof callback === "undefined") { 2347 _this.events[event].splice(index, 1); 2348 } 2349 else if (_callback === callback) { 2350 _this.events[event].splice(index, 1); 2351 } 2352 }); 2353 } 2354 return this; 2355 } 2356 trigger(event, thisArg, args) { 2357 if (this.events[event] && this.events[event].length) 2358 this.events[event].forEach((callback) => { 2359 try { 2360 callback && callback.apply(thisArg || this.context, args || [this.context]); 2361 } 2362 catch (err) { 2363 console.error(err); 2364 } 2365 }); 2366 return this; 2367 } 2368 } 2369 2370 class ArrayIndexed extends Array { 2371 constructor(indexKey, items, options) { 2372 if (items) { 2373 super(...items); 2374 } 2375 else { 2376 super(); 2377 } 2378 this.key = indexKey; 2379 this.dict = {}; 2380 this.nextId = 1; 2381 if (options) { 2382 this.options = options; 2383 } 2384 else { 2385 this.options = { autoId: false, unique: false }; 2386 } 2387 if (this.length > 0) { 2388 let i = 0; 2389 const _this = this; 2390 if (this.options.autoId) { 2391 let maxId = 0; 2392 let missingIds = false;
2393 this.forEach(function (item) { 2394 if (item[_this.key] != null) { 2395 if (item[_this.key] > maxId) { 2396 maxId = item[_this.key]; 2397 } 2398 } 2399 else { 2400 missingIds = true; 2401 } 2402 }); 2403 this.nextId = ++maxId; 2404 if (missingIds) { 2405 this.forEach(function (item) { 2406 if (item[_this.key] == null) { 2407 item[_this.key] = _this.nextId; 2408 _this.nextId++; 2409 } 2410 }); 2411 } 2412 } 2413 this.forEach(function (item) { 2414 _this.dict[item[_this.key]] = i; 2415 i++; 2416 }); 2417 } 2418 } 2419 push(item) { 2420 const length = super.push(item); 2421 if (this.options.autoId === true) { 2422 item[this.key] = this.nextId; 2423 this.nextId++; 2424 } 2425 this.dict[item[this.key]] = length - 1; 2426 return length; 2427 } 2428 pop() { 2429 const item = this[this.length - 1]; 2430 const id = item[this.key]; 2431 const length = super.pop(); 2432 delete this.dict[id]; 2433 this.reindex(); 2434 return super.pop(); 2435 } 2436 update(data) { 2437 if (data[this.key] != null) { 2438 const obj = this.get(data[this.key]); 2439 for (const i in data) { 2440 obj[i] = data[i]; 2441 } 2442 return obj; 2443 } 2444 return false; 2445 } 2446 get(id) { 2447 return this.findById(id); 2448 } 2449 findById(id) { 2450 return this[this.dict[id]]; 2451 } 2452 deleteById(id) { 2453 const index = this.dict[id]; 2454 if (typeof index !== "undefined") { 2455 delete this.dict[id]; 2456 this.splice(index, 1); 2457 } 2458 } 2459 delete(id) { 2460 this.deleteById(id); 2461 } 2462 clear() { 2463 this.length = 0; 2464 this.reindex(); 2465 } 2466 reindex() { 2467 const _this = this; 2468 this.dict = {}; 2469 this.forEach(function (item, index) { 2470 _this.dict[item[_this.key]] = index; 2471 }); 2472 } 2473 sort(compareFn) { 2474 super.sort(compareFn); 2475 this.reindex(); 2476 return this; 2477 } 2478 splice(start, deleteCount) { 2479 const res = super.splice(start, deleteCount); 2480 this.reindex(); 2481 return res; 2482 } 2483 } 2484 2485 class SchemaField { 2486 constructor(field) { 2487 const booleans = ["visible", "searchable", "readonly", "protected"]; 2488 for (const key in field) { 2489 this[key] = field[key]; 2490 } 2491 booleans.forEach((paramName) => { 2492 if (typeof this[paramName] !== "undefined") { 2493 this[paramName] = MapSVG.parseBoolean(this[paramName]); 2494 } 2495 else { 2496 this[paramName] = false; 2497 } 2498 }); 2499 if (typeof this.options !== "undefined") { 2500 if (!(this.options instanceof ArrayIndexed)) { 2501 this.options = new ArrayIndexed("value", this.options); 2502 } 2503 } 2504 } 2505 } 2506 2507 class Schema { 2508 constructor(options) { 2509 this.fields = new ArrayIndexed("name"); 2510 this.build(options); 2511 this.lastChangeTime = Date.now(); 2512 this.events = new Events(this); 2513 } 2514 build(options) { 2515 const allowedParams = ["id", "title", "type", "name", "fields"]; 2516 allowedParams.forEach((paramName) => { 2517 const setter = "set" + MapSVG.ucfirst(paramName); 2518 if (typeof options[paramName] !== "undefined" && typeof this[setter] == "function") { 2519 this[setter](options[paramName]); 2520 } 2521 }); 2522 } 2523 update(options) { 2524 this.build(options); 2525 } 2526 setId(id) { 2527 this.id = id; 2528 } 2529 setTitle(title) { 2530 this.title = title; 2531 } 2532 setName(name) { 2533 this.name = name; 2534 } 2535 loaded() { 2536 return this.fields.length !== 0; 2537 } 2538 setFields(fields) { 2539 if (fields) { 2540 this.fields.clear(); 2541 fields.forEach((fieldParams) => { 2542 this.fields.push(new SchemaField(fieldParams)); 2543 }); 2544 } 2545 } 2546 getFields() { 2547 return this.fields; 2548 } 2549 getFieldsAsArray() { 2550 return this.fields; 2551 } 2552 getFieldNames() { 2553 return this.fields.map((f) => f.name); 2554 } 2555 getField(field) { 2556 return this.fields.findById(field); 2557 } 2558 getFieldByType(type) { 2559 let f = null; 2560 this.fields.forEach(function (field) { 2561 if (field.type === type) 2562 f = field; 2563 }); 2564 return f; 2565 } 2566 getColumns(filters) { 2567 filters = filters || {}; 2568 const columns = this.fields; 2569 const needfilters = Object.keys(filters).length !== 0; 2570 let results = []; 2571 if (needfilters) { 2572 let filterpass; 2573 columns.forEach(function (obj) { 2574 filterpass = true; 2575 for (const param in filters) { 2576 filterpass = obj[param] == filters[param]; 2577 } 2578 filterpass && results.push(obj); 2579 }); 2580 } 2581 else { 2582 results = columns; 2583 } 2584 return results; 2585 } 2586 getData() { 2587 const data = { 2588 id: this.id, 2589 title: this.title, 2590 name: this.name, 2591 fields: this.fields, 2592 type: this.type, 2593 }; 2594 return data; 2595 } 2596 } 2597 2598 class Query { 2599 constructor(options) { 2600 this.filters = {}; 2601 this.filterout = {}; 2602 this.page = 1; 2603 if (options) { 2604 for (const i in options) { 2605 if (typeof options[i] !== "undefined") { 2606 this[i] = options[i]; 2607 } 2608 } 2609 } 2610 } 2611 setFields(fields) { 2612 const _this = this; 2613 for (const key in fields) { 2614 if (key == "filters") { 2615 _this.setFilters(fields[key]); 2616 } 2617 else { 2618 _this[key] = fields[key]; 2619 } 2620 } 2621 } 2622 update(query) { 2623 for (const i in query) { 2624 if (typeof query[i] !== "undefined") { 2625 if (i === "filters") { 2626 this.setFilters(query[i]); 2627 } 2628 else { 2629 this[i] = query[i]; 2630 } 2631 } 2632 } 2633 } 2634 get() { 2635 return { 2636 search: this.search, 2637 searchField: this.searchField, 2638 searchFallback: this.searchFallback, 2639 filters: this.filters, 2640 filterout: this.filterout, 2641 page: this.page, 2642 sort: this.sort, 2643 perpage: this.perpage, 2644 lastpage: this.lastpage, 2645 }; 2646 } 2647 clearFilters() { 2648 this.resetFilters(); 2649 } 2650 setFilters(fields) { 2651 const _this = this; 2652 for (const key in fields) { 2653 if (fields[key] === null || fields[key] === "" || fields[key] === undefined) { 2654 if (_this.filters[key]) { 2655 delete _this.filters[key]; 2656 } 2657 } 2658 else { 2659 _this.filters[key] = fields[key]; 2660 } 2661 } 2662 } 2663 setSearch(search) { 2664 this.search = search; 2665 } 2666 setFilterOut(fields) {
2667 this.filterout = fields; 2668 } 2669 resetFilters(fields) { 2670 this.filters = {}; 2671 this.setSearch(""); 2672 } 2673 setFilterField(field, value) { 2674 this.filters[field] = value; 2675 } 2676 hasFilters() { 2677 return Object.keys(this.filters).length > 0 || this.search.length > 0; 2678 } 2679 removeFilter(fieldName) { 2680 this.filters[fieldName] = null; 2681 delete this.filters[fieldName]; 2682 } 2683 requestSchema(requestSchema) { 2684 this.withSchema = requestSchema ? requestSchema : true; 2685 } 2686 } 2687 2688 class LocationAddress { 2689 constructor(fields) { 2690 for (const i in fields) { 2691 this[i] = fields[i]; 2692 } 2693 } 2694 getData() { 2695 const copy = {}; 2696 [ 2697 "route", 2698 "address_formatted", 2699 "administrative_area_level_1", 2700 "administrative_area_level_1_short", 2701 "administrative_area_level_2", 2702 "administrative_area_level_2_short", 2703 "country", 2704 "country_short", 2705 "postal_code", 2706 ].forEach((field) => { 2707 if (this[field]) { 2708 copy[field] = this[field]; 2709 } 2710 }); 2711 return copy; 2712 } 2713 get state() { 2714 return this.country_short === "US" ? this.administrative_area_level_1 : null; 2715 } 2716 get state_short() { 2717 return this.country_short === "US" ? this.administrative_area_level_1_short : null; 2718 } 2719 get county() { 2720 return this.country_short === "US" ? this.administrative_area_level_2 : null; 2721 } 2722 get zip() { 2723 return this.postal_code; 2724 } 2725 } 2726 2727 class ScreenPoint { 2728 constructor(x, y) { 2729 this.x = x; 2730 this.y = y; 2731 } 2732 } 2733 class SVGPoint { 2734 constructor(x, y) { 2735 let _x, _y; 2736 if (typeof x === "object") { 2737 if (x.x && x.y) { 2738 _x = parseFloat(x.x + ""); 2739 _y = parseFloat(x.y + ""); 2740 } 2741 else { 2742 console.error("MapSVG: incorrect format of {x, y} object for SVGPoint."); 2743 _x = 0; 2744 _y = 0; 2745 } 2746 } 2747 else { 2748 _x = parseFloat(x + ""); 2749 _y = parseFloat(y + ""); 2750 } 2751 this.x = _x; 2752 this.y = _y; 2753 } 2754 toString() { 2755 return this.x + "," + this.y; 2756 } 2757 } 2758 class GeoPoint { 2759 constructor(lat, lng) { 2760 let _lat, _lng; 2761 if (typeof lat === "object") { 2762 if (lat.lat && lat.lng) { 2763 _lat = parseFloat(lat.lat + ""); 2764 _lng = parseFloat(lat.lng + ""); 2765 } 2766 else { 2767 console.error("MapSVG: incorrect format of {lat, lng} object for GeoPoint."); 2768 _lat = 0; 2769 _lng = 0; 2770 } 2771 } 2772 else { 2773 _lat = parseFloat(lat + ""); 2774 _lng = parseFloat(lng + ""); 2775 } 2776 this.lat = _lat; 2777 this.lng = _lng; 2778 } 2779 toString() { 2780 return this.lat + "," + this.lng; 2781 } 2782 } 2783 class Location { 2784 constructor(options) { 2785 this.update(options); 2786 } 2787 update(options) { 2788 if (options.object) { 2789 this.setObject(options.object); 2790 } 2791 if (options.img) { 2792 this.setImage(options.img); 2793 } 2794 if (options.address) { 2795 this.setAddress(options.address); 2796 } 2797 if (options.svgPoint) { 2798 this.setSvgPoint(options.svgPoint); 2799 } 2800 if (options.geoPoint) { 2801 this.setGeoPoint(options.geoPoint); 2802 } 2803 } 2804 setObject(object) { 2805 this.object = object; 2806 } 2807 setImage(imgUrl) { 2808 if (typeof imgUrl !== "string") { 2809 return; 2810 } 2811 let src = imgUrl.split("/").pop(); 2812 if (imgUrl.indexOf("uploads") !== -1) { 2813 src = "uploads/" + src; 2814 } 2815 this.img = src; 2816 this.imagePath = this.getImageUrl(); 2817 this.marker && this.marker && this.marker.setImage(this.imagePath); 2818 } 2819 getImageUrl() { 2820 if (this.img && this.img.indexOf("uploads/") === 0) { 2821 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2822 } 2823 else { 2824 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2825 } 2826 } 2827 setAddress(address) { 2828 this.address = new LocationAddress(address); 2829 } 2830 setSvgPoint(svgPoint) { 2831 this.svgPoint = svgPoint instanceof SVGPoint ? svgPoint : new SVGPoint(svgPoint); 2832 if (this.marker) { 2833 this.marker.setSvgPointFromLocation(); 2834 } 2835 } 2836 setGeoPoint(geoPoint) { 2837 this.geoPoint = geoPoint instanceof GeoPoint ? geoPoint : new GeoPoint(geoPoint); 2838 if (this.marker) { 2839 this.marker.setSvgPointFromLocation(); 2840 } 2841 } 2842 getMarkerImage() { 2843 if (this.img && this.img.indexOf("uploads/") === 0) { 2844 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2845 } 2846 else { 2847 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2848 } 2849 } 2850 getData() { 2851 const data = { 2852 img: this.img, 2853 imagePath: this.imagePath, 2854 markerImagePath: this.marker && this.marker.object 2855 ? this.marker.object.getMarkerImage() 2856 : this.imagePath, 2857 address: this.address, 2858 }; 2859 if (this.geoPoint) { 2860 data.geoPoint = { lat: this.geoPoint.lat, lng: this.geoPoint.lng }; 2861 } 2862 if (this.svgPoint) { 2863 data.svgPoint = { x: this.svgPoint.x, y: this.svgPoint.y }; 2864 } 2865 return data; 2866 } 2867 } 2868 2869 class CustomObject { 2870 constructor(params, schema) { 2871 this.initialLoad = true; 2872 this.setSchema(schema); 2873 this.dirtyFields = []; 2874 this.regions = []; 2875 this._regions = {}; 2876 if (params.id !== undefined) { 2877 this.id = params.id; 2878 } 2879 this.initialLoad = true; 2880 this.build(params); 2881 this.initialLoad = false;
2882 if (this.id) { 2883 this.clearDirtyFields(); 2884 } 2885 } 2886 setSchema(schema) { 2887 this.schema = schema; 2888 this.schema.events.on("changed", () => this.setLocationField()); 2889 this.fields = schema.getFieldNames(); 2890 this.setLocationField(); 2891 } 2892 build(params) { 2893 for (const fieldName in params) { 2894 const field = this.schema.getField(fieldName); 2895 if (field) { 2896 if (!this.initialLoad) { 2897 this.dirtyFields.push(fieldName); 2898 } 2899 switch (field.type) { 2900 case "region": 2901 this.regions = params[fieldName]; 2902 break; 2903 case "location": 2904 if (params[fieldName] != null && 2905 params[fieldName] != "" && 2906 Object.keys(params[fieldName]).length !== 0) { 2907 const data = { 2908 img: this.isMarkersByFieldEnabled() 2909 ? this.getMarkerImage() 2910 : params[fieldName].img, 2911 address: new LocationAddress(params[fieldName].address), 2912 }; 2913 if (params[fieldName].geoPoint && 2914 params[fieldName].geoPoint.lat && 2915 params[fieldName].geoPoint.lng) { 2916 data.geoPoint = new GeoPoint(params[fieldName].geoPoint); 2917 } 2918 else if (params[fieldName].svgPoint && 2919 params[fieldName].svgPoint.x && 2920 params[fieldName].svgPoint.y) { 2921 data.svgPoint = new SVGPoint(params[fieldName].svgPoint); 2922 } 2923 if (this.location != null) { 2924 this.location.update(data); 2925 } 2926 else { 2927 this.location = new Location(data); 2928 } 2929 } 2930 else { 2931 this.location = null; 2932 } 2933 break; 2934 case "post": 2935 if (params.post) { 2936 this.post = params.post; 2937 } 2938 break; 2939 case "select": 2940 this[fieldName] = params[fieldName]; 2941 if (!field.multiselect) { 2942 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2943 } 2944 break; 2945 case "radio": 2946 this[fieldName] = params[fieldName]; 2947 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2948 break; 2949 default: 2950 this[fieldName] = params[fieldName]; 2951 break; 2952 } 2953 } 2954 } 2955 const locationField = this.getLocationField(); 2956 if (locationField && this.isMarkersByFieldEnabled() && this.isMarkerFieldChanged(params)) { 2957 this.reloadMarkerImage(); 2958 } 2959 } 2960 isMarkerFieldChanged(params) { 2961 return Object.keys(params).indexOf(this.getLocationField().markerField) !== -1; 2962 } 2963 setLocationField() { 2964 } 2965 getLocationField() { 2966 return this.schema.getFieldByType("location"); 2967 } 2968 reloadMarkerImage() { 2969 this.location && this.location.setImage(this.getMarkerImage()); 2970 } 2971 getMarkerImage() { 2972 let fieldValue; 2973 if (this.isMarkersByFieldEnabled()) { 2974 const locationField = this.getLocationField(); 2975 fieldValue = this[locationField.markerField]; 2976 if (!fieldValue) { 2977 return locationField.defaultMarkerPath || MapSVG.defaultMarkerImage; 2978 } 2979 else { 2980 if (locationField.markerField === "regions") { 2981 fieldValue = fieldValue[0] && fieldValue[0].id; 2982 } 2983 else if (typeof fieldValue === "object" && fieldValue.length) { 2984 fieldValue = fieldValue[0].value; 2985 } 2986 return (locationField.markersByField[fieldValue] || 2987 locationField.defaultMarkerPath || 2988 MapSVG.defaultMarkerImage); 2989 } 2990 } 2991 else { 2992 return this.location.imagePath; 2993 } 2994 } 2995 isMarkersByFieldEnabled() { 2996 const locationField = this.getLocationField(); 2997 if (!locationField) { 2998 return false;
2999 } 3000 if (locationField.markersByFieldEnabled && 3001 locationField.markerField && 3002 Object.values(locationField.markersByField).length > 0) { 3003 return true; 3004 } 3005 else { 3006 return false; 3007 } 3008 } 3009 clone() { 3010 const data = this.getData(); 3011 return new CustomObject(data, this.schema); 3012 } 3013 getEnumLabel(field, params, fieldName) { 3014 const value = field.options.get(params[fieldName]); 3015 if (typeof value !== "undefined") { 3016 return value.label; 3017 } 3018 else { 3019 return ""; 3020 } 3021 } 3022 update(params) { 3023 this.build(params); 3024 } 3025 getDirtyFields() { 3026 const data = {}; 3027 this.dirtyFields.forEach((field) => { 3028 data[field] = this[field]; 3029 }); 3030 data.id = this.id; 3031 if (data.location != null) { 3032 data.location = data.location.getData(); 3033 } 3034 if (this.schema.getFieldByType("region")) { 3035 data.regions = this.regions; 3036 } 3037 return data; 3038 } 3039 clearDirtyFields() { 3040 this.dirtyFields = []; 3041 } 3042 getData() { 3043 const data = {}; 3044 const fields = this.schema.getFields(); 3045 fields.forEach((field) => { 3046 switch (field.type) { 3047 case "region": 3048 data[field.name] = this[field.name]; 3049 break; 3050 case "select": 3051 data[field.name] = this[field.name]; 3052 if (!field.multiselect) { 3053 data[field.name + "_text"] = this[field.name + "_text"]; 3054 } 3055 break; 3056 case "post": 3057 data[field.name] = this[field.name]; 3058 data["post"] = this.post; 3059 break; 3060 case "status": 3061 case "radio": 3062 data[field.name] = this[field.name]; 3063 data[field.name + "_text"] = this[field.name + "_text"]; 3064 break; 3065 case "location": 3066 data[field.name] = this[field.name] ? this[field.name].getData() : null; 3067 break; 3068 default: 3069 data[field.name] = this[field.name]; 3070 break; 3071 } 3072 }); 3073 return data; 3074 } 3075 getRegions(regionsTableName) { 3076 return this.regions; 3077 } 3078 getRegionsForTable(regionsTableName) { 3079 return this.regions 3080 ? this.regions.filter((region) => !region.tableName || region.tableName === regionsTableName) 3081 : []; 3082 } 3083 } 3084 3085 const $$2 = jQuery; 3086 class Repository { 3087 constructor(objectName, path) { 3088 this.server = new Server(); 3089 this.query = new Query(); 3090 this.events = new Events(this); 3091 this.className = ""; 3092 this.objectNameSingle = objectName; 3093 this.objectNameMany = objectName + "s"; 3094 this.setPath(path); 3095 this.objects = new ArrayIndexed("id"); 3096 this.completeChunks = 0; 3097 } 3098 setNoFiltersNoLoad(value) { 3099 this.noFiltersNoLoad = value; 3100 } 3101 setDataSource(path) { 3102 this.setPath(path); 3103 this.query = new Query({ withSchema: true }); 3104 return this.find().done(() => { 3105 this.query.update({ withSchema: false }); 3106 }); 3107 } 3108 setPath(path) { 3109 this.path = path.replace(/\/+$/, "") + "/"; 3110 } 3111 setSchema(schema) { 3112 this.schema = schema; 3113 } 3114 getSchema() { 3115 return this.schema; 3116 } 3117 loadDataFromResponse(response) { 3118 let data; 3119 data = this.decodeData(response); 3120 this.objects.clear(); 3121 if (data[this.objectNameMany] && data[this.objectNameMany].length) { 3122 this.hasMoreRecords = 3123 this.query.perpage && data[this.objectNameMany].length > this.query.perpage; 3124 if (this.hasMoreRecords) { 3125 data[this.objectNameMany].pop(); 3126 }
3127 data[this.objectNameMany].forEach((obj) => { 3128 this.objects.push(obj); 3129 }); 3130 } 3131 else { 3132 this.hasMoreRecords = false; 3133 } 3134 this.loaded = true; 3135 this.events.trigger("loaded"); 3136 } 3137 reload() { 3138 return this.find(); 3139 } 3140 create(object) { 3141 const defer = jQuery.Deferred(); 3142 defer.promise(); 3143 const data = {}; 3144 data[this.objectNameSingle] = this.encodeData(object); 3145 this.server 3146 .post(this.path, data) 3147 .done((response) => { 3148 const data = this.decodeData(response); 3149 const object = data[this.objectNameSingle]; 3150 this.objects.push(object); 3151 defer.resolve(object); 3152 this.events.trigger("created", this, [object]); 3153 }) 3154 .fail((response) => { 3155 defer.reject(response); 3156 }); 3157 return defer; 3158 } 3159 findById(id, nocache = false) { 3160 const defer = jQuery.Deferred(); 3161 defer.promise(); 3162 let object; 3163 if (!nocache) { 3164 object = this.objects.findById(id.toString()); 3165 } 3166 if (!nocache && object) { 3167 defer.resolve(object); 3168 } 3169 else { 3170 this.server 3171 .get(this.path + id) 3172 .done((response) => { 3173 const data = this.decodeData(response); 3174 defer.resolve(data[this.objectNameSingle]); 3175 }) 3176 .fail((response) => { 3177 defer.reject(response); 3178 }); 3179 } 3180 return defer; 3181 } 3182 find(query) { 3183 this.events.trigger("load"); 3184 const defer = jQuery.Deferred(); 3185 defer.promise(); 3186 if (typeof query !== "undefined") { 3187 this.query.update(query); 3188 } 3189 if (this.noFiltersNoLoad && !this.query.hasFilters()) { 3190 this.objects.clear(); 3191 this.events.trigger("loaded"); 3192 defer.resolve(this.getLoaded()); 3193 return defer; 3194 } 3195 if (!this.schema) { 3196 this.query.update({ withSchema: true }); 3197 } 3198 this.server 3199 .get(this.path, this.query) 3200 .done((response) => { 3201 if (!this.schema) { 3202 this.query.update({ withSchema: false }); 3203 } 3204 this.loadDataFromResponse(response); 3205 defer.resolve(this.getLoaded()); 3206 }) 3207 .fail((response) => { 3208 defer.reject(response); 3209 }); 3210 return defer; 3211 } 3212 getLoaded() { 3213 return this.objects; 3214 } 3215 getLoadedObject(id) { 3216 return this.objects.findById(id.toString()); 3217 } 3218 getLoadedAsArray() { 3219 return this.objects; 3220 } 3221 update(object) { 3222 const defer = jQuery.Deferred(); 3223 defer.promise(); 3224 const data = {}; 3225 const objectUpdatedFields = "getDirtyFields" in object ? object.getDirtyFields() : object; 3226 data[this.objectNameSingle] = this.encodeData(objectUpdatedFields); 3227 this.server 3228 .put(this.path + objectUpdatedFields.id, data) 3229 .done((response) => { 3230 if ("clearDirtyFields" in object) { 3231 object.clearDirtyFields(); 3232 } 3233 defer.resolve(object); 3234 this.events.trigger("updated", this, object); 3235 }) 3236 .fail((response, stat) => { 3237 defer.reject(response, stat); 3238 }); 3239 return defer; 3240 } 3241 delete(id) { 3242 const defer = jQuery.Deferred(); 3243 defer.promise(); 3244 this.server 3245 .delete(this.path + id) 3246 .done((response) => { 3247 this.objects.delete(id.toString()); 3248 this.events.trigger("deleted"); 3249 defer.resolve(); 3250 }) 3251 .fail((response) => { 3252 defer.reject(response); 3253 }); 3254 return defer; 3255 } 3256 clear() { 3257 const defer = jQuery.Deferred(); 3258 defer.promise(); 3259 this.server 3260 .delete(this.path) 3261 .done((response) => { 3262 this.objects.clear(); 3263 this.events.trigger("loaded"); 3264 this.events.trigger("cleared"); 3265 defer.resolve(); 3266 }) 3267 .fail((response) => { 3268 defer.reject(response); 3269 }); 3270 return defer; 3271 } 3272 onFirstPage() { 3273 return this.query.page === 1; 3274 } 3275 onLastPage() { 3276 return this.hasMoreRecords === false; 3277 } 3278 encodeData(params) { 3279 return params; 3280 } 3281 decodeData(dataJSON) { 3282 let data; 3283 if (typeof dataJSON === "string") { 3284 data = JSON.parse(dataJSON); 3285 } 3286 else { 3287 data = dataJSON; 3288 } 3289 if ((data.object || data.region || data.regions || data.objects) && data.schema) { 3290 this.setSchema(new Schema(data.schema)); 3291 } 3292 const dataFormatted = {}; 3293 for (const key in data) { 3294 if (data[key]) { 3295 switch (key) { 3296 case "object": 3297 case "region": 3298 dataFormatted[key] = new CustomObject(data[key], this.schema); 3299 break; 3300 case "objects": 3301 case "regions": 3302 dataFormatted[key] = data[key].map((obj) => new CustomObject(obj, this.schema)); 3303 break; 3304 case "schema": 3305 dataFormatted[key] = this.schema || new Schema(data[key]); 3306 break; 3307 case "schemas": 3308 dataFormatted[key] = data[key].map((obj) => new Schema(obj)); 3309 break; 3310 } 3311 } 3312 } 3313 return dataFormatted; 3314 } 3315 import(data, convertLatlngToAddress, mapsvg) { 3316 const _this = this; 3317 const locationField = _this.schema.getFieldByType("location"); 3318 let language = "en"; 3319 if (locationField && locationField.language) { 3320 language = locationField.language; 3321 } 3322 data = this.formatCSV(data, mapsvg); 3323 return this.importByChunks(data, language, convertLatlngToAddress).done(function () { 3324 _this.find(); 3325 }); 3326 } 3327 importByChunks(data, language, convertLatlngToAddress) { 3328 const _this = this; 3329 let i, j, temparray, chunk = 50; 3330 const chunks = []; 3331 for (i = 0, j = data.length; i < j; i += chunk) { 3332 temparray = data.slice(i, i + chunk); 3333 chunks.push(temparray); 3334 } 3335 if (chunks.length > 0) { 3336 let delay = 0; 3337 const delayPlus = chunks[0][0] && chunks[0][0].location ? 1000 : 0; 3338 var defer = $$2.Deferred(); 3339 defer.promise(); 3340 _this.completeChunks = 0; 3341 chunks.forEach(function (chunk) { 3342 delay += delayPlus; 3343 setTimeout(function () { 3344 const data = { 3345 language: language, 3346 convertLatlngToAddress: convertLatlngToAddress, 3347 }; 3348 data[_this.objectNameMany] = JSON.stringify(chunk); 3349 _this.server 3350 .post(_this.path + "import", data) 3351 .done(function (_data) { 3352 _this.completeChunk(chunks, defer); 3353 }) 3354 .fail((response) => { 3355 console.error(response); 3356 }); 3357 }, delay); 3358 }); 3359 } 3360 return defer; 3361 } 3362 completeChunk(chunks, defer) { 3363 const _this = this; 3364 _this.completeChunks++; 3365 if (_this.completeChunks === chunks.length) { 3366 defer.resolve(); 3367 } 3368 } 3369 formatCSV(data, mapsvg) { 3370 const _this = this; 3371 const latLngRegex = /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/g; 3372 const regionsTable = mapsvg.regionsRepository.getSchema().name; 3373 data.forEach(function (object, index) { 3374 const newObject = {}; 3375 for (const key in object) { 3376 let field = _this.schema.getField(key); 3377 if (key === "post") { 3378 field = { type: "post" }; 3379 } 3380 if (field !== undefined) { 3381 switch (field.type) { 3382 case "region":
3383 newObject[key] = {}; 3384 newObject[key] = object[key] 3385 .split(",") 3386 .map(function (regionId) { 3387 return regionId.trim(); 3388 }) 3389 .filter(function (rId) { 3390 return (mapsvg.getRegion(rId) !== undefined || 3391 mapsvg.regions.find(function (item) { 3392 return item.title === rId; 3393 }) !== undefined); 3394 }) 3395 .map(function (rId) { 3396 let r = mapsvg.getRegion(rId); 3397 if (typeof r === "undefined") { 3398 r = mapsvg.regions.find(function (item) { 3399 return item.title === rId; 3400 }); 3401 } 3402 return { id: r.id, title: r.title, tableName: regionsTable }; 3403 }); 3404 break; 3405 case "location": 3406 if (object[key].match(latLngRegex)) { 3407 const coords = object[key].split(",").map(function (n) { 3408 return parseFloat(n); 3409 }); 3410 if (coords.length == 2 && 3411 coords[0] > -90 && 3412 coords[0] < 90 && 3413 coords[1] > -180 && 3414 coords[1] < 180) { 3415 newObject[key] = { 3416 geoPoint: { lat: coords[0], lng: coords[1] }, 3417 }; 3418 } 3419 else { 3420 newObject[key] = ""; 3421 } 3422 } 3423 else if (object[key]) { 3424 newObject[key] = { address: object[key] }; 3425 } 3426 if (typeof newObject[key] == "object") { 3427 newObject[key].img = mapsvg.options.defaultMarkerImage; 3428 } 3429 break; 3430 case "select": 3431 const field = _this.schema.getField(key); 3432 if (field.multiselect) { 3433 const labels = _this.schema.getField(key).options.map(function (f) { 3434 return f.label; 3435 }); 3436 newObject[key] = object[key] 3437 .split(",") 3438 .map(function (label) { 3439 return label.trim(); 3440 }) 3441 .filter(function (label) { 3442 return labels.indexOf(label) !== -1; 3443 }) 3444 .map(function (label) { 3445 return _this.schema 3446 .getField(key) 3447 .options.filter(function (option) { 3448 return option.label == label; 3449 })[0]; 3450 }); 3451 if (newObject[key].length === 0) { 3452 const values = _this.schema 3453 .getField(key) 3454 .options.map(function (f) { 3455 return f.value + ""; 3456 });
3457 newObject[key] = object[key] 3458 .split(",") 3459 .map(function (value) { 3460 return value.trim(); 3461 }) 3462 .filter(function (value) { 3463 return values.indexOf(value) !== -1; 3464 }) 3465 .map(function (value) { 3466 return _this.schema 3467 .getField(key) 3468 .options.filter(function (option) { 3469 return option.value == value; 3470 })[0]; 3471 }); 3472 } 3473 } 3474 else { 3475 newObject[key] = object[key]; 3476 } 3477 break; 3478 case "radio": 3479 case "text": 3480 case "textarea": 3481 case "status": 3482 default: 3483 newObject[key] = object[key]; 3484 break; 3485 } 3486 } 3487 } 3488 data[index] = newObject; 3489 }); 3490 return data; 3491 } 3492 } 3493 3494 class MapsRepository extends Repository { 3495 constructor() { 3496 super("map", "maps"); 3497 this.path = "maps/"; 3498 } 3499 encodeData(params) { 3500 const data = {}; 3501 if (typeof params.options !== "undefined") { 3502 data.options = JSON.stringify(params.options); 3503 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3504 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3505 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3506 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3507 data.options = data.options.replace(/int\(11\)/g, "!mapsvg-encoded-int"); 3508 } 3509 if (typeof params.title !== "undefined") { 3510 data.title = params.title; 3511 } 3512 if (typeof params.id !== "undefined") { 3513 data.id = params.id; 3514 } 3515 if (typeof params.status !== "undefined") { 3516 data.status = params.status; 3517 } 3518 return data; 3519 } 3520 decodeData(dataJSON) { 3521 let data; 3522 if (typeof dataJSON === "string") { 3523 data = JSON.parse(dataJSON); 3524 } 3525 else { 3526 data = dataJSON; 3527 } 3528 return data; 3529 } 3530 copy(id, title) { 3531 const defer = jQuery.Deferred(); 3532 defer.promise(); 3533 const data = { options: { title: title } }; 3534 this.server 3535 .post(this.path + id + "/copy", this.encodeData(data)) 3536 .done((response) => { 3537 const data = this.decodeData(response); 3538 this.objects.clear(); 3539 this.events.trigger("loaded"); 3540 this.events.trigger("cleared"); 3541 defer.resolve(data.map); 3542 }) 3543 .fail(() => { 3544 defer.reject(); 3545 }); 3546 return defer; 3547 } 3548 createFromV2(object) { 3549 const defer = jQuery.Deferred(); 3550 defer.promise(); 3551 const data = {}; 3552 data[this.objectNameSingle] = this.encodeData(object); 3553 this.server 3554 .post(this.path + "/createFromV2", data) 3555 .done((response) => { 3556 const data = this.decodeData(response); 3557 const object = data[this.objectNameSingle]; 3558 this.objects.push(object); 3559 defer.resolve(object); 3560 this.events.trigger("created", this, [object]); 3561 }) 3562 .fail(() => { 3563 defer.reject(); 3564 }); 3565 return defer; 3566 } 3567 delete(id) { 3568 const defer = jQuery.Deferred(); 3569 defer.promise(); 3570 this.server 3571 .delete(this.path + id) 3572 .done((response) => { 3573 this.objects.delete(id.toString()); 3574 this.events.trigger("deleted"); 3575 defer.resolve(); 3576 }) 3577 .fail(() => { 3578 defer.reject(); 3579 }); 3580 return defer; 3581 } 3582 } 3583 3584 class MapsV2Repository extends Repository { 3585 constructor() { 3586 super("map", "maps"); 3587 this.path = "maps-v2/"; 3588 } 3589 encodeData(params) { 3590 const data = {}; 3591 data.options = JSON.stringify(params.options); 3592 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3593 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3594 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3595 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3596 data.id = params.id; 3597 data.title = params.title; 3598 return data; 3599 } 3600 decodeData(dataJSON) { 3601 let data; 3602 if (typeof dataJSON === "string") { 3603 data = JSON.parse(dataJSON); 3604 } 3605 else { 3606 data = dataJSON; 3607 } 3608 return data; 3609 } 3610 } 3611 3612 class Converter {
3613 constructor(mapElement, defViewBox, viewBox, geoViewBox) { 3614 this.mapElement = mapElement; 3615 this.defViewBox = defViewBox; 3616 this.viewBox = viewBox; 3617 this.yShift = 0; 3618 if (geoViewBox) { 3619 this.setGeoViewBox(geoViewBox); 3620 } 3621 } 3622 setYShift() { 3623 if (this.defViewBox.width === 20426) { 3624 this.yShift = 0; 3625 return; 3626 } 3627 if (this.geoViewBox) { 3628 const topLeftPoint = this.convertGeoToSVG(this.geoViewBox.ne); 3629 this.yShift = topLeftPoint.y - this.defViewBox.y; 3630 } 3631 } 3632 setGeoViewBox(geoViewBox) { 3633 this.geoViewBox = geoViewBox; 3634 this.mapLonDelta = this.geoViewBox.ne.lng - this.geoViewBox.sw.lng; 3635 this.mapLatBottomDegree = (this.geoViewBox.sw.lat * Math.PI) / 180; 3636 this.worldMapWidth = (this.defViewBox.width / this.mapLonDelta) * 360; 3637 this.worldMapRadius = ((this.defViewBox.width / this.mapLonDelta) * 360) / (2 * Math.PI); 3638 this.setYShift(); 3639 } 3640 setWorldShift(on) { 3641 this.worldShift = on; 3642 } 3643 getScale() { 3644 return this.mapElement.clientWidth / this.viewBox.width; 3645 } 3646 convertSVGToPixel(svgPoint) { 3647 const scale = this.getScale(); 3648 let shiftXByGM = 0; 3649 const shiftYByGM = 0; 3650 if (this.worldShift) { 3651 if (this.viewBox.x - this.defViewBox.x > this.defViewBox.width) { 3652 shiftXByGM = 3653 this.worldMapWidth * 3654 Math.floor((this.viewBox.x - this.defViewBox.x) / this.defViewBox.width); 3655 } 3656 } 3657 return new ScreenPoint((svgPoint.x - this.viewBox.x + shiftXByGM) * scale, (svgPoint.y - this.viewBox.y + shiftYByGM) * scale); 3658 } 3659 convertPixelToSVG(screenPoint) { 3660 const scale = this.getScale(); 3661 return new SVGPoint(screenPoint.x / scale + this.viewBox.x, screenPoint.y / scale + this.viewBox.y); 3662 } 3663 convertGeoToSVG(geoPoint) { 3664 if (!this.geoViewBox) { 3665 throw new Error("Can't do convertGeoToSVG() - geoViewBox is not provided."); 3666 } 3667 let x = (geoPoint.lng - this.geoViewBox.sw.lng) * (this.defViewBox.width / this.mapLonDelta); 3668 const lat = (geoPoint.lat * Math.PI) / 180; 3669 const mapOffsetY = (this.worldMapRadius / 2) * 3670 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3671 let y = this.defViewBox.height - 3672 ((this.worldMapRadius / 2) * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat))) - 3673 mapOffsetY); 3674 x += this.defViewBox.x; 3675 y += this.defViewBox.y; 3676 y -= this.yShift; 3677 return new SVGPoint(x, y); 3678 } 3679 convertSVGToGeo(svgPoint) { 3680 if (!this.geoViewBox) { 3681 throw new Error("Can't do convertSVGToGeo() - geoViewBox is not provided."); 3682 } 3683 const tx = svgPoint.x - this.defViewBox.x; 3684 const ty = svgPoint.y - this.defViewBox.y; 3685 const mapOffsetY = (this.worldMapRadius / 2) * 3686 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3687 const equatorY = this.defViewBox.height + mapOffsetY; 3688 const a = (equatorY - ty) / this.worldMapRadius; 3689 let lat = (180 / Math.PI) * (2 * Math.atan(Math.exp(a)) - Math.PI / 2); 3690 let lng = this.geoViewBox.sw.lng + (tx / this.defViewBox.width) * this.mapLonDelta; 3691 lat = parseFloat(lat.toFixed(6)); 3692 lng = parseFloat(lng.toFixed(6)); 3693 return new GeoPoint(lat, lng); 3694 } 3695 } 3696 3697 const $$3 = jQuery; 3698 class ResizeSensor { 3699 constructor(element, callback) { 3700 const _this = this; 3701 _this.element = element; 3702 _this.callback = callback; 3703 const style = getComputedStyle(element); 3704 let zIndex = parseInt(style.zIndex); 3705 if (isNaN(zIndex)) { 3706 zIndex = 0; 3707 } 3708 zIndex--; 3709 _this.expand = document.createElement("div"); 3710 _this.expand.style.position = "absolute";
3711 _this.expand.style.left = "0px"; 3712 _this.expand.style.top = "0px"; 3713 _this.expand.style.right = "0px"; 3714 _this.expand.style.bottom = "0px"; 3715 _this.expand.style.overflow = "hidden"; 3716 _this.expand.style.zIndex = zIndex.toString(); 3717 _this.expand.style.visibility = "hidden"; 3718 const expandChild = document.createElement("div"); 3719 expandChild.style.position = "absolute"; 3720 expandChild.style.left = "0px"; 3721 expandChild.style.top = "0px"; 3722 expandChild.style.width = "10000000px"; 3723 expandChild.style.height = "10000000px"; 3724 _this.expand.appendChild(expandChild); 3725 _this.shrink = document.createElement("div"); 3726 _this.shrink.style.position = "absolute"; 3727 _this.shrink.style.left = "0px"; 3728 _this.shrink.style.top = "0px"; 3729 _this.shrink.style.right = "0px"; 3730 _this.shrink.style.bottom = "0px"; 3731 _this.shrink.style.overflow = "hidden"; 3732 _this.shrink.style.zIndex = zIndex.toString(); 3733 _this.shrink.style.visibility = "hidden"; 3734 const shrinkChild = document.createElement("div"); 3735 shrinkChild.style.position = "absolute"; 3736 shrinkChild.style.left = "0px"; 3737 shrinkChild.style.top = "0px"; 3738 shrinkChild.style.width = "200%"; 3739 shrinkChild.style.height = "200%"; 3740 _this.shrink.appendChild(shrinkChild); 3741 _this.element.appendChild(_this.expand); 3742 _this.element.appendChild(_this.shrink); 3743 const size = element.getBoundingClientRect(); 3744 _this.currentWidth = size.width; 3745 _this.currentHeight = size.height; 3746 _this.setScroll(); 3747 _this.expand.addEventListener("scroll", function () { 3748 _this.onScroll(); 3749 }); 3750 _this.shrink.addEventListener("scroll", function () { 3751 _this.onScroll(); 3752 }); 3753 } 3754 onScroll() { 3755 const _this = this; 3756 const size = _this.element.getBoundingClientRect(); 3757 const newWidth = size.width; 3758 const newHeight = size.height; 3759 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 3760 _this.currentWidth = newWidth; 3761 _this.currentHeight = newHeight; 3762 _this.callback(); 3763 } 3764 this.setScroll(); 3765 } 3766 setScroll() { 3767 this.expand.scrollLeft = 10000000; 3768 this.expand.scrollTop = 10000000; 3769 this.shrink.scrollLeft = 10000000; 3770 this.shrink.scrollTop = 10000000; 3771 } 3772 destroy() { 3773 this.expand.remove(); 3774 this.shrink.remove(); 3775 } 3776 } 3777 3778 class ViewBox { 3779 constructor(x, y, width, height) { 3780 if (typeof x === "object") { 3781 if (x.hasOwnProperty("x") && 3782 x.hasOwnProperty("y") && 3783 x.hasOwnProperty("width") && 3784 x.hasOwnProperty("height")) { 3785 this.x = typeof x.x === "string" ? parseFloat(x.x) : x.x; 3786 this.y = typeof x.y === "string" ? parseFloat(x.y) : x.y; 3787 this.width = typeof x.width === "string" ? parseFloat(x.width) : x.width; 3788 this.height = typeof x.height === "string" ? parseFloat(x.height) : x.height; 3789 } 3790 else if (typeof x === "object" && x.length && x.length === 4) { 3791 this.x = typeof x[0] === "string" ? parseFloat(x[0]) : x[0]; 3792 this.y = typeof x[1] === "string" ? parseFloat(x[1]) : x[1]; 3793 this.width = typeof x[2] === "string" ? parseFloat(x[2]) : x[2]; 3794 this.height = typeof x[3] === "string" ? parseFloat(x[3]) : x[3]; 3795 } 3796 } 3797 else { 3798 this.x = typeof x === "string" ? parseFloat(x) : x; 3799 this.y = typeof y === "string" ? parseFloat(y) : y; 3800 this.width = typeof width === "string" ? parseFloat(width) : width; 3801 this.height = typeof height === "string" ? parseFloat(height) : height; 3802 } 3803 } 3804 update(newViewBox) { 3805 this.x = newViewBox.x; 3806 this.y = newViewBox.y; 3807 this.width = newViewBox.width; 3808 this.height = newViewBox.height; 3809 } 3810 toString() { 3811 return this.x + " " + this.y + " " + this.width + " " + this.height; 3812 } 3813 toArray() { 3814 return [this.x, this.y, this.width, this.height]; 3815 } 3816 clone() { 3817 return new ViewBox({ x: this.x, y: this.y, width: this.width, height: this.height }); 3818 } 3819 fitsInViewBox(viewBox, atLeastByOneDimension) { 3820 if (atLeastByOneDimension === true) { 3821 return viewBox.width >
3821 this.width || viewBox.height > this.height; 3822 } 3823 else { 3824 return viewBox.width > this.width && viewBox.height > this.height; 3825 } 3826 } 3827 addPadding(padding) { 3828 if (padding.top) { 3829 this.y -= padding.top; 3830 this.height += padding.top; 3831 } 3832 if (padding.right) { 3833 this.width += padding.right; 3834 } 3835 if (padding.bottom) { 3836 this.height += padding.bottom; 3837 } 3838 if (padding.left) { 3839 this.x -= padding.left; 3840 this.width += padding.left; 3841 } 3842 } 3843 } 3844 class GeoViewBox { 3845 constructor(sw, ne) { 3846 this.sw = sw; 3847 this.ne = ne; 3848 } 3849 } 3850 3851 const $$4 = jQuery; 3852 class MapObject { 3853 constructor(element, mapsvg) { 3854 this.id = ""; 3855 this.objects = []; 3856 this.events = new Events(this); 3857 this.element = element; 3858 this.mapsvg = mapsvg; 3859 } 3860 getBBox() { 3861 return new ViewBox(1, 2, 3, 4); 3862 } 3863 getGeoBounds() { 3864 const bbox = this.getBBox(); 3865 const pointSW = new SVGPoint(bbox.x, bbox.y + bbox.height); 3866 const pointNE = new SVGPoint(bbox.x + bbox.width, bbox.y); 3867 const sw = this.mapsvg.converter.convertSVGToGeo(pointSW); 3868 const ne = this.mapsvg.converter.convertSVGToGeo(pointNE); 3869 return { sw: sw, ne: ne }; 3870 } 3871 getComputedStyle(prop, elem) { 3872 elem = elem || this.element; 3873 return MapObject.getComputedStyle(prop, elem); 3874 } 3875 static getComputedStyle(prop, elem) { 3876 const _p1 = elem.getAttribute(prop); 3877 if (_p1) { 3878 return _p1; 3879 } 3880 const _p2 = elem.getAttribute("style"); 3881 if (_p2) { 3882 const s = _p2.split(";"); 3883 const z = s.filter(function (e) { 3884 e = e.trim(); 3885 const attr = e.split(":"); 3886 if (attr[0] == prop) 3887 return true; 3888 }); 3889 if (z.length) { 3890 return z[0].split(":").pop().trim(); 3891 } 3892 } 3893 const parent = elem.parentElement; 3894 const elemType = parent ? parent.tagName : null; 3895 if (elemType && elemType != "svg") 3896 return MapObject.getComputedStyle(prop, parent); 3897 else 3898 return undefined; 3899 } 3900 getStyle(prop) { 3901 const _p1 = this.attr(prop); 3902 if (_p1) { 3903 return _p1; 3904 } 3905 const _p2 = this.attr("style"); 3906 if (_p2) { 3907 const s = _p2.split(";"); 3908 const z = s.filter(function (e) { 3909 var e = e.trim(); 3910 if (e.indexOf(prop) === 0) 3911 return e; 3912 }); 3913 return z.length ? z[0].split(":").pop().trim() : undefined; 3914 } 3915 return ""; 3916 } 3917 getCenter() { 3918 const x = this.element.getBoundingClientRect().left; 3919 const y = this.element.getBoundingClientRect().top; 3920 const w = this.element.getBoundingClientRect().width; 3921 const h = this.element.getBoundingClientRect().height; 3922 const point = new ScreenPoint(x + w / 2, y + h / 2); 3923 return point; 3924 } 3925 getCenterSVG() { 3926 const bbox = this.getBBox(); 3927 const point = new SVGPoint(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2); 3928 return point; 3929 } 3930 getCenterLatLng(yShift) { 3931 yShift = yShift ? yShift : 0; 3932 const bbox = this.getBBox(); 3933 const x = bbox.x + bbox.width / 2; 3934 const y = bbox.y + bbox.height / 2 - yShift; 3935 const point = new SVGPoint(x, y); 3936 return this.mapsvg.converter.convertSVGToGeo(point); 3937 } 3938 attr(v1, v2 = null) { 3939 const svgDom = this.element; 3940 if (typeof v1 == "object") { 3941 for (const key in v1) { 3942 const item = v1[key]; 3943 if (typeof item === "string" || typeof item === "number") { 3944 svgDom.setAttribute(key, "" + item); 3945 } 3946 } 3947 } 3948 else if (typeof v1 == "string" && (typeof v2 == "string" || typeof v2 == "number")) { 3949 svgDom.setAttribute(v1, "" + v2); 3950 } 3951 else if (v2 == undefined) { 3952 return svgDom.getAttribute(v1); 3953 } 3954 } 3955 setId(id) { 3956 if (id !== undefined) { 3957 this.id = id; 3958 this.element.setAttribute("id", id); 3959 } 3960 } 3961 } 3962 3963 const $$5 = jQuery; 3964 class Marker extends MapObject { 3965 constructor(params) { 3966 super(null, params.mapsvg); 3967 this.element = $$5("<div />").addClass("mapsvg-marker")[0]; 3968 this.image = $$5('<img src="" />').addClass("mapsvg-marker-image")[0]; 3969 if (params.object) { 3970 this.setObject(params.object); 3971 } 3972 if (!(params.location instanceof Location)) { 3973 throw new Error("MapSVG.Marker: no Location provided for Marker initializaton"); 3974 } 3975 else { 3976 this.location = params.location; 3977 this.location.marker = this; 3978 } 3979 this.setImage(this.location.imagePath); 3980 $$5(this.element).append(this.image); 3981 if (params.width && params.height) { 3982 this.setSize(params.width, params.height); 3983 } 3984 else { 3985 this.setSize(15, 24); 3986 } 3987 this.setId(this.mapsvg.markerId()); 3988 this.setSvgPointFromLocation(); 3989 this.setAltAttr(); 3990 } 3991 reload() { 3992 this.setImage(); 3993 this.setSvgPointFromLocation(); 3994 } 3995 getImagePath() { 3996 return (this.object && this.object.getMarkerImage()) || this.location.getMarkerImage(); 3997 } 3998 setSize(width, height) { 3999 this.width = width; 4000 this.height = height; 4001 this.setCentered(this.width === this.height); 4002 } 4003 setSvgPointFromLocation() { 4004 const svgPoint = this.location.geoPoint && 4005 this.location.geoPoint.lat !== 0 && 4006 this.location.geoPoint.lng !== 0 4007 ? this.mapsvg.converter.convertGeoToSVG(this.location.geoPoint) 4008 : this.location.svgPoint; 4009 if (svgPoint) { 4010 this.setSvgPoint(svgPoint); 4011 } 4012 } 4013 setId(id) { 4014 MapObject.prototype.setId.call(this, id); 4015 this.mapsvg.markers.reindex(); 4016 } 4017 getBBox() { 4018 if (this.centered) { 4019 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); 4020 } 4021 else { 4022 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); 4023 } 4024 } 4025 getOptions() { 4026 const o = { 4027 id: this.id, 4028 src: this.src, 4029 svgPoint: this.svgPoint, 4030 geoPoint: this.geoPoint, 4031 }; 4032 $$5.each(o, function (key, val) { 4033 if (val == undefined) { 4034 delete o[key]; 4035 } 4036 }); 4037 return o; 4038 } 4039 update(data) { 4040 for (const key in data) { 4041 const setter = "set" + MapSVG.ucfirst(key); 4042 if (setter in this) 4043 this[setter](data[key]); 4044 } 4045 } 4046 setImage(src, skipChangingLocationImage = false) { 4047 if (!src) { 4048 src = this.getImagePath(); 4049 } 4050 this.src = MapSVG.safeURL(src); 4051 const img = new Image(); 4052 const marker = this; 4053 img.onload = function () { 4054 if (marker.image.getAttribute("src") !== "src") { 4055 marker.image.setAttribute("src", marker.src); 4056 } 4057 marker.setSize(this.width, this.height); 4058 marker.adjustScreenPosition(); 4059 }; 4060 img.src = this.src; 4061 this.events.trigger("change"); 4062 } 4063 setAltAttr() { 4064 const marker = this; 4065 marker.altAttr = 4066 typeof marker.object != "undefined" && 4067 typeof marker.object.title != "undefined" && 4068 marker.object.title !== "" 4069 ? marker.object.title 4070 : marker.id; 4071 marker.element.setAttribute("alt", marker.altAttr); 4072 } 4073 setSvgPoint(svgPoint) { 4074 this.svgPoint = svgPoint; 4075 this.adjustScreenPosition(); 4076 this.events.trigger("change"); 4077 } 4078 adjustScreenPosition() { 4079 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 4080 pos.x -= this.width / 2; 4081 pos.y -= !this.centered ? this.height : this.height / 2; 4082 this.setScreenPosition(pos.x, pos.y); 4083 } 4084 moveSrceenPositionBy(deltaX, deltaY) { 4085 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 4086 this.setScreenPosition(x, y); 4087 } 4088 setScreenPosition(x, y) { 4089 if (this.screenPoint instanceof ScreenPoint) { 4090 this.screenPoint.x = x; 4091 this.screenPoint.y = y; 4092 } 4093 else { 4094 this.screenPoint = new ScreenPoint(x, y); 4095 } 4096 this.updateVisibility(); 4097 if (this.visible === true) { 4098 this.element.style.transform = "translate(" + x + "px," + y + "px)"; 4099 this.adjustLabelScreenPosition(); 4100 } 4101 } 4102 adjustLabelScreenPosition() { 4103 if (this.label) { 4104 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()); 4105 } 4106 } 4107 inViewBox() { 4108 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 4109 return (x - this.width / 2 < 2 * mapFullWidth && 4110 x + this.width / 2 > -mapFullWidth && 4111 y - this.height / 2 < 2 * mapFullHeight && 4112 y + this.height / 2 > -mapFullHeight); 4113 } 4114 updateVisibility() { 4115 if (this.inViewBox() === true) { 4116 this.visible = true; 4117 this.element.classList.remove("mapsvg-out-of-sight"); 4118 if (this.label) { 4119 this.label.classList.remove("mapsvg-out-of-sight"); 4120 } 4121 } 4122 else { 4123 this.visible = false;
4124 this.element.classList.add("mapsvg-out-of-sight"); 4125 if (this.label) { 4126 this.label.classList.add("mapsvg-out-of-sight"); 4127 } 4128 } 4129 return this.visible; 4130 } 4131 isMoving() { 4132 return this.moving; 4133 } 4134 setMoving(value) { 4135 this.moving = value; 4136 } 4137 drag(startCoords, scale, endCallback, clickCallback) { 4138 const _this = this; 4139 this.svgPointBeforeDrag = new SVGPoint(this.svgPoint.x, this.svgPoint.y); 4140 this.setMoving(true); 4141 $$5("body").on("mousemove.drag.mapsvg", function (e) { 4142 e.preventDefault(); 4143 $$5(_this.mapsvg.containers.map).addClass("no-transitions"); 4144 const mouseNew = MapSVG.mouseCoords(e); 4145 const dx = mouseNew.x - startCoords.x; 4146 const dy = mouseNew.y - startCoords.y; 4147 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 4148 _this.setSvgPoint(newSvgPoint); 4149 }); 4150 $$5("body").on("mouseup.drag.mapsvg", function (e) { 4151 e.preventDefault(); 4152 _this.undrag(); 4153 const mouseNew = MapSVG.mouseCoords(e); 4154 const dx = mouseNew.x - startCoords.x; 4155 const dy = mouseNew.y - startCoords.y; 4156 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 4157 _this.setSvgPoint(newSvgPoint); 4158 if (_this.mapsvg.isGeo()) { 4159 _this.geoPoint = _this.mapsvg.converter.convertSVGToGeo(newSvgPoint); 4160 } 4161 endCallback && endCallback.call(_this); 4162 if (_this.svgPointBeforeDrag.x == _this.svgPoint.x && 4163 _this.svgPointBeforeDrag.y == _this.svgPoint.y) 4164 clickCallback && clickCallback.call(_this); 4165 }); 4166 } 4167 undrag() { 4168 this.setMoving(false); 4169 $$5("body").off(".drag.mapsvg"); 4170 $$5(this.mapsvg.containers.map).removeClass("no-transitions"); 4171 } 4172 delete() { 4173 if (this.label) { 4174 this.label.remove(); 4175 this.label = null; 4176 } 4177 $$5(this.element).empty().remove(); 4178 } 4179 setObject(obj) { 4180 this.object = obj; 4181 $$5(this.element).attr("data-object-id", this.object.id); 4182 } 4183 hide() { 4184 $$5(this.element).addClass("mapsvg-marker-hidden"); 4185 if (this.label) { 4186 $$5(this.label).hide(); 4187 } 4188 } 4189 show() { 4190 $$5(this.element).removeClass("mapsvg-marker-hidden"); 4191 if (this.label) { 4192 $$5(this.label).show(); 4193 } 4194 } 4195 highlight() { 4196 $$5(this.element).addClass("mapsvg-marker-hover"); 4197 } 4198 unhighlight() { 4199 $$5(this.element).removeClass("mapsvg-marker-hover"); 4200 } 4201 select() { 4202 this.selected = true; 4203 $$5(this.element).addClass("mapsvg-marker-active"); 4204 } 4205 deselect() { 4206 this.selected = false; 4207 $$5(this.element).removeClass("mapsvg-marker-active"); 4208 } 4209 getData() { 4210 return this.object; 4211 } 4212 getChoroplethColor() { 4213 const markerValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4214 let color; 4215 if (!markerValue) { 4216 color = this.mapsvg.options.choropleth.coloring.noData.color; 4217 } 4218 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 4219 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 4220 ? 0 4221 : (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); 4222 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 4223 } 4224 else { 4225 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 4226 if (!paletteColors[0].valueFrom && markerValue < paletteColors[0].valueTo) { 4227 color = paletteColors[0].color; 4228 } 4229 else if (!paletteColors[paletteColors.length - 1].valueTo && 4230 markerValue > paletteColors[paletteColors.length - 1].valueFrom) { 4231 color = paletteColors[paletteColors.length - 1].color; 4232 } 4233 else {
4234 paletteColors.forEach(function (paletteColor) { 4235 if (markerValue >= paletteColor.valueFrom && 4236 markerValue < paletteColor.valueTo) { 4237 color = paletteColor.color; 4238 } 4239 }); 4240 color = color 4241 ? color 4242 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4243 } 4244 } 4245 return color; 4246 } 4247 getBubbleSize() { 4248 let bubbleSize; 4249 if (this.object[this.mapsvg.options.choropleth.sourceField]) { 4250 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]); 4251 bubbleSize = 4252 ((sourceFieldvalue - minSourceFieldvalue) / 4253 (maxSourceFieldvalue - minSourceFieldvalue)) * 4254 (maxBubbleSize - minBubbleSize) + 4255 Number(minBubbleSize); 4256 } 4257 else { 4258 bubbleSize = false; 4259 } 4260 return bubbleSize; 4261 } 4262 getBubbleScreenPosition() { 4263 const bubbleSize = Number(this.getBubbleSize()); 4264 return { 4265 x: this.width / 2 - bubbleSize / 2, 4266 y: this.height - bubbleSize / 2, 4267 }; 4268 } 4269 drawBubble() { 4270 const bubbleId = "mapsvg-bubble-" + this.object.id; 4271 const bubbleValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4272 if (bubbleValue) { 4273 if (!this.bubble) { 4274 this.bubble = $$5('<div id="' + 4275 bubbleId + 4276 '" data-marker-id="' + 4277 this.element.id + 4278 '" class="mapsvg-bubble mapsvg-marker-bubble"></div>')[0]; 4279 $$5(this.element).append(this.bubble); 4280 } 4281 const color = this.getChoroplethColor(), bubbleSize = Number(this.getBubbleSize()); 4282 $$5(this.bubble) 4283 .css("background-color", color) 4284 .css("width", bubbleSize + "px") 4285 .css("height", bubbleSize + "px") 4286 .css("lineHeight", bubbleSize - 2 + "px"); 4287 } 4288 else { 4289 $$5("#" + bubbleId).remove(); 4290 delete this.bubble; 4291 } 4292 } 4293 setBubbleMode(bubbleMode) { 4294 this.bubbleMode = bubbleMode; 4295 if (bubbleMode) { 4296 this.setCentered(true); 4297 this.drawBubble(); 4298 if (this.bubble) { 4299 this.width = this.bubble.offsetWidth; 4300 this.height = this.bubble.offsetHeight; 4301 this.adjustScreenPosition(); 4302 } 4303 } 4304 else { 4305 this.setImage(this.src); 4306 } 4307 } 4308 setLabel(html) { 4309 if (html) { 4310 if (!this.label) { 4311 this.label = $$5("<div />").addClass("mapsvg-marker-label")[0]; 4312 $$5(this.element).append(this.label); 4313 } 4314 $$5(this.label).html(html); 4315 } 4316 else { 4317 if (this.label) { 4318 $$5(this.label).remove(); 4319 delete this.label; 4320 } 4321 } 4322 } 4323 setCentered(on) { 4324 this.centered = on; 4325 } 4326 } 4327 4328 const $$6 = jQuery; 4329 class MarkerCluster extends MapObject { 4330 constructor(options, mapsvg) { 4331 super(null, mapsvg); 4332 this.svgPoint = options.svgPoint; 4333 this.cellX = options.cellX; 4334 this.cellY = options.cellY; 4335 this.markers = options.markers || []; 4336 this.cellSize = 50; 4337 this.width = 30; 4338 this.elem = $$6('<div class="mapsvg-marker-cluster">' + this.markers.length + "</div>")[0]; 4339 $$6(this.elem).data("cluster", this); 4340 if (this.markers.length < 2) { 4341 $$6(this.elem).hide(); 4342 } 4343 this.adjustScreenPosition(); 4344 } 4345 addMarker(marker) { 4346 this.markers.push(marker); 4347 if (this.markers.length > 1) { 4348 if (this.markers.length === 2) { 4349 $$6(this.elem).show(); 4350 } 4351 if (this.markers.length === 2) { 4352 const x = this.markers.map(function (m) { 4353 return m.svgPoint.x; 4354 }); 4355 this.min_x = Math.min.apply(null, x); 4356 this.max_x = Math.max.apply(null, x); 4357 const y = this.markers.map(function (m) { 4358 return m.svgPoint.y; 4359 }); 4360 this.min_y = Math.min.apply(null, y); 4361 this.max_y = Math.max.apply(null, y); 4362 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4363 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4364 } 4365 if (this.markers.length > 2) { 4366 if (marker.svgPoint.x < this.min_x) { 4367 this.min_x = marker.svgPoint.x; 4368 } 4369 else if (marker.svgPoint.x > this.max_x) { 4370 this.max_x = marker.svgPoint.x; 4371 } 4372 if (marker.svgPoint.y < this.min_y) { 4373 this.min_y = marker.svgPoint.y; 4374 } 4375 else if (marker.svgPoint.x > this.max_x) { 4376 this.max_y = marker.svgPoint.y; 4377 } 4378 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4379 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4380 } 4381 } 4382 else { 4383 this.svgPoint.x = marker.svgPoint.x; 4384 this.svgPoint.y = marker.svgPoint.y; 4385 } 4386 $$6(this.elem).text(this.markers.length); 4387 this.adjustScreenPosition(); 4388 } 4389 canTakeMarker(marker) { 4390 const _this = this; 4391 const screenPoint = _this.mapsvg.converter.convertSVGToPixel(marker.svgPoint); 4392 return (this.cellX === Math.ceil(screenPoint.x / this.cellSize) && 4393 this.cellY === Math.ceil(screenPoint.y / this.cellSize)); 4394 } 4395 destroy() { 4396 this.markers = null; 4397 $$6(this.elem).remove(); 4398 } 4399 adjustScreenPosition() { 4400 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 4401 pos.x -= this.width / 2; 4402 pos.y -= this.width / 2; 4403 this.setScreenPosition(pos.x, pos.y); 4404 } 4405 moveSrceenPositionBy(deltaX, deltaY) { 4406 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 4407 this.setScreenPosition(x, y); 4408 } 4409 setScreenPosition(x, y) { 4410 if (this.screenPoint instanceof ScreenPoint) { 4411 this.screenPoint.x = x; 4412 this.screenPoint.y = y; 4413 } 4414 else { 4415 this.screenPoint = new ScreenPoint(x, y); 4416 } 4417 this.updateVisibility(); 4418 if (this.visible === true) { 4419 this.elem.style.transform = "translate(" + x + "px," + y + "px)"; 4420 } 4421 } 4422 inViewBox() { 4423 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 4424 return (x - this.width / 2 < mapFullWidth && 4425 x + this.width / 2 > 0 && 4426 y - this.width / 2 < mapFullHeight && 4427 y + this.width / 2 > 0); 4428 } 4429 updateVisibility() { 4430 if (this.inViewBox() === true) { 4431 this.visible = true; 4432 this.elem.classList.remove("mapsvg-out-of-sight"); 4433 } 4434 else { 4435 this.visible = false;
4436 this.elem.classList.add("mapsvg-out-of-sight"); 4437 } 4438 return this.visible; 4439 } 4440 getBBox() { 4441 let bbox = { 4442 x: this.svgPoint.x, 4443 y: this.svgPoint.y, 4444 width: this.cellSize / this.mapsvg.getScale(), 4445 height: this.cellSize / this.mapsvg.getScale(), 4446 }; 4447 bbox = $$6.extend(true, {}, bbox); 4448 return new ViewBox(bbox.x, bbox.y, bbox.width, bbox.height); 4449 } 4450 getData() { 4451 return this.markers.map((m) => m.object); 4452 } 4453 } 4454 4455 const $$7 = jQuery; 4456 class Region extends MapObject { 4457 constructor(element, mapsvg) { 4458 super(element, mapsvg); 4459 this.id = this.element.getAttribute("id"); 4460 if (this.id && this.mapsvg.options.regionPrefix) { 4461 this.setId(this.id.replace(this.mapsvg.options.regionPrefix, "")); 4462 } 4463 this.id_no_spaces = this.id.replace(/\s/g, "_"); 4464 this.element.setAttribute("class", (this.element.className || "") + " mapsvg-region"); 4465 this.setStyleInitial(); 4466 const regionOptions = this.mapsvg.options.regions && this.mapsvg.options.regions[this.id] 4467 ? this.mapsvg.options.regions[this.id] 4468 : null; 4469 this.disabled = this.getDisabledState(); 4470 this.disabled && this.attr("class", this.attr("class") + " mapsvg-disabled"); 4471 this.default_attr = {}; 4472 this.selected_attr = {}; 4473 this.hover_attr = {}; 4474 let selected = false; 4475 if (regionOptions && regionOptions.selected) { 4476 selected = true; 4477 delete regionOptions.selected; 4478 } 4479 regionOptions && this.update(regionOptions); 4480 this.setFill(); 4481 if (selected) { 4482 this.setSelected(); 4483 } 4484 this.saveState(); 4485 } 4486 adjustStroke(scale) { 4487 $$7(this.element).css({ "stroke-width": this.style["stroke-width"] / scale }); 4488 } 4489 setStyleInitial() { 4490 this.style = { fill: this.getComputedStyle("fill") }; 4491 this.style.stroke = this.getComputedStyle("stroke") || ""; 4492 let w; 4493 w = this.getComputedStyle("stroke-width"); 4494 w = w ? w.replace("px", "") : "1"; 4495 w = parseFloat(w); 4496 this.style["stroke-width"] = w; 4497 $$7(this.element).attr("data-stroke-width", w); 4498 } 4499 saveState() { 4500 this.initialState = JSON.stringify(this.getOptions()); 4501 } 4502 getBBox() { 4503 const _bbox = this.element.getBBox(); 4504 const bbox = new ViewBox(_bbox.x, _bbox.y, _bbox.width, _bbox.height); 4505 const matrix = this.element.getTransformToElement(this.mapsvg.containers.svg); 4506 if (!matrix) { 4507 return _bbox; 4508 } 4509 const x2 = bbox.x + bbox.width; 4510 const y2 = bbox.y + bbox.height; 4511 let position = this.mapsvg.containers.svg.createSVGPoint(); 4512 position.x = bbox.x; 4513 position.y = bbox.y; 4514 position = position.matrixTransform(matrix); 4515 bbox.x = position.x; 4516 bbox.y = position.y; 4517 position.x = x2; 4518 position.y = y2; 4519 position = position.matrixTransform(matrix); 4520 bbox.width = position.x - bbox.x; 4521 bbox.height = position.y - bbox.y; 4522 return bbox; 4523 } 4524 changed() { 4525 return JSON.stringify(this.getOptions()) != this.initialState; 4526 } 4527 edit() { 4528 this.elemOriginal = $$7(this.element).clone()[0]; 4529 } 4530 editCommit() { 4531 this.elemOriginal = null; 4532 } 4533 editCancel() { 4534 this.mapsvg.containers.svg.appendChild(this.elemOriginal); 4535 this.element = this.elemOriginal; 4536 this.elemOriginal = null; 4537 } 4538 getOptions(forTemplate) { 4539 let o; 4540 o = { 4541 id: this.id, 4542 id_no_spaces: this.id_no_spaces, 4543 title: this.title, 4544 fill: this.mapsvg.options.regions[this.id] && this.mapsvg.options.regions[this.id].fill, 4545 data: this.data, 4546 choroplethValue: this.choroplethValue, 4547 }; 4548 if (forTemplate) { 4549 o.disabled = this.disabled; 4550 } 4551 for (const key in o) {
4552 if (typeof o[key] === "undefined") { 4553 delete o[key]; 4554 } 4555 } 4556 if (this.customAttrs) { 4557 const that = this; 4558 this.customAttrs.forEach(function (attr) { 4559 o[attr] = that[attr]; 4560 }); 4561 } 4562 return o; 4563 } 4564 forTemplate() { 4565 const data = { 4566 id: this.id, 4567 title: this.title, 4568 objects: this.objects, 4569 data: this.data, 4570 }; 4571 if (this.data) { 4572 for (const key in this.data) { 4573 if (key != "title" && key != "id") 4574 data[key] = this.data[key]; 4575 } 4576 } 4577 return data; 4578 } 4579 getData() { 4580 return this.forTemplate(); 4581 } 4582 update(options) { 4583 for (const key in options) { 4584 const setter = "set" + MapSVG.ucfirst(key); 4585 if (setter in this) 4586 this[setter](options[key]); 4587 else { 4588 this[key] = options[key]; 4589 this.customAttrs = this.customAttrs || []; 4590 this.customAttrs.push(key); 4591 } 4592 } 4593 } 4594 setTitle(title) { 4595 if (title) { 4596 this.title = title; 4597 } 4598 this.element.setAttribute("title", this.title); 4599 } 4600 setStyle(style) { 4601 $$7.extend(true, this.style, style); 4602 this.setFill(); 4603 } 4604 getChoroplethColor() { 4605 const o = this.mapsvg.options.choropleth; 4606 let color = ""; 4607 if (this.data && 4608 (this.data[this.mapsvg.options.regionChoroplethField] || 4609 this.data[this.mapsvg.options.regionChoroplethField] === 0)) { 4610 const w = o.maxAdjusted === 0 4611 ? 0 4612 : (parseFloat(this.data[this.mapsvg.options.regionChoroplethField]) - o.min) / 4613 o.maxAdjusted; 4614 const c = { 4615 r: Math.round(o.colors.diffRGB.r * w + o.colors.lowRGB.r), 4616 g: Math.round(o.colors.diffRGB.g * w + o.colors.lowRGB.g), 4617 b: Math.round(o.colors.diffRGB.b * w + o.colors.lowRGB.b), 4618 a: (o.colors.diffRGB.a * w + o.colors.lowRGB.a).toFixed(2), 4619 }; 4620 color = "rgba(" + c.r + "," + c.g + "," + c.b + "," + c.a + ")"; 4621 } 4622 else { 4623 color = o.colors.noData; 4624 } 4625 return color; 4626 } 4627 _new_getChoroplethColor() { 4628 let regionValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]), color; 4629 if (!regionValue) { 4630 color = this.mapsvg.options.choropleth.coloring.noData.color; 4631 } 4632 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 4633 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 4634 ? 0 4635 : (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); 4636 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 4637 } 4638 else { 4639 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 4640 if (!paletteColors[0].valueFrom && regionValue < paletteColors[0].valueTo) { 4641 color = paletteColors[0].color; 4642 } 4643 else if (!paletteColors[paletteColors.length - 1].valueTo && 4644 regionValue > paletteColors[paletteColors.length - 1].valueFrom) { 4645 color = paletteColors[paletteColors.length - 1].color; 4646 } 4647 else {
4648 paletteColors.forEach(function (paletteColor) { 4649 if (regionValue >= paletteColor.valueFrom && 4650 regionValue < paletteColor.valueTo) { 4651 color = paletteColor.color; 4652 } 4653 }); 4654 color = color 4655 ? color 4656 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4657 } 4658 } 4659 return color; 4660 } 4661 getBubbleSize() { 4662 let bubbleSize; 4663 if (this.data[this.mapsvg.options.choropleth.sourceField]) { 4664 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]); 4665 bubbleSize = 4666 ((sourceFieldvalue - minSourceFieldvalue) / 4667 (maxSourceFieldvalue - minSourceFieldvalue)) * 4668 (maxBubbleSize - minBubbleSize) + 4669 minBubbleSize; 4670 } 4671 else { 4672 bubbleSize = false; 4673 } 4674 return bubbleSize; 4675 } 4676 setFill(fill) { 4677 if (this.mapsvg.options.colorsIgnore) { 4678 $$7(this.element).css(this.style); 4679 return; 4680 } 4681 if (fill) { 4682 const regions = {}; 4683 regions[this.id] = { fill: fill }; 4684 $$7.extend(true, this.mapsvg.options, { regions: regions }); 4685 } 4686 else if (!fill && 4687 fill !== undefined && 4688 this.mapsvg.options.regions && 4689 this.mapsvg.options.regions[this.id] && 4690 this.mapsvg.options.regions[this.id].fill) { 4691 delete this.mapsvg.options.regions[this.id].fill; 4692 } 4693 if (this.mapsvg.options.choropleth.on) { 4694 this.default_attr["fill"] = this.getChoroplethColor(); 4695 } 4696 else if (this.status !== undefined && 4697 this.mapsvg.regions && 4698 this.mapsvg.regionsRepository.getSchema().getFieldByType("status") && 4699 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict && 4700 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status] && 4701 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status].color) { 4702 this.default_attr["fill"] = this.mapsvg.regionsRepository 4703 .getSchema() 4704 .getFieldByType("status").optionsDict[this.status].color; 4705 } 4706 else if (this.mapsvg.options.regions[this.id] && 4707 this.mapsvg.options.regions[this.id].fill) { 4708 this.default_attr["fill"] = this.mapsvg.options.regions[this.id].fill; 4709 } 4710 else if (this.mapsvg.options.colors.base) { 4711 this.default_attr["fill"] = this.mapsvg.options.colors.base; 4712 } 4713 else if (this.style.fill != "none") { 4714 this.default_attr["fill"] = this.style.fill 4715 ? this.style.fill 4716 : this.mapsvg.options.colors.baseDefault; 4717 } 4718 else { 4719 this.default_attr["fill"] = "none"; 4720 } 4721 if (MapSVG.isNumber(this.mapsvg.options.colors.selected)) 4722 this.selected_attr["fill"] = tinycolor(this.default_attr.fill) 4723 .lighten(parseFloat("" + this.mapsvg.options.colors.selected)) 4724 .toRgbString(); 4725 else 4726 this.selected_attr["fill"] = this.mapsvg.options.colors.selected; 4727 if (MapSVG.isNumber(this.mapsvg.options.colors.hover)) 4728 this.hover_attr["fill"] = tinycolor(this.default_attr.fill) 4729 .lighten(parseFloat("" + this.mapsvg.options.colors.hover)) 4730 .toRgbString(); 4731 else 4732 this.hover_attr["fill"] = this.mapsvg.options.colors.hover; 4733 $$7(this.element).css("fill", this.default_attr["fill"]); 4734 this.fill = this.default_attr["fill"]; 4735 if (this.style.stroke != "none" && this.mapsvg.options.colors.stroke != undefined) { 4736 $$7(this.element).css("stroke", this.mapsvg.options.colors.stroke); 4737 } 4738 else { 4739 const s = this.style.stroke == undefined ? "" : this.style.stroke; 4740 $$7(this.element).css("stroke", s); 4741 } 4742 if (this.selected) 4743 this.setSelected(); 4744 } 4745 setDisabled(on, skipSetFill) { 4746 on = on !== undefined ? MapSVG.parseBoolean(on) : this.getDisabledState(); 4747 const prevDisabled = this.disabled; 4748 this.disabled = on; 4749 this.attr("class", this.attr("class").replace("mapsvg-disabled", "")); 4750 if (on) { 4751 this.attr("class", this.attr("class") + " mapsvg-disabled"); 4752 } 4753 if (this.disabled != prevDisabled) 4754 this.mapsvg.deselectRegion(this); 4755 !skipSetFill && this.setFill(); 4756 } 4757 setStatus(status) { 4758 const statusOptions = this.mapsvg.options.regionStatuses && this.mapsvg.options.regionStatuses[status]; 4759 if (statusOptions) { 4760 this.status = status; 4761 if (this.data) { 4762 this.data.status = status; 4763 this.data.status_text = statusOptions.label; 4764 } 4765 this.setDisabled(statusOptions.disabled, true); 4766 } 4767 else { 4768 this.status = undefined; 4769 if (this.data) { 4770 this.data.status = undefined; 4771 this.data.status_text = undefined; 4772 } 4773 this.setDisabled(false, true); 4774 } 4775 this.setFill(); 4776 } 4777 setSelected() { 4778 this.mapsvg.selectRegion(this); 4779 } 4780 setchoroplethValue(val) { 4781 if ($$7.isNumeric(val)) { 4782 if (typeof val === "string") { 4783 val = parseFloat(val); 4784 } 4785 this.choroplethValue = val; 4786 } 4787 else { 4788 this.choroplethValue = undefined; 4789 } 4790 } 4791 getDisabledState(asDefault) { 4792 const opts = this.mapsvg.options.regions[this.id]; 4793 if (!asDefault && opts && opts.disabled !== undefined) { 4794 return opts.disabled; 4795 } 4796 else { 4797 return (this.mapsvg.options.disableAll || 4798 this.style.fill === "none" || 4799 this.id == "labels" || 4800 this.id == "Labels"); 4801 } 4802 } 4803 highlight() { 4804 $$7(this.element).css({ fill: this.hover_attr.fill }); 4805 $$7(this.element).addClass("mapsvg-region-hover"); 4806 } 4807 unhighlight() { 4808 $$7(this.element).css({ fill: this.default_attr.fill }); 4809 $$7(this.element).removeClass("mapsvg-region-hover"); 4810 } 4811 select() { 4812 $$7(this.element).css({ fill: this.selected_attr.fill }); 4813 this.selected = true; 4814 $$7(this.element).addClass("mapsvg-region-active"); 4815 } 4816 deselect() { 4817 $$7(this.element).css({ fill: this.default_attr.fill }); 4818 this.selected = false;
4819 $$7(this.element).removeClass("mapsvg-region-active"); 4820 } 4821 setData(data) { 4822 this.data = data; 4823 if (typeof data.title !== "undefined") { 4824 this.setTitle(data.title); 4825 } 4826 } 4827 drawBubble() { 4828 if (this.data) { 4829 const bubbleId = "mapsvg-bubble-" + this.id; 4830 const bubbleValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]); 4831 if (bubbleValue) { 4832 if (!this.center) { 4833 this.center = this.getCenterSVG(); 4834 } 4835 const pos = this.mapsvg.converter.convertSVGToPixel(this.center); 4836 if (!this.bubble) { 4837 this.bubble = $$7('<div id="' + 4838 bubbleId + 4839 '" class="mapsvg-bubble mapsvg-region-bubble"></div>')[0]; 4840 $$7(this.mapsvg.layers.bubbles).append(this.bubble); 4841 } 4842 const color = this.getChoroplethColor(); 4843 const bubbleSize = Number(this.getBubbleSize()); 4844 $$7(this.bubble) 4845 .css("transform", "translate(-50%,-50%) translate(" + pos.x + "px," + pos.y + "px)") 4846 .css("background-color", color) 4847 .css("width", bubbleSize + "px") 4848 .css("height", bubbleSize + "px") 4849 .css("lineHeight", bubbleSize - 2 + "px"); 4850 } 4851 else { 4852 delete this.bubble; 4853 } 4854 } 4855 } 4856 adjustLabelScreenPosition() { 4857 if (this.label) { 4858 if (!this.center) { 4859 this.center = this.getCenterSVG(); 4860 } 4861 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.label.offsetWidth / 2, y = pos.y - this.label.offsetHeight / 2; 4862 this.setLabelScreenPosition(x, y); 4863 } 4864 } 4865 adjustBubbleScreenPosition() { 4866 if (this.bubble) { 4867 if (!this.center) { 4868 this.center = this.getCenterSVG(); 4869 } 4870 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.bubble.offsetWidth / 2, y = pos.y - this.bubble.offsetHeight / 2; 4871 this.setBubbleScreenPosition(x, y); 4872 } 4873 } 4874 moveLabelScreenPositionBy(deltaX, deltaY) { 4875 if (this.label) { 4876 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; 4877 this.setLabelScreenPosition(x, y); 4878 } 4879 } 4880 moveBubbleScreenPositionBy(deltaX, deltaY) { 4881 if (this.bubble) { 4882 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; 4883 this.setBubbleScreenPosition(x, y); 4884 } 4885 } 4886 setLabelScreenPosition(x, y) { 4887 if (this.label) { 4888 this.label.style.transform = "translate(" + x + "px," + y + "px)"; 4889 } 4890 } 4891 setBubbleScreenPosition(x, y) { 4892 if (this.bubble) { 4893 this.bubble.style.transform = "translate(" + x + "px," + y + "px)"; 4894 } 4895 } 4896 } 4897 4898 class SchemaRepository extends Repository { 4899 constructor() { 4900 const objectName = "schema"; 4901 super(objectName, +objectName + "s"); 4902 this.className = "Schema"; 4903 this.objectNameSingle = objectName; 4904 this.objectNameMany = objectName + "s"; 4905 this.path = objectName + "s/"; 4906 this.events = new Events(this); 4907 } 4908 create(schema) { 4909 const defer = jQuery.Deferred(); 4910 defer.promise(); 4911 const data = {}; 4912 data[this.objectNameSingle] = this.encodeData(schema); 4913 this.server 4914 .post(this.path, data) 4915 .done((response) => { 4916 const data = this.decodeData(response); 4917 schema.id = data[this.objectNameSingle].id; 4918 this.objects.push(schema); 4919 this.events.trigger("created"); 4920 schema.events.trigger("created"); 4921 defer.resolve(schema); 4922 }) 4923 .fail(() => { 4924 defer.reject(); 4925 }); 4926 return defer; 4927 } 4928 update(schema) { 4929 const defer = jQuery.Deferred(); 4930 defer.promise(); 4931 const data = {}; 4932 data[this.objectNameSingle] = this.encodeData(schema); 4933 this.server 4934 .put(this.path + schema.id, data) 4935 .done((response) => { 4936 const data = this.decodeData(response); 4937 this.objects.push(schema); 4938 defer.resolve(schema); 4939 this.events.trigger("changed"); 4940 schema.events.trigger("changed"); 4941 }) 4942 .fail(() => { 4943 defer.reject(); 4944 }); 4945 return defer; 4946 } 4947 encodeData(schema) { 4948 const _schema = schema.getData(); 4949 let fieldsJsonString = JSON.stringify(_schema); 4950 fieldsJsonString = fieldsJsonString.replace(/select/g, "!mapsvg-encoded-slct"); 4951 fieldsJsonString = fieldsJsonString.replace(/table/g, "!mapsvg-encoded-tbl"); 4952 fieldsJsonString = fieldsJsonString.replace(/database/g, "!mapsvg-encoded-db"); 4953 fieldsJsonString = fieldsJsonString.replace(/varchar/g, "!mapsvg-encoded-vc"); 4954 fieldsJsonString = fieldsJsonString.replace(/int\(11\)/g, "!mapsvg-encoded-int"); 4955 const back = JSON.parse(fieldsJsonString); 4956 back.fields = JSON.stringify(_schema.fields); 4957 return back; 4958 } 4959 } 4960 4961 const $$8 = jQuery; 4962 class Controller { 4963 constructor(options) { 4964 this.containers = { 4965 main: options.container, 4966 }; 4967 this.mapsvg = options.mapsvg; 4968 this.template = options.template || ""; 4969 this.scrollable = options.scrollable === undefined ? true : options.scrollable; 4970 this.withToolbar = options.withToolbar === undefined ? true : options.withToolbar; 4971 this.autoresize = MapSVG.parseBoolean(options.autoresize); 4972 this.templates = { 4973 toolbar: Handlebars.compile(this.getToolbarTemplate()), 4974 main: Handlebars.compile(this.getMainTemplate()), 4975 }; 4976 this.data = options.data; 4977 this.width = options.width; 4978 this.color = options.color; 4979 this.events = new Events(this); 4980 if (options.events) { 4981 for (const eventName in options.events) { 4982 if (typeof options.events[eventName] === "function") { 4983 this.events.on(eventName, options.events[eventName]); 4984 } 4985 } 4986 } 4987 } 4988 viewDidLoad() { 4989 const _this = this; 4990 _this.updateScroll(); 4991 if (this.autoresize) { 4992 _this.adjustHeight(); 4993 this.resizeSensor.setScroll(); 4994 } 4995 } 4996 _viewDidLoad() { 4997 this.updateScroll(); 4998 } 4999 viewDidAppear() { } 5000 viewDidDisappear() { } 5001 updateScroll() { 5002 if (!this.scrollable) 5003 return; 5004 const _this = this; 5005 $$8(this.containers.contentWrap).nanoScroller({ 5006 preventPageScrolling: true, 5007 }); 5008 setTimeout(function () { 5009 $$8(_this.containers.contentWrap).nanoScroller({ 5010 preventPageScrolling: true, 5011 }); 5012 }, 300); 5013 } 5014 adjustHeight() { 5015 const _this = this; 5016 $$8(_this.containers.main).height($$8(_this.containers.main).find(".mapsvg-auto-height").outerHeight() + 5017 (_this.containers.toolbar ? $$8(_this.containers.toolbar).outerHeight() : 0)); 5018 } 5019 _init() { 5020 const _this = this; 5021 _this.render(); 5022 _this.init(); 5023 } 5024 init() { } 5025 getToolbarTemplate() { 5026 return ""; 5027 } 5028 setMainTemplate(template) { 5029 return (this.templates.main = Handlebars.compile(template)); 5030 } 5031 getMainTemplate() { 5032 return this.template; 5033 } 5034 render() { 5035 const _this = this; 5036 this.containers.view = $$8("<div />") 5037 .attr("id", "mapsvg-controller-" + this.name) 5038 .addClass("mapsvg-controller-view")[0]; 5039 this.containers.contentWrap = $$8("<div />").addClass("mapsvg-controller-view-wrap")[0]; 5040 this.containers.contentWrap2 = $$8("<div />")[0]; 5041 this.containers.sizer = $$8("<div />").addClass("mapsvg-auto-height")[0]; 5042 this.containers.contentView = $$8("<div />").addClass("mapsvg-controller-view-content")[0]; 5043 this.containers.sizer.appendChild(this.containers.contentView); 5044 if (this.scrollable) { 5045 $$8(this.containers.contentWrap).addClass("nano"); 5046 $$8(this.containers.contentWrap2).addClass("nano-content"); 5047 } 5048 this.containers.contentWrap.appendChild(this.containers.contentWrap2); 5049 this.containers.contentWrap2.appendChild(this.containers.sizer); 5050 if (this.withToolbar && this.templates.toolbar) { 5051 this.containers.toolbar = $$8("<div />").addClass("mapsvg-controller-view-toolbar")[0]; 5052 this.containers.view.appendChild(this.containers.toolbar); 5053 } 5054 this.containers.view.append(this.containers.contentWrap); 5055 this.containers.main.appendChild(this.containers.view);
5056 $$8(this.containers.main).data("controller", this); 5057 if (this.width) 5058 this.containers.view.style.width = this.width; 5059 if (this.color) 5060 this.containers.view.style["background-color"] = this.color; 5061 _this.viewReadyToFill(); 5062 this.redraw(); 5063 setTimeout(function () { 5064 _this._viewDidLoad(); 5065 _this.viewDidLoad(); 5066 _this.setEventHandlersCommon(); 5067 _this.setEventHandlers(); 5068 }, 1); 5069 } 5070 viewReadyToFill() { 5071 const _this = this; 5072 if (_this.autoresize) { 5073 _this.resizeSensor = new ResizeSensor(this.containers.sizer, () => { 5074 _this.adjustHeight(); 5075 _this.updateScroll(); 5076 _this.events.trigger("resize", this, [this]); 5077 }); 5078 } 5079 } 5080 redraw(data) { 5081 if (data !== undefined) { 5082 this.data = data; 5083 } 5084 try { 5085 $$8(this.containers.contentView).html(this.templates.main(this.data)); 5086 } 5087 catch (err) { 5088 console.error(err); 5089 $$8(this.containers.contentView).html(""); 5090 } 5091 if (this.withToolbar && this.templates.toolbar) 5092 $$8(this.containers.toolbar).html(this.templates.toolbar(this.data)); 5093 this.updateTopShift(); 5094 if (this.noPadding) 5095 this.containers.contentView.style.padding = "0"; 5096 this.updateScroll(); 5097 } 5098 updateTopShift() { 5099 const _this = this; 5100 if (!this.withToolbar) 5101 return; 5102 $$8(_this.containers.contentWrap).css({ 5103 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5104 }); 5105 setTimeout(function () { 5106 $$8(_this.containers.contentWrap).css({ 5107 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5108 }); 5109 }, 100); 5110 setTimeout(function () { 5111 $$8(_this.containers.contentWrap).css({ 5112 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5113 }); 5114 }, 200); 5115 setTimeout(function () { 5116 $$8(_this.containers.contentWrap).css({ 5117 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5118 }); 5119 _this.updateScroll(); 5120 }, 500); 5121 } 5122 setEventHandlersCommon() { } 5123 setEventHandlers() { } 5124 destroy() { 5125 delete this.resizeSensor; 5126 $$8(this.containers.view).empty().remove(); 5127 } 5128 } 5129 5130 const $$9 = jQuery; 5131 class DirectoryController extends Controller { 5132 constructor(options) { 5133 super(options); 5134 this.repository = options.repository; 5135 this.noPadding = true; 5136 this.position = options.position; 5137 this.search = options.search; 5138 } 5139 getToolbarTemplate() { 5140 let t = '<div class="mapsvg-directory-search-wrap">'; 5141 t += '<div class="mapsvg-directory-filter-wrap filter-wrap"></div>'; 5142 t += "</div>"; 5143 t += "</div>"; 5144 return t; 5145 } 5146 viewDidLoad() { 5147 const _this = this; 5148 this.menuBtn = $$9('<div class="mapsvg-button-menu"><i class="mapsvg-icon-menu"></i> ' + 5149 this.mapsvg.options.mobileView.labelList + 5150 "</div>")[0]; 5151 this.mapBtn = $$9('<div class="mapsvg-button-map"><i class="mapsvg-icon-map"></i> ' + 5152 this.mapsvg.options.mobileView.labelMap + 5153 "</div>")[0]; 5154 if (MapSVG.isPhone && _this.mapsvg.options.menu.hideOnMobile) { 5155 if (this.mapsvg.options.menu.showFirst == "map") { 5156 this.toggle(false); 5157 } 5158 else { 5159 this.toggle(true); 5160 } 5161 } 5162 this.mobileButtons = $$9('<div class="mapsvg-mobile-buttons"></div>')[0]; 5163 this.mobileButtons.append(this.menuBtn, this.mapBtn); 5164 if (this.mapsvg.options.menu.on !== false) { 5165 this.mapsvg.containers.wrapAll.appendChild(this.mobileButtons); 5166 } 5167 this.events.trigger("shown", this.containers.view); 5168 } 5169 setEventHandlers() { 5170 const _this = this; 5171 $$9(window).on("resize", function () { 5172 _this.updateTopShift(); 5173 }); 5174 $$9(this.menuBtn).on("click", function () { 5175 _this.toggle(true); 5176 }); 5177 $$9(this.mapBtn).on("click", function () { 5178 _this.toggle(false); 5179 _this.mapsvg.redraw(); 5180 }); 5181 $$9(this.containers.view) 5182 .on("click.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5183 if (e.target.nodeName == "A") { 5184 return; 5185 } 5186 const objID = $$9(this).data("object-id"); 5187 let regions; 5188 let marker; 5189 let detailsViewObject; 5190 let eventObject; 5191 _this.deselectItems(); 5192 _this.selectItems(objID, false); 5193 if (MapSVG.isPhone && _this.mapsvg.options.menu.showMapOnClick) { 5194 _this.toggle(false); 5195 } 5196 if (_this.mapsvg.options.menu.source == "regions") { 5197 regions = [_this.mapsvg.getRegion(objID)]; 5198 eventObject = regions[0]; 5199 detailsViewObject = regions[0]; 5200 } 5201 else { 5202 detailsViewObject = _this.repository.getLoadedObject(objID); 5203 eventObject = detailsViewObject; 5204 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5205 if (_regions) { 5206 regions = _regions 5207 .map(function (region) { 5208 return _this.mapsvg.getRegion(region.id); 5209 }) 5210 .filter(function (r) { 5211 return r !== undefined; 5212 }); 5213 } 5214 } 5215 if (detailsViewObject.location && detailsViewObject.location.marker) 5216 marker = detailsViewObject.location.marker; 5217 if (_this.mapsvg.options.actions.directoryItem.click.showDetail
5217s) { 5218 _this.mapsvg.loadDetailsView(detailsViewObject); 5219 } 5220 if (regions && regions.length > 0) { 5221 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 5222 _this.mapsvg.zoomTo(regions, _this.mapsvg.options.actions.directoryItem.click.zoomToLevel); 5223 } 5224 if (regions.length > 1) { 5225 _this.mapsvg.setMultiSelect(true); 5226 } 5227 regions.forEach(function (region) { 5228 const center = region.getCenter(); 5229 e.clientX = center[0]; 5230 e.clientY = center[1]; 5231 if (_this.mapsvg.options.actions.directoryItem.click.selectRegion) { 5232 _this.mapsvg.selectRegion(region, true); 5233 } 5234 if (_this.mapsvg.options.actions.directoryItem.click.showRegionPopover) { 5235 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 5236 setTimeout(function () { 5237 _this.mapsvg.showPopover(region); 5238 }, 500); 5239 } 5240 else { 5241 _this.mapsvg.showPopover(region); 5242 } 5243 } 5244 if (_this.mapsvg.options.actions.directoryItem.click.fireRegionOnClick) { 5245 _this.mapsvg.events.trigger("click.region", region, [region]); 5246 } 5247 }); 5248 if (regions.length > 1) { 5249 _this.mapsvg.setMultiSelect(false, false); 5250 } 5251 } 5252 if (marker) { 5253 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5254 _this.mapsvg.zoomTo(marker, _this.mapsvg.options.actions.directoryItem.click.zoomToMarkerLevel); 5255 } 5256 if (_this.mapsvg.options.actions.directoryItem.click.showMarkerPopover) { 5257 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5258 setTimeout(function () { 5259 _this.mapsvg.showPopover(detailsViewObject); 5260 }, 500); 5261 } 5262 else { 5263 _this.mapsvg.showPopover(detailsViewObject); 5264 } 5265 } 5266 if (_this.mapsvg.options.actions.directoryItem.click.fireMarkerOnClick) { 5267 _this.mapsvg.events.trigger("click.marker", marker, [e, _this.mapsvg]); 5268 } 5269 _this.mapsvg.selectMarker(marker); 5270 } 5271 _this.events.trigger("click", this, [e, eventObject, _this.mapsvg]); 5272 const actions = _this.mapsvg.options.actions; 5273 if (actions.directoryItem.click.goToLink) { 5274 const linkParts = actions.directoryItem.click.linkField.split("."); 5275 let url; 5276 if (linkParts.length > 1) { 5277 const obj = linkParts.shift(); 5278 const attr = "." + linkParts.join("."); 5279 if (obj == "Region") { 5280 if (regions[0] && regions[0].data) 5281 url = eval("regions[0].data" + attr); 5282 } 5283 else { 5284 if (detailsViewObject) 5285 url = eval("detailsViewObject" + attr); 5286 } 5287 if (url) { 5288 if (actions.directoryItem.click.newTab) { 5289 const win = window.open(url, "_blank"); 5290 win.focus(); 5291 } 5292 else { 5293 window.location.href = url; 5294 } 5295 } 5296 } 5297 } 5298 if (actions.directoryItem.click.showAnotherMap) { 5299 if (_this.mapsvg.editMode) { 5300 alert('"Show another map" action is disabled in the preview'); 5301 return true; 5302 } 5303 const linkParts2 = actions.directoryItem.click.showAnotherMapField.split("."); 5304 if (linkParts2.length > 1) { 5305 const obj2 = linkParts2.shift(); 5306 const attr2 = "." + linkParts2.join("."); 5307 let map_id; 5308 if (obj2 == "Region") { 5309 if (regions[0] && regions[0].data) 5310 map_id = eval("regions[0].data" + attr2); 5311 } 5312 else { 5313 if (detailsViewObject) 5314 map_id = eval("detailsViewObject" + attr2); 5315 } 5316 if (map_id) { 5317 const container = actions.directoryItem.click.showAnotherMapContainerId 5318 ? $$9("#" + actions.directoryItem.click.showAnotherMapContainerId)[0] 5319 : $$9(_this.mapsvg.containers.wrapAll)[0]; 5320 _this.mapsvg.loadMap(map_id, container); 5321 } 5322 } 5323 } 5324 }) 5325 .on("mouseover.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5326 const objID = $$9(this).data("object-id"); 5327 let regions; 5328 let detailsViewObject; 5329 let eventObject; 5330 let marker; 5331 if (_this.mapsvg.options.menu.source == "regions") { 5332 regions = [_this.mapsvg.getRegion(objID)]; 5333 eventObject = regions[0]; 5334 detailsViewObject = regions[0]; 5335 } 5336 else { 5337 detailsViewObject = _this.repository.getLoadedObject(objID); 5338 eventObject = detailsViewObject; 5339 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5340 if (_regions) { 5341 regions = _regions.map(function (region) { 5342 return _this.mapsvg.getRegion(region.id); 5343 }); 5344 } 5345 if (detailsViewObject.location) { 5346 marker = detailsViewObject.location.marker; 5347 } 5348 } 5349 if (regions && regions.length) { 5350 _this.mapsvg.highlightRegions(regions); 5351 } 5352 if (marker) { 5353 _this.mapsvg.highlightMarker(marker); 5354 if (_this.mapsvg.options.actions.directoryItem.hover.centerOnMarker) { 5355 _this.mapsvg.centerOn(marker); 5356 } 5357 } 5358 _this.events.trigger("mouseover", $$9(this), [e, eventObject, _this.mapsvg]); 5359 }) 5360 .on("mouseout.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5361 const objID = $$9(this).data("object-id"); 5362 let regions; 5363 let detailsViewObject; 5364 let eventObject; 5365 let marker; 5366 if (_this.mapsvg.options.menu.source == "regions") { 5367 regions = [_this.mapsvg.getRegion(objID)]; 5368 eventObject = regions[0]; 5369 detailsViewObject = regions[0]; 5370 } 5371 else { 5372 detailsViewObject = _this.repository.getLoadedObject(objID); 5373 eventObject = detailsViewObject; 5374 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5375 if (_regions) { 5376 regions = _regions.map(function (region) { 5377 return _this.mapsvg.getRegion(region.id); 5378 }); 5379 } 5380 if (detailsViewObject.location) { 5381 marker = detailsViewObject.location.marker; 5382 } 5383 } 5384 if (regions && regions.length) { 5385 _this.mapsvg.unhighlightRegions(); 5386 } 5387 if (marker) { 5388 _this.mapsvg.unhighlightMarker(); 5389 } 5390 _this.events.trigger("mouseout", $$9(this), [e, eventObject, _this.mapsvg]); 5391 }); 5392 $$9(this.containers.contentView).on("click", ".mapsvg-category-item", function () { 5393 const panel = $$9(this).next(".mapsvg-category-block"); 5394 if (panel[0].style.maxHeight || panel.hasClass("active")) { 5395 panel[0].style.maxHeight = null; 5396 } 5397 else { 5398 panel[0].style.maxHeight = panel[0].scrollHeight + "px"; 5399 } 5400 if ($$9(this).hasClass("active")) { 5401 $$9(this).toggleClass("active", false); 5402 $$9(this).next(".mapsvg-category-block").addClass("collapsed").removeClass("active"); 5403 } 5404 else { 5405 if (_this.mapsvg.options.menu.categories.collapseOther) { 5406 $$9(this).parent().find(".mapsvg-category-item.active").removeClass("active"); 5407 $$9(this) 5408 .parent() 5409 .find(".mapsvg-category-block.active") 5410 .removeClass("active") 5411 .addClass("collapsed"); 5412 } 5413 $$9(this).toggleClass("active", true); 5414 $$9(this).next(".mapsvg-category-block").removeClass("collapsed").addClass("active"); 5415 } 5416 const panels = $$9(".mapsvg-category-block.collapsed"); 5417 panels.each(function (i, panel) { 5418 panel.style.maxHeight = null; 5419 }); 5420 }); 5421 } 5422 highlightItems(ids) { 5423 const _this = this; 5424 if (typeof ids != "object") 5425 ids = [ids]; 5426 ids.forEach(function (id) { 5427 $$9(_this.containers.view) 5428 .find("#mapsvg-directory-item-" + _this.convertId(id)
5428) 5429 .addClass("hover"); 5430 }); 5431 } 5432 unhighlightItems() { 5433 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("hover"); 5434 } 5435 selectItems(ids, scrollTo = true) { 5436 if (typeof ids != "object") 5437 ids = [ids]; 5438 ids.forEach((id) => { 5439 $$9(this.containers.view) 5440 .find("#mapsvg-directory-item-" + this.convertId(id)) 5441 .addClass("selected"); 5442 }); 5443 if (scrollTo && $$9("#mapsvg-directory-item-" + ids[0]).length > 0) { 5444 this.scrollable && 5445 $$9(this.containers.contentWrap).nanoScroller({ 5446 scrollTo: $$9(this.containers.view).find("#mapsvg-directory-item-" + this.convertId(ids[0])), 5447 }); 5448 } 5449 } 5450 deselectItems() { 5451 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("selected"); 5452 } 5453 removeItems(ids) { 5454 $$9(this.containers.view) 5455 .find("#mapsvg-directory-item-" + this.convertId(ids)) 5456 .remove(); 5457 } 5458 filterOut(items) { 5459 return items; 5460 } 5461 loadItemsToDirectory() { 5462 let items = []; 5463 const _this = this; 5464 if (!_this.repository.loaded) 5465 return false; 5466 if (_this.mapsvg.options.menu.categories && 5467 _this.mapsvg.options.menu.categories.on && 5468 _this.mapsvg.options.menu.categories.groupBy) { 5469 const categoryField = _this.mapsvg.options.menu.categories.groupBy; 5470 if (_this.repository.getSchema().getField(categoryField) === undefined || 5471 _this.repository.getSchema().getField(categoryField).options === undefined) { 5472 return false; 5473 } 5474 const categories = _this.repository.getSchema().getField(categoryField).options; 5475 categories.forEach(function (category) { 5476 let dbItems = _this.repository.getLoaded(); 5477 dbItems = _this.filterOut(dbItems); 5478 const itemArr = []; 5479 dbItems.forEach((item) => { 5480 itemArr.push(item); 5481 }); 5482 const catItems = itemArr.filter(function (object) { 5483 if (categoryField === "regions") { 5484 const objectRegions = typeof object[categoryField] !== "undefined" && 5485 object[categoryField].length 5486 ? object[categoryField] 5487 : []; 5488 const objectRegionIDs = objectRegions.map(function (region) { 5489 return region.id; 5490 }); 5491 return objectRegionIDs.indexOf(category.id) !== -1; 5492 } 5493 else { 5494 return object[categoryField] == category.value; 5495 } 5496 }); 5497 category.counter = catItems.length; 5498 if (categoryField === "regions") { 5499 category.label = category.title; 5500 category.value = category.id; 5501 } 5502 items.push({ category: category, items: catItems }); 5503 }); 5504 if (_this.mapsvg.options.menu.categories.hideEmpty) { 5505 items = items.filter(function (item) { 5506 return item.category.counter > 0; 5507 }); 5508 } 5509 } 5510 else { 5511 if (_this.mapsvg.options.menu.source === "regions") { 5512 items = _this.repository.getLoaded().map((r) => { 5513 const data = r.getData(); 5514 data.objects = _this.mapsvg.getRegion(data.id).objects; 5515 data.id_no_spaces = data.id.split(" ").join("_"); 5516 return data; 5517 }); 5518 } 5519 else { 5520 items = _this.repository 5521 .getLoaded() 5522 .map((r) => r.getData(_this.mapsvg.regionsRepository.schema.name)); 5523 } 5524 } 5525 try { 5526 $$9(this.containers.contentView).html(this.templates.main({ items: items })); 5527 } 5528 catch (err) { 5529 console.error('MapSVG: Error in the "Directory item" template'); 5530 console.error(err); 5531 } 5532 if (items.length === 0) { 5533 $$9(this.containers.contentView).html('<div class="mapsvg-no-results">' + 5534 this.mapsvg.options.menu.noResultsText + 5535 "</div>"); 5536 } 5537 if (_this.mapsvg.options.menu.categories.on) { 5538 if (_this.mapsvg.options.menu.categories.collapse && items.length > 1) { 5539 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("collapsed"); 5540 } 5541 else if (_this.mapsvg.options.menu.categories.collapse && items.length === 1) { 5542 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5543 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5544 const panel = $$9(this.containers.contentView).find(".mapsvg-category-block")[0]; 5545 if (panel) 5546 panel.style.maxHeight = panel.scrollHeight + "px"; 5547 } 5548 else if (!_this.mapsvg.options.menu.categories.collapse) { 5549 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5550 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5551 const panels = $$9(this.containers.contentView).find(".mapsvg-category-block"); 5552 if (panels.length) 5553 panels.each(function (i, panel) { 5554 panel.style.maxHeight = panel.scrollHeight + "px"; 5555 }); 5556 } 5557 } 5558 this.updateTopShift(); 5559 this.updateScroll(); 5560 } 5561 toggle(on) { 5562 const _this = this; 5563 if (on) { 5564 $$9(this.containers.main).parent().show(); 5565 $$9(_this.mapsvg.containers.mapContainer).hide(); 5566 $$9(this.menuBtn).addClass("active"); 5567 $$9(this.mapBtn).removeClass("active"); 5568 } 5569 else { 5570 $$9(this.containers.main).parent().hide(); 5571 $$9(_this.mapsvg.containers.mapContainer).show(); 5572 $$9(this.menuBtn).removeClass("active"); 5573 $$9(this.mapBtn).addClass("active"); 5574 } 5575 if (!$$9(this.containers.main).parent().is(":visible")) { 5576 if (MapSVG.isPhone) { 5577 $$9(_this.mapsvg.containers.wrap).css("height", "auto"); 5578 _this.updateScroll(); 5579 } 5580 } 5581 else { 5582 if (MapSVG.isPhone && 5583 $$9(this.containers.main).height() < parseInt(this.mapsvg.options.menu.minHeight)) { 5584 $$9(_this.mapsvg.containers.wrap).css("height", parseInt(this.mapsvg.options.menu.minHeight) + "px"); 5585 _this.updateScroll(); 5586 } 5587 } 5588 this.updateTopShift(); 5589 } 5590 addPagination(pager) { 5591 $$9(this.containers.contentView).append('<div class="mapsvg-pagination-container"></div>'); 5592 $$9(this.containers.contentView).find(".mapsvg-pagination-container").html(pager); 5593 } 5594 convertId(id) { 5595 return (id + "") 5596 .split(" ") 5597 .join("_") 5598 .replace(/(:|\(|\)|\.|\[|\]|,|=|@)/g, "\\$1"); 5599 } 5600 } 5601 5602 const $$a = jQuery; 5603 class DetailsController extends Controller { 5604 constructor(options) { 5605 super(options); 5606 this.modal = options.modal; 5607 } 5608 getToolbarTemplate() { 5609 if (this.withToolbar) 5610 return '<div class="mapsvg-popover-close mapsvg-details-close"></div>'; 5611 else 5612 return ""; 5613 } 5614 viewDidLoad() { 5615 const _this = this; 5616 this.events.trigger("shown", _this, [_this]); 5617 if (this.modal &&
5618 MapSVG.isPhone && 5619 this.mapsvg.options.detailsView.mobileFullscreen && 5620 !this.mobileCloseBtn) { 5621 this.mobileCloseBtn = $$a('<button class="mapsvg-mobile-modal-close">' + 5622 _this.mapsvg.options.mobileView.labelClose + 5623 "</button>")[0]; 5624 this.containers.view.appendChild(this.mobileCloseBtn); 5625 } 5626 } 5627 setEventHandlers() { 5628 const _this = this; 5629 $$a(this.containers.toolbar).on("click touchend", ".mapsvg-popover-close", function (e) { 5630 e.stopPropagation(); 5631 _this.destroy(); 5632 _this.events.trigger("closed", _this, [_this]); 5633 }); 5634 $$a(this.containers.view).on("click touchend", ".mapsvg-mobile-modal-close", function (e) { 5635 e.stopPropagation(); 5636 _this.destroy(); 5637 _this.events.trigger("closed", _this, [_this]); 5638 }); 5639 } 5640 } 5641 5642 const $$b = jQuery; 5643 class FormElement { 5644 constructor(options, formBuilder, external) { 5645 this.readonly = typeof options.readonly !== "undefined" ? options.readonly : false; 5646 this.protected = typeof options.protected !== "undefined" ? options.protected : false; 5647 this.auto_increment = 5648 typeof options.auto_increment !== "undefined" ? options.auto_increment : false; 5649 this.not_null = typeof options.not_null !== "undefined" ? options.not_null : false; 5650 this.searchable = typeof options.searchable !== "undefined" ? options.searchable : false; 5651 this.visible = typeof options.visible !== "undefined" ? options.visible : true; 5652 this.formBuilder = formBuilder; 5653 this.events = new Events(this); 5654 this.type = options.type; 5655 this.value = options.value; 5656 this.db_type = options.db_type || "varchar(255)"; 5657 this.label = this.label || (options.label === undefined ? "Label" : options.label); 5658 this.name = this.name || options.name || "label"; 5659 this.help = options.help || ""; 5660 this.placeholder = options.placeholder; 5661 this.setExternal(external); 5662 let t = this.type; 5663 if (t === "marker" && this.mapIsGeo) { 5664 t = "marker-geo"; 5665 } 5666 if (t === "location" && this.mapIsGeo) { 5667 t = "location-geo"; 5668 } 5669 if (this.filtersMode) { 5670 this.parameterName = options.parameterName || ""; 5671 this.parameterNameShort = this.parameterName.split(".")[1]; 5672 this.name = this.parameterNameShort; 5673 this.placeholder = options.placeholder || ""; 5674 this.templates = { 5675 main: Handlebars.compile($$b("#mapsvg-filters-tmpl-" + t + "-view").html()), 5676 }; 5677 } 5678 else { 5679 this.templates = { 5680 main: Handlebars.compile($$b("#mapsvg-data-tmpl-" + t + "-view").html()), 5681 }; 5682 } 5683 this.inputs = {}; 5684 } 5685 init() { 5686 this.setDomElements(); 5687 this.setEventHandlers(); 5688 } 5689 setDomElements() { 5690 this.domElements = { 5691 main: $$b(this.templates.main(this.getDataForTemplate()))[0], 5692 }; 5693 $$b(this.domElements.main).data("formElement", this); 5694 this.addSelect2(); 5695 } 5696 setEventHandlers() { 5697 const _this = this; 5698 if (this.formBuilder.editMode) { 5699 $$b(this.domElements.main).on("click", function () { 5700 _this.events.trigger("click", _this, [_this]); 5701 }); 5702 } 5703 } 5704 addSelect2() { 5705 if ($$b().mselect2) { 5706 $$b(this.domElements.main) 5707 .find("select") 5708 .css({ width: "100%", display: "block" }) 5709 .mselect2() 5710 .on("select2:focus", function () { 5711 $$b(this).mselect2("open"); 5712 }); 5713 $$b(this.domElements.main) 5714 .find(".select2-selection--multiple .select2-search__field") 5715 .css("width", "100%"); 5716 } 5717 } 5718 setEditorEventHandlers() { 5719 const _this = this; 5720 $$b(this.domElements.edit).on("click", "button.mapsvg-remove", function () { 5721 $$b(_this.domElements.main).empty().remove(); 5722 $$b(_this.domElements.edit).empty().remove(); 5723 _this.events.trigger("delete", _this, [_this]); 5724 }); 5725 $$b(this.domElements.edit).on("click", ".mapsvg-filter-insert-options", function () { 5726 const objType = _this.parameterName.split(".")[0]; 5727 const fieldName = _this.parameterName.split(".")[1]; 5728 let field; 5729 if (objType == "Object") { 5730 field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 5731 } 5732 else { 5733 if (fieldName == "id") { 5734 const options = []; 5735 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5736 options.push({ label: r.id, value: r.id }); 5737 }); 5738 field = { 5739 options: options, 5740 }; 5741 } 5742 else if (fieldName === "title") { 5743 const options = []; 5744 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5745 options.push({ label: r.title, value: r.title }); 5746 }); 5747 field = { options: options }; 5748 } 5749 else { 5750 field = _this.formBuilder.mapsvg.regionsRepository 5751 .getSchema() 5752 .getField(fieldName); 5753 } 5754 } 5755 if ((field && field.options) || fieldName === "regions") { 5756 let options; 5757 if (fieldName == "regions") { 5758 const _options = _this.formBuilder.mapsvg.regions.map((r) => { 5759 return { id: r.id, title: r.title }; 5760 }); 5761 _options.sort(function (a, b) { 5762 if (a.title < b.title) 5763 return -1; 5764 if (a.title > b.title) 5765 return 1; 5766 return 0; 5767 }); 5768 options = _options.map(function (o) { 5769 return (o.title || o.id) + ":" + o.id; 5770 }); 5771 } 5772 else { 5773 options = field.options.map(function (o) { 5774 return o.label + ":" + o.value; 5775 }); 5776 } 5777 $$b(this) 5778 .closest(".form-group") 5779 .find("textarea") 5780 .val(options.join("\n")) 5781 .trigger("change"); 5782 } 5783 }); 5784 $$b(this.domElements.edit).on("keyup change paste", "input, textarea, select", function () { 5785 const prop = $$b(this).attr("name"); 5786 const array = $$b(this).data("array"); 5787 if (_this.type === "status" && array) { 5788 const param = $$b(this).data("param"); 5789 const index = $$b(this).closest("tr").index(); 5790 _this.options[index] = _this.options[index] || { 5791 label: "", 5792 value: "", 5793 color: "", 5794 disabled: false, 5795 }; 5796 _this.options[index][param] = $$b(this).is(":checkbox") 5797 ? $$b(this).prop("checked") 5798 : $$b(this).val(); 5799 _this.redraw(); 5800 } 5801 else if (_this.type === "distance" && array) { 5802 const param = $$b(this).data("param"); 5803 const index = $$b(this).closest("tr").index(); 5804 if (!_this.options[index]) { 5805 _this.options[index] = { value: "", default: false }; 5806 } 5807 if (param === "default") { 5808 _this.options.forEach(function (option) { 5809 option.default = false;
5810 }); 5811 _this.options[index].default = $$b(this).prop("checked"); 5812 } 5813 else { 5814 _this.options[index].value = $$b(this).val(); 5815 } 5816 _this.redraw(); 5817 } 5818 else if (prop == "label" || prop == "name") { 5819 return false; 5820 } 5821 else { 5822 let value; 5823 value = 5824 $$b(this).attr("type") == "checkbox" ? $$b(this).prop("checked") : $$b(this).val(); 5825 if ($$b(this).attr("type") == "radio") { 5826 const name = $$b(this).attr("name"); 5827 value = $$b('input[name="' + name + '"]:checked').val(); 5828 } 5829 _this.update(prop, value); 5830 } 5831 }); 5832 $$b(this.domElements.edit).on("keyup change paste", 'input[name="label"]', function () { 5833 if (!_this.nameChanged) { 5834 _this.label = $$b(this).val() + ""; 5835 if (_this.type != "region" && _this.type != "location" && _this.type != "title") { 5836 let str = $$b(this).val() + ""; 5837 str = str.toLowerCase().replace(/ /g, "_").replace(/\W/g, ""); 5838 if (str.length < 64) { 5839 $$b(_this.domElements.edit).find('input[name="name"]').val(str); 5840 } 5841 _this.name = str + ""; 5842 } 5843 $$b(_this.domElements.main).find("label").first().html(_this.label); 5844 if (!_this.filtersMode) { 5845 $$b(_this.domElements.main) 5846 .find("label") 5847 .first() 5848 .append('<div class="field-name">' + _this.name + "</div>"); 5849 } 5850 } 5851 }); 5852 $$b(this.domElements.edit).on("keyup change paste", 'input[name="name"]', function (e) { 5853 if (e.target.value) { 5854 if (e.target.value.match(/[^a-zA-Z0-9_]/g)) { 5855 e.target.value = e.target.value.replace(/[^a-zA-Z0-9_]/g, ""); 5856 $$b(e.target).trigger("change"); 5857 } 5858 if (e.target.value[0].match(/[^a-zA-Z_]/g)) { 5859 e.target.value = 5860 e.target.value[0].replace(/[^a-zA-Z_]/g, "") + e.target.value.slice(1); 5861 $$b(e.target).trigger("change"); 5862 } 5863 } 5864 if (_this.type != "region") 5865 _this.name = e.target.value; 5866 $$b(_this.domElements.main) 5867 .find("label") 5868 .html(_this.label + '<div class="field-name">' + _this.name + "</div>"); 5869 _this.nameChanged = true; 5870 }); 5871 $$b(this.domElements.edit).on("keyup change paste", 'textarea[name="help"]', function (e) { 5872 $$b(_this.domElements.main).find(".form-text").text(e.target.value); 5873 }); 5874 } 5875 getEditor() { 5876 if (!this.filtersMode) { 5877 this.templates.edit = 5878 this.templates.edit || 5879 Handlebars.compile($$b("#mapsvg-data-tmpl-" + this.type + "-control").html()); 5880 } 5881 else { 5882 this.templates.edit = 5883 this.templates.edit || 5884 Handlebars.compile($$b("#mapsvg-filters-tmpl-" + this.type + "-control").html()); 5885 } 5886 this.domElements.edit = $$b("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>")[0]; 5887 return this.domElements.edit; 5888 } 5889 destroyEditor() { 5890 $$b(this.domElements.edit).empty().remove(); 5891 } 5892 initEditor() { 5893 $$b(this.domElements.edit).find("input").first().select(); 5894 if ($$b().colorpicker) { 5895 $$b(this.domElements.edit) 5896 .find(".cpicker") 5897 .colorpicker() 5898 .on("changeColor.colorpicker", function (event) { 5899 const input = $$b(this).find("input"); 5900 if (input.val() == "") 5901 $$b(this).find("i").css({ "background-color": "" }); 5902 }); 5903 } 5904 if ($$b().mselect2) {
5905 if (this.type !== "distance") { 5906 $$b(this.domElements.edit) 5907 .find("select") 5908 .css({ width: "100%", display: "block" }) 5909 .mselect2(); 5910 } 5911 } 5912 this.setEditorEventHandlers(); 5913 } 5914 getSchema() { 5915 let data; 5916 data = { 5917 type: this.type, 5918 db_type: this.db_type, 5919 label: this.label, 5920 name: this.name, 5921 value: this.value, 5922 searchable: this.searchable, 5923 help: this.help, 5924 visible: this.visible === undefined ? true : this.visible, 5925 readonly: this.readonly, 5926 placeholder: this.placeholder, 5927 protected: this.protected, 5928 auto_increment: this.auto_increment, 5929 not_null: this.not_null, 5930 }; 5931 if (this.options) { 5932 data.options = this.getSchemaFieldOptionsList(); 5933 } 5934 if (this.filtersMode) { 5935 data.parameterName = this.parameterName; 5936 data.parameterNameShort = this.parameterName.split(".")[1]; 5937 } 5938 return data; 5939 } 5940 getSchemaFieldOptionsList() { 5941 const options = []; 5942 this.options.forEach((option, index) => { 5943 if (this.options[index].value !== "") { 5944 options.push(this.options[index]); 5945 } 5946 }); 5947 return options; 5948 } 5949 getDataForTemplate() { 5950 const data = this.getSchema(); 5951 data._name = data.name; 5952 if (this.namespace) { 5953 data.name = this.name.split("[")[0]; 5954 let suffix = this.name.split("[")[1] || ""; 5955 if (suffix) 5956 suffix = "[" + suffix; 5957 data.name = this.namespace + "[" + data.name + "]" + suffix; 5958 } 5959 data.external = this.external; 5960 return data; 5961 } 5962 update(prop, value) { 5963 const _this = this; 5964 if (prop == "options") { 5965 const options = []; 5966 value = value.split("\n").forEach(function (row) { 5967 row = row.trim().split(":"); 5968 if (_this.type == "checkbox" && row.length == 3) { 5969 options.push({ 5970 label: row[0], 5971 name: row[1], 5972 value: row[2], 5973 }); 5974 } 5975 else if ((_this.type == "radio" || 5976 _this.type == "select" || 5977 _this.type == "checkboxes") && 5978 row.length == 2) { 5979 options.push({ 5980 label: row[0], 5981 value: row[1], 5982 }); 5983 } 5984 }); 5985 this.options = options; 5986 } 5987 else { 5988 this[prop] = value; 5989 } 5990 if (prop == "parameterName") { 5991 $$b(this.domElements.edit).find(".mapsvg-filter-param-name").text(value); 5992 } 5993 } 5994 redraw() { 5995 const newView = $$b(this.templates.main(this.getDataForTemplate())); 5996 $$b(this.domElements.main).html(newView.html()); 5997 if ($$b().mselect2) { 5998 if (this.type !== "distance") { 5999 $$b(this.domElements.main) 6000 .find("select") 6001 .css({ width: "100%", display: "block" }) 6002 .mselect2() 6003 .on("select2:focus", function () { 6004 $$b(this).mselect2("open"); 6005 }); 6006 } 6007 else { 6008 $$b(this.domElements.main) 6009 .find("select") 6010 .mselect2() 6011 .on("select2:focus", function () { 6012 $$b(this).mselect2("open"); 6013 }); 6014 } 6015 } 6016 } 6017 redrawEditor() { 6018 if (this.domElements.edit) { 6019 $$b(this.domElements.edit).empty(); 6020 $$b(this.domElements.edit).html("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>"); 6021 this.initEditor(); 6022 } 6023 } 6024 setOptions(options) { 6025 if (options) { 6026 this.options = []; 6027 this.optionsDict = {}; 6028 options.forEach((value, key) => { 6029 this.options.push(value); 6030 this.optionsDict[key] = value; 6031 }); 6032 return this.options; 6033 } 6034 else { 6035 return this.setOptions([ 6036 { label: "Option one", name: "option_one", value: 1 }, 6037 { label: "Option two", name: "option_two", value: 2 }, 6038 ]); 6039 } 6040 } 6041 getData() { 6042 return { name: this.name, value: this.getValue() }; 6043 } 6044 destroy() { 6045 if ($$b().mselect2) { 6046 const sel = $$b(this.domElements.main).find(".mapsvg-select2"); 6047 if (sel.length) { 6048 sel.mselect2("destroy"); 6049 } 6050 } 6051 } 6052 show() { 6053 $$b(this.domElements.main).show(); 6054 } 6055 hide() { 6056 $$b(this.domElements.main).hide(); 6057 } 6058 setExternal(params) { 6059 this.external = params; 6060 if (typeof this.external.mapIsGeo !== "undefined") { 6061 this.mapIsGeo = this.external.mapIsGeo; 6062 } 6063 if (typeof this.external.editMode !== "undefined") { 6064 this.editMode = this.external.editMode; 6065 } 6066 if (typeof this.external.filtersMode !== "undefined") { 6067 this.filtersMode = this.external.filtersMode; 6068 } 6069 if (typeof this.external.namespace !== "undefined") { 6070 this.namespace = this.external.namespace; 6071 } 6072 } 6073 getValue() { 6074 return this.value; 6075 } 6076 setValue(value, updateInput = true) { 6077 this.value = value; 6078 if (updateInput) { 6079 this.setInputValue(value); 6080 } 6081 } 6082 setInputValue(value) { 6083 return; 6084 } 6085 triggerChanged() { 6086 this.events.trigger("changed", this, [this]); 6087 } 6088 } 6089 6090 const $$c = jQuery; 6091 class CheckboxFormElement extends FormElement { 6092 constructor(options, formBuilder, external) { 6093 super(options, formBuilder, external); 6094 if (typeof options.showAsSwitch === "undefined") { 6095 this.showAsSwitch = true; 6096 } 6097 else { 6098 this.showAsSwitch = options.showAsSwitch; 6099 } 6100 this.db_type = "tinyint(1)"; 6101 this.checkboxLabel = options.checkboxLabel; 6102 this.checkboxValue = options.checkboxValue; 6103 } 6104 setDomElements() { 6105 super.setDomElements(); 6106 this.inputs.checkbox = $$c(this.domElements.main).find("input")[0]; 6107 this.inputs.switch = $$c(this.domElements.main).find("input")[0]; 6108 } 6109 setEventHandlers() { 6110 super.setEventHandlers(); 6111 $$c(this.inputs.checkbox).on("change", (e) => { 6112 this.setValue(e.target.checked, false); 6113 this.triggerChanged(); 6114 }); 6115 } 6116 setEditorEventHandlers() { 6117 super.setEditorEventHandlers(); 6118 $$c(this.domElements.edit).on("change", "[name='showAsSwitch']", (e) => { 6119 if (this.showAsSwitch) { 6120 $$c(this.domElements.main) 6121 .find("[name='checkboxToSwitch']") 6122 .addClass("form-switch form-switch-md"); 6123 } 6124 if (!this.showAsSwitch) { 6125 $$c(this.domElements.main) 6126 .find("[name='checkboxToSwitch']") 6127 .removeClass("form-switch form-switch-md"); 6128 } 6129 }); 6130 $$c(this.domElements.edit).on("keyup change paste", '[name="checkboxLabel"]',
6130(e) => { 6131 $$c(this.domElements.main).find(".form-check-label").text(e.target.value); 6132 }); 6133 } 6134 getSchema() { 6135 const schema = super.getSchema(); 6136 if (this.checkboxLabel) { 6137 schema.checkboxLabel = this.checkboxLabel; 6138 } 6139 if (this.checkboxValue) { 6140 schema.checkboxValue = this.checkboxValue; 6141 } 6142 schema.showAsSwitch = this.showAsSwitch; 6143 return schema; 6144 } 6145 setInputValue(value) { 6146 this.inputs.checkbox.checked = value === true; 6147 } 6148 } 6149 6150 const $$d = jQuery; 6151 class CheckboxesFormElement extends FormElement { 6152 constructor(options, formBuilder, external) { 6153 super(options, formBuilder, external); 6154 this.db_type = "text"; 6155 this.checkboxLabel = options.checkboxLabel; 6156 this.setOptions(options.options); 6157 } 6158 setDomElements() { 6159 super.setDomElements(); 6160 this.$checkboxes = $$d(this.domElements.main).find('input[type="checkbox"]'); 6161 this.setInputValue(this.value || []); 6162 } 6163 setEventHandlers() { 6164 super.setEventHandlers(); 6165 this.$checkboxes.on("change", (e) => { 6166 const values = []; 6167 $$d(this.domElements.main) 6168 .find("input:checked") 6169 .each((i, el) => { 6170 values.push(jQuery(el).attr("value")); 6171 }); 6172 this.setValue(values, false); 6173 this.triggerChanged(); 6174 }); 6175 } 6176 setInputValue(values) { 6177 if (values === null) { 6178 $$d(this.domElements.main).find(`input`).prop("checked", false); 6179 } 6180 else { 6181 values.forEach((value) => { 6182 $$d(this.domElements.main).find(`input[value="${value}"]`).prop("checked", true); 6183 }); 6184 } 6185 } 6186 } 6187 6188 const $$e = jQuery; 6189 class DateFormElement extends FormElement { 6190 constructor(options, formBuilder, external) { 6191 super(options, formBuilder, external); 6192 if (this.formBuilder.admin) { 6193 this.languages = [ 6194 "en-GB", 6195 "ar", 6196 "az", 6197 "bg", 6198 "bs", 6199 "ca", 6200 "cs", 6201 "cy", 6202 "da", 6203 "de", 6204 "el", 6205 "es", 6206 "et", 6207 "eu", 6208 "fa", 6209 "fi", 6210 "fo", 6211 "fr", 6212 "gl", 6213 "he", 6214 "hr", 6215 "hu", 6216 "hy", 6217 "id", 6218 "is", 6219 "it", 6220 "ja", 6221 "ka", 6222 "kh", 6223 "kk", 6224 "kr", 6225 "lt", 6226 "lv", 6227 "mk", 6228 "ms", 6229 "nb", 6230 "nl", 6231 "nl-BE", 6232 "no", 6233 "pl", 6234 "pt-BR", 6235 "pt", 6236 "ro", 6237 "rs", 6238 "rs-latin", 6239 "ru", 6240 "sk", 6241 "sl", 6242 "sq", 6243 "sr", 6244 "sr-latin", 6245 "sv", 6246 "sw", 6247 "th", 6248 "tr", 6249 "uk", 6250 "vi", 6251 "zh-CN", 6252 "zh-TW", 6253 ]; 6254 } 6255 this.db_type = "varchar(50)"; 6256 this.language = options.language; 6257 } 6258 setDomElements() { 6259 super.setDomElements(); 6260 this.inputs.date = $$e(this.domElements.main).find("input")[0]; 6261 } 6262 setEventHandlers() { 6263 super.setEventHandlers(); 6264 $$e(this.inputs.date).on("change", (e) => { 6265 this.setValue(e.target.value, false); 6266 this.triggerChanged(); 6267 }); 6268 } 6269 getSchema() { 6270 const schema = super.getSchema(); 6271 schema.language = this.language; 6272 return schema; 6273 } 6274 getDataForTemplate() { 6275 const data = super.getDataForTemplate(); 6276 if (this.formBuilder.admin) 6277 data.languages = this.languages; 6278 data.language = this.language; 6279 return data; 6280 } 6281 } 6282 6283 const $$f = jQuery; 6284 class DistanceFormElement extends FormElement { 6285 constructor(options, formBuilder, external) { 6286 super(options, formBuilder, external); 6287 this.name = "distance"; 6288 this.label = this.label || (options.label === undefined ? "Search radius" : options.label); 6289 this.distanceControl = options.distanceControl || "select"; 6290 this.distanceUnits = options.distanceUnits || "km"; 6291 this.distanceUnitsLabel = options.distanceUnitsLabel || "km"; 6292 this.fromLabel = options.fromLabel || "from"; 6293 this.placeholder = options.placeholder; 6294 this.userLocationButton = options.userLocationButton || false; 6295 this.type = options.type; 6296 this.addressField = options.addressField || true; 6297 this.addressFieldPlaceholder = options.addressFieldPlaceholder || "Address"; 6298 this.languages = [ 6299 { value: "sq", label: "Albanian" }, 6300 { value: "ar", label: "Arabic" }, 6301 { 6302 value: "eu", 6303 label: "Basque", 6304 }, 6305 { value: "be", label: "Belarusian" }, 6306 { value: "bg", label: "Bulgarian" }, 6307 { 6308 value: "my", 6309 label: "Burmese", 6310 }, 6311 { value: "bn", label: "Bengali" }, 6312 { value: "ca", label: "Catalan" }, 6313 { 6314 value: "zh-cn", 6315 label: "Chinese (simplified)", 6316 }, 6317 { value: "zh-tw", label: "Chinese (traditional)" }, 6318 { 6319 value: "hr", 6320 label: "Croatian", 6321 }, 6322 { value: "cs", label: "Czech" }, 6323 { value: "da", label: "Danish" }, 6324 { 6325 value: "nl", 6326 label: "Dutch", 6327 }, 6328 { value: "en", label: "English" }, 6329 { 6330 value: "en-au", 6331 label: "English (australian)", 6332 }, 6333 { value: "en-gb", label: "English (great Britain)" }, 6334 { 6335 value: "fa", 6336 label: "Farsi", 6337 }, 6338 { value: "fi", label: "Finnish" }, 6339 { value: "fil", label: "Filipino" }, 6340 { 6341 value: "fr", 6342 label: "French", 6343 }, 6344 { value: "gl", label: "Galician" }, 6345 { value: "de", label: "German" }, 6346 { 6347 value: "el", 6348 label: "Greek", 6349 }, 6350 { value: "gu", label: "Gujarati" }, 6351 { value: "iw", label: "Hebrew" }, 6352 { 6353 value: "hi", 6354 label: "Hindi", 6355 }, 6356 { value: "hu", label: "Hungarian" }, 6357 { value: "id", label: "Indonesian" }, 6358 { 6359 value: "it", 6360 label: "Italian", 6361 }, 6362 { value: "ja", label: "Japanese" }, 6363 { value: "kn", label: "Kannada" }, 6364 { 6365 value: "kk", 6366 label: "Kazakh", 6367 }, 6368 { value: "ko", label: "Korean" }, 6369 { value: "ky", label: "Kyrgyz" }, 6370 { 6371 value: "lt", 6372 label: "Lithuanian", 6373 }, 6374 { value: "lv", label: "Latvian" }, 6375 { value: "mk", label: "Macedonian" }, 6376 { 6377 value: "ml", 6378 label: "Malayalam", 6379 }, 6380 { value: "mr", label: "Marathi" },
6381 { value: "no", label: "Norwegian" }, 6382 { 6383 value: "pl", 6384 label: "Polish", 6385 }, 6386 { value: "pt", label: "Portuguese" }, 6387 { 6388 value: "pt-br", 6389 label: "Portuguese (brazil)", 6390 }, 6391 { value: "pt-pt", label: "Portuguese (portugal)" }, 6392 { 6393 value: "pa", 6394 label: "Punjabi", 6395 }, 6396 { value: "ro", label: "Romanian" }, 6397 { value: "ru", label: "Russian" }, 6398 { 6399 value: "sr", 6400 label: "Serbian", 6401 }, 6402 { value: "sk", label: "Slovak" }, 6403 { value: "sl", label: "Slovenian" }, 6404 { 6405 value: "es", 6406 label: "Spanish", 6407 }, 6408 { value: "sv", label: "Swedish" }, 6409 { value: "tl", label: "Tagalog" }, 6410 { 6411 value: "ta", 6412 label: "Tamil", 6413 }, 6414 { value: "te", label: "Telugu" }, 6415 { value: "th", label: "Thai" }, 6416 { 6417 value: "tr", 6418 label: "Turkish", 6419 }, 6420 { value: "uk", label: "Ukrainian" }, 6421 { value: "uz", label: "Uzbek" }, 6422 { 6423 value: "vi", 6424 label: "Vietnamese", 6425 }, 6426 ]; 6427 this.countries = MapSVG.countries; 6428 this.country = options.country; 6429 this.language = options.language; 6430 this.searchByZip = options.searchByZip; 6431 this.zipLength = parseInt(options.zipLength) || 5; 6432 this.userLocationButton = MapSVG.parseBoolean(options.userLocationButton); 6433 this.options = options.options || [ 6434 { value: "10", default: true }, 6435 { value: "30", default: false }, 6436 { value: "50", default: false }, 6437 { value: "100", default: false }, 6438 ]; 6439 let defOption; 6440 if (this.value) { 6441 this.options.forEach((option) => { 6442 if (option.value === this.value.length) { 6443 defOption = option; 6444 } 6445 }); 6446 } 6447 if (!defOption) { 6448 defOption = this.options.find(function (option) { 6449 return option.default === true; 6450 }); 6451 } 6452 if (!defOption) { 6453 defOption = this.options[0]; 6454 } 6455 const defLengthOption = this.options.find((opt) => opt.selected === true); 6456 this.defaultLength = defOption.value; 6457 this.setDefaultValue(); 6458 } 6459 setDefaultValue() { 6460 this.value = { 6461 units: this.distanceUnits, 6462 geoPoint: { lat: null, lng: null }, 6463 length: this.defaultLength, 6464 address: "", 6465 country: this.country, 6466 }; 6467 } 6468 setDomElements() { 6469 super.setDomElements(); 6470 this.inputs.units = ($$f(this.domElements.main).find('[name="distanceUnits"]')[0]); 6471 this.inputs.geoPoint = ($$f(this.domElements.main).find('[name="distanceGeoPoint"]')[0]); 6472 this.inputs.length = ($$f(this.domElements.main).find('[name="distanceLength"]')[0]); 6473 this.inputs.address = ($$f(this.domElements.main).find('[name="distance"]')[0]); 6474 } 6475 getSchema() { 6476 const schema = super.getSchema(); 6477 schema.distanceControl = this.distanceControl; 6478 schema.distanceUnits = this.distanceUnits; 6479 schema.distanceUnitsLabel = this.distanceUnitsLabel; 6480 schema.fromLabel = this.fromLabel; 6481 schema.addressField = this.addressField; 6482 schema.addressFieldPlaceholder = this.addressFieldPlaceholder; 6483 schema.userLocationButton = this.userLocationButton; 6484 schema.placeholder = this.placeholder; 6485 schema.language = this.language; 6486 schema.country = this.country; 6487 schema.searchByZip = this.searchByZip; 6488 schema.zipLength = parseInt(this.zipLength + ""); 6489 schema.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6490 if (schema.distanceControl === "none") { 6491 schema.distanceDefault = schema.options.filter(function (o) { 6492 return o.default; 6493 })[0].value; 6494 } 6495 schema.options.forEach(function (option, index) { 6496 if (schema.options[index].value === "") { 6497 schema.options.splice(index, 1); 6498 } 6499 else { 6500 schema.options[index].default = MapSVG.parseBoolean(schema.options[index].default); 6501 } 6502 }); 6503 return schema; 6504 } 6505 getDataForTemplate() { 6506 const data = super.getDataForTemplate(); 6507 if (this.formBuilder.admin) { 6508 data.languages = this.languages; 6509 data.countries = this.countries; 6510 } 6511 data.language = this.language; 6512 data.country = this.country; 6513 data.searchByZip = this.searchByZip; 6514 data.zipLength = this.zipLength; 6515 data.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6516 return data; 6517 } 6518 destroy() { 6519 if ($$f().mselect2) { 6520 const sel = $$f(this.domElements.main).find(".mapsvg-select2"); 6521 if (sel.length) { 6522 sel.mselect2("destroy"); 6523 } 6524 } 6525 } 6526 initEditor() { 6527 super.initEditor(); 6528 this.mayBeAddDistanceRow(); 6529 if ($$f().mselect2) { 6530 $$f(this.domElements.edit).find("select").mselect2(); 6531 } 6532 } 6533 setEventHandlers() { 6534 super.setEventHandlers(); 6535 const _this = this; 6536 $$f(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-distance-row input", function () { 6537 _this.mayBeAddDistanceRow(); 6538 }); 6539 const server = new Server(); 6540 const locations = new Bloodhound({ 6541 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 6542 queryTokenizer: Bloodhound.tokenizers.whitespace, 6543 remote: { 6544 url: server.getUrl("geocoding") + 6545 "?address=" + 6546 (this.searchByZip === true ? "zip%20" : "") + 6547 "%QUERY%&language=" + 6548 this.language + 6549 (this.country ? "&country=" + this.country : ""), 6550 wildcard: "%QUERY%", 6551 transform: function (response) { 6552 if (response.error_message) { 6553 alert(response.error_message); 6554 } 6555 return response.results; 6556 }, 6557 rateLimitWait: 600, 6558 }, 6559 }); 6560 const thContainer = $$f(this.domElements.main).find(".typeahead"); 6561 this.spinner = $$f("<span class='spinner-border spinner-border-sm'></span>")[0]; 6562 if (this.searchByZip) { 6563 $$f(this.domElements.main).find(".mapsvg-distance-fields").addClass("search-by-zip"); 6564 thContainer.on("change keyup", (e) => { 6565 const zip = $$f(e.target).val().toString(); 6566 if (zip.length === _this.zipLength) { 6567 $$f(this.spinner).appendTo($$f(e.target).closest(".distance-search-wrap")); 6568 locations.search($$f(e.target).val(), (data) => this.handleAddressFieldChange(zip, data), (data) => this.handleAddressFieldChange(zip, data, true)); 6569 } 6570 }); 6571 } 6572 else { 6573 const tH = thContainer 6574 .typeahead({ minLength: 3 }, { 6575 name: "mapsvg-addresses", 6576 display: "formatted_address", 6577 limit: 5, 6578 async: true, 6579 source: (query, sync, async) => { 6580 const request = { address: query }; 6581 if (this.country) { 6582 request.componentRestrictions = { country: this.country }; 6583 } 6584 MapSVG.geocode(request, async); 6585 }, 6586 }) 6587 .on("typeahead:asyncrequest", (e) => { 6588 $$f(this.spinner).appendTo($$f(e.target).closest(".twitter-typeahead")); 6589 }) 6590 .on("typeahead:asynccancel typeahead:asyncreceive", (e) => { 6591 $$f(this.spinner).remove(); 6592 }); 6593 $$f(this.domElements.main).find(".mapsvg-distance-fields").removeClass("search-by-zip"); 6594 } 6595 if (_this.userLocationButton) { 6596 const userLocationButton = $$f(this.domElements.main).find(".user-location-button"); 6597 userLocationButton.on("click", () => { 6598 _this.formBuilder.mapsvg.showUserLocation((location) => { 6599 locations.search(location.geoPoint.lat + "," + location.geoPoint.lng, (data) => this.setAddressByUserLocation(data, location), (data) => this.setAddressByUserLocation(data, location)); 6600 this.setValue({ geoPoint: location.geoPoint }); 6601 this.triggerChanged(); 6602 }); 6603 }); 6604 } 6605 thContainer.on("change keyup", (e) => { 6606 const input = e.target; 6607 if (input.value === "" && this.getValue() !== null) { 6608 this.setValue(null); 6609 this.triggerChanged(); 6610 } 6611 }); 6612 thContainer.on("typeahead:select", (ev, item) => { 6613 this.setValue({ 6614 address: item.formatted_address, 6615 geoPoint: item.geometry.location.toJSON(), 6616 }); 6617 this.triggerChanged(); 6618 thContainer.blur(); 6619 }); 6620 $$f(this.inputs.geoPoint).on("change", (e) => { 6621 const geoPoint = e.target.value.split(",").map((value) => parseFloat(value)); 6622 this.setValue({ geoPoint: { lat: geoPoint[0], lng: geoPoint[1] } }, false); 6623 this.triggerChanged(); 6624 }); 6625 $$f(this.inputs.length).on("change", (e) => { 6626 this.setLength(parseInt(e.target.value), false); 6627 this.triggerChanged(); 6628 }); 6629 } 6630 setAddressByUserLocation(data, location) { 6631 if (data && data[0]) { 6632 this.setAddress(data[0].formatted_address); 6633 } 6634 else { 6635 this.setAddress(location.geoPoint.lat + "," + location.geoPoint.lng); 6636 } 6637 } 6638 handleAddressFieldChange(zip, data, removeSpinner = false) { 6639 if (removeSpinner) { 6640 $$f(this.spinner).remove(); 6641 } 6642 if (data && data[0]) { 6643 this.setValue({ address: zip, geoPoint: data[0].geometry.location }, false); 6644 this.triggerChanged(); 6645 } 6646 } 6647 addSelect2() { 6648 if ($$f().mselect2) { 6649 $$f(this.domElements.main) 6650 .find("select") 6651 .mselect2() 6652 .on("select2:focus", function () { 6653 $$f(this).mselect2("open"); 6654 }); 6655 } 6656 } 6657 mayBeAddDistanceRow() { 6658 const _this = this; 6659 const editDistanceRow = $$f($$f("#mapsvg-edit-distance-row").html()); 6660 const z = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 6661 if (z && z.last() && z.last().val() && z.last().val().toString().trim().length) { 6662 const newRow = editDistanceRow.clone(); 6663 newRow.insertAfter($$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 6664 } 6665 const rows = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 6666 const row1 = rows.eq(rows.length - 2); 6667 const row2 = rows.eq(rows.length - 1); 6668 if (row1.length && 6669 row2.length && 6670 !row1.find("input:eq(0)").val().toString().trim() && 6671 !row2.find("input:eq(0)").val().toString().trim()) { 6672 row2.remove(); 6673 } 6674 } 6675 setValue(value, updateInput = true) { 6676 if (value === null) { 6677 this.setGeoPoint(null); 6678 this.setAddress(""); 6679 } 6680 else { 6681 for (const key in value) { 6682 if (typeof this.value[key] !== undefined) { 6683 const method = "set" + MapSVG.ucfirst(key); 6684 if (typeof this[method] === "function") { 6685 this[method](value[key], updateInput); 6686 } 6687 } 6688 } 6689 } 6690 } 6691 setGeoPoint(geoPoint, updateInput = true) { 6692 this.value.geoPoint = geoPoint === null ? { lat: null, lng: null } : geoPoint; 6693 if (updateInput) { 6694 this.setInputGeoPointValue(geoPoint); 6695 } 6696 } 6697 setInputGeoPointValue(geoPoint) { 6698 this.inputs.geoPoint.value = geoPoint ? geoPoint.lat + "," + geoPoint.lng : ""; 6699 } 6700 setLength(length, updateInput = true) { 6701 this.value.length = parseInt(length.toString()); 6702 this.defaultLength = this.value.length; 6703 if (updateInput) { 6704 this.setInputLengthValue(this.value.length); 6705 } 6706 } 6707 setInputLengthValue(length) { 6708 this.inputs.length.value = length.toString(); 6709 } 6710 setAddress(address, updateInput = true) { 6711 this.value.address = address !== null ? address : ""; 6712 if (updateInput) { 6713 this.setInputAddressValue(this.value.address); 6714 } 6715 } 6716 setInputAddressValue(address) { 6717 this.inputs.address.value = address; 6718 } 6719 getValue() { 6720 return this.value.geoPoint.lat === null ? null : this.value; 6721 } 6722 } 6723 6724 const $$g = jQuery; 6725 class EmptyFormElement extends FormElement { 6726 constructor(options, formBuilder, external) { 6727 super(options, formBuilder, external); 6728 this.readonly = true; 6729 } 6730 } 6731 6732 class IdFormElement extends FormElement { 6733 constructor(options, formBuilder, external) { 6734 super(options, formBuilder, external); 6735 } 6736 getData() { 6737 return { name: "id", value: this.value }; 6738 } 6739 } 6740 6741 function createCommonjsModule(fn, module) { 6742 return module = { exports: {} }, fn(module, module.exports), module.exports; 6743 } 6744 6745 var sortable_min = createCommonjsModule(function (module) { 6746 /**! 6747 * Sortable 6748 * @author RubaXa <[email protected]> 6749 * @license MIT 6750 */ 6751 6752 (function sortableModule(factory) { 6753 6754 { 6755 module.exports = factory(); 6756 } 6757 })(function sortableFactory() { 6758 6759 if (typeof window == "undefined" || !window.document) { 6760 return function sortableError() { 6761 throw new Error("Sortable.js requires a window with a document"); 6762 }; 6763 } 6764 6765 var dragEl, 6766 parentEl, 6767 ghostEl, 6768 cloneEl, 6769 rootEl, 6770 nextEl, 6771 scrollEl, 6772 scrollParentEl, 6773 scrollCustomFn, 6774 lastEl, 6775 lastCSS, 6776 lastParentCSS, 6777 oldIndex, 6778 newIndex, 6779 activeGroup, 6780 putSortable, 6781 autoScroll = {}, 6782 tapEvt, 6783 touchEvt, 6784 moved, 6785 /** @const */ 6786 RSPACE = /\s+/g, 6787 expando = "Sor
6787table" + new Date().getTime(), 6788 win = window, 6789 document = win.document, 6790 parseInt = win.parseInt, 6791 $ = win.jQuery || win.Zepto, 6792 Polymer = win.Polymer, 6793 supportDraggable = !!("draggable" in document.createElement("div")), 6794 supportCssPointerEvents = (function (el) { 6795 // false when IE11 6796 if (navigator.userAgent.match(/Trident.*rv[ :]?11\./)) { 6797 return false; 6798 } 6799 el = document.createElement("x"); 6800 el.style.cssText = "pointer-events:auto"; 6801 return el.style.pointerEvents === "auto"; 6802 })(), 6803 _silent = false, 6804 abs = Math.abs, 6805 min = Math.min, 6806 touchDragOverListeners = [], 6807 _autoScroll = _throttle(function ( 6808 /**Event*/ evt, 6809 /**Object*/ options, 6810 /**HTMLElement*/ rootEl 6811 ) { 6812 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 6813 if (rootEl && options.scroll) { 6814 var el, 6815 rect, 6816 sens = options.scrollSensitivity, 6817 speed = options.scrollSpeed, 6818 x = evt.clientX, 6819 y = evt.clientY, 6820 winWidth = window.innerWidth, 6821 winHeight = window.innerHeight, 6822 vx, 6823 vy, 6824 scrollOffsetX, 6825 scrollOffsetY; 6826 6827 // Delect scrollEl 6828 if (scrollParentEl !== rootEl) { 6829 scrollEl = options.scroll; 6830 scrollParentEl = rootEl; 6831 scrollCustomFn = options.scrollFn; 6832 6833 if (scrollEl === true) { 6834 scrollEl = rootEl; 6835 6836 do { 6837 if ( 6838 scrollEl.offsetWidth < scrollEl.scrollWidth || 6839 scrollEl.offsetHeight < scrollEl.scrollHeight 6840 ) { 6841 break; 6842 } 6843 /* jshint boss:true */ 6844 } while ((scrollEl = scrollEl.parentNode)); 6845 } 6846 } 6847 6848 if (scrollEl) { 6849 el = scrollEl; 6850 rect = scrollEl.getBoundingClientRect(); 6851 vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); 6852 vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); 6853 } 6854 6855 if (!(vx || vy)) { 6856 vx = (winWidth - x <= sens) - (x <= sens); 6857 vy = (winHeight - y <= sens) - (y <= sens); 6858 6859 /* jshint expr:true */ 6860 (vx || vy) && (el = win); 6861 } 6862 6863 if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) { 6864 autoScroll.el = el; 6865 autoScroll.vx = vx; 6866 autoScroll.vy = vy; 6867 6868 clearInterval(autoScroll.pid); 6869 6870 if (el) { 6871 autoScroll.pid = setInterval(function () { 6872 scrollOffsetY = vy ? vy * speed : 0; 6873 scrollOffsetX = vx ? vx * speed : 0; 6874 6875 if ("function" === typeof scrollCustomFn) { 6876 return scrollCustomFn.call( 6877 _this, 6878 scrollOffsetX, 6879 scrollOffsetY, 6880 evt 6881 ); 6882 } 6883 6884 if (el === win) { 6885 win.scrollTo( 6886 win.pageXOffset + scrollOffsetX, 6887 win.pageYOffset + scrollOffsetY 6888 ); 6889 } else { 6890 el.scrollTop += scrollOffsetY; 6891 el.scrollLeft += scrollOffsetX; 6892 } 6893 }, 24); 6894 } 6895 } 6896 } 6897 }, 6898 30), 6899 _prepareGroup = function (options) { 6900 function toFn(value, pull) { 6901 if (value === void 0 || value === true) { 6902 value = group.name; 6903 } 6904 6905 if (typeof value === "function") { 6906 return value; 6907 } else { 6908 return function (to, from) { 6909 var fromGroup = from.options.group.name; 6910 6911 return pull 6912 ? value 6913 : value && 6914 (value.join ? value.indexOf(fromGroup) > -1 : fromGroup == value); 6915 }; 6916 } 6917 } 6918 6919 var group = {}; 6920 var originalGroup = options.group; 6921 6922 if (!originalGroup || typeof originalGroup != "object") { 6923 originalGroup = { name: originalGroup }; 6924 } 6925 6926 group.name = originalGroup.name; 6927 group.checkPull = toFn(originalGroup.pull, true); 6928 group.checkPut = toFn(originalGroup.put); 6929 6930 options.group = group; 6931 }; 6932 /** 6933 * @class Sortable 6934 * @param {HTMLElement} el 6935 * @param {Object} [options] 6936 */ 6937 function Sortable(el, options) { 6938 if (!(el && el.nodeType && el.nodeType === 1)) { 6939 throw "Sortable: `el` must be HTMLElement, and not " + {}.toString.call(el); 6940 } 6941 6942 this.el = el; // root element 6943 this.options = options = _extend({}, options); 6944 6945 // Export instance 6946 el[expando] = this; 6947 6948 // Default options 6949 var defaults = { 6950 group: Math.random(), 6951 sort: true, 6952 disabled: false, 6953 store: null, 6954 handle: null, 6955 scroll: true, 6956 scrollSensitivity: 30, 6957 scrollSpeed: 10, 6958 draggable: /[uo]l/i.test(el.nodeName) ? "li" : ">*", 6959 ghostClass: "sortable-ghost", 6960 chosenClass: "sortable-chosen", 6961 dragClass: "sortable-drag", 6962 ignore: "a, img", 6963 filter: null, 6964 animation: 0, 6965 setData: function (dataTransfer, dragEl) { 6966 dataTransfer.setData("Text", dragEl.textContent); 6967 }, 6968 dropBubble: false, 6969 dragoverBubble: false, 6970 dataIdAttr: "data-id", 6971 delay: 0, 6972 forceFallback: false, 6973 fallbackClass: "sortable-fallback", 6974 fallbackOnBody: false, 6975 fallbackTolerance: 0, 6976 fallbackOffset: { x: 0, y: 0 }, 6977 }; 6978 6979 // Set default options 6980 for (var name in defaults) { 6981 !(name in options) && (options[name] = defaults[name]); 6982 } 6983 6984 _prepareGroup(options); 6985 6986 // Bind all private methods 6987 for (var fn in this) { 6988 if (fn.charAt(0) === "_" && typeof this[fn] === "function") { 6989 this[fn] = this[fn].bind(this); 6990 } 6991 } 6992 6993 // Setup drag mode 6994 this.nativeDraggable = options.forceFallback ? false : supportDraggable; 6995 6996 // Bind events 6997 _on(el, "mousedown", this._onTapStart); 6998 _on(el, "touchstart", this._onTapStart); 6999 7000 if (this.nativeDraggable) { 7001 _on(el, "dragover", this); 7002 _on(el, "dragenter", this); 7003 } 7004 7005 touchDragOverListeners.push(this._onDragOver); 7006 7007 // Restore sorting 7008 options.store && this.sort(options.store.get(this)); 7009 } 7010 7011 Sortable.prototype = /** @lends Sortable.prototype */ { 7012 constructor: Sortable, 7013 7014 _onTapStart: function (/** Event|TouchEvent */ evt) { 7015 if (evt.target.tagName == "i" || evt.target.tagName == "I") { 7016 evt.target.click(); 7017 return; 7018 } 7019 var _this = this, 7020 el = this.el, 7021 options = this.options, 7022 type = evt.type, 7023 touch = evt.touches && evt.touches[0], 7024 target = (touch || evt).target, 7025 originalTarget = (evt.target.shadowRoot && evt.path[0]) || target, 7026 filter = options.filter, 7027 startIndex; 7028 7029 // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. 7030 if (dragEl) { 7031 return; 7032 } 7033 7034 if ((type === "mousedown" && evt.button !== 0) || options.disabled) { 7035 return; // only left button or enabled 7036 } 7037 7038 if (options.handle && !_closest(originalTarget, options.handle, el)) { 7039 return; 7040 } 7041 7042 target = _closest(target, options.draggable, el); 7043 7044 if (!target) { 7045 return; 7046 } 7047 7048 // Get the index of the dragged element within its parent 7049 startIndex = _index(target, options.draggable); 7050 7051 // Check filter 7052 if (typeof filter === "function") { 7053 if (filter.call(this, evt, target, this)) { 7054 _dispatchEvent(_this, originalTarget, "filter", target, el, startIndex); 7055 evt.preventDefault(); 7056 return; // cancel dnd 7057 } 7058 } else if (filter) {
7059 filter = filter.split(",").some(function (criteria) { 7060 criteria = _closest(originalTarget, criteria.trim(), el); 7061 7062 if (criteria) { 7063 _dispatchEvent(_this, criteria, "filter", target, el, startIndex); 7064 return true; 7065 } 7066 }); 7067 7068 if (filter) { 7069 evt.preventDefault(); 7070 return; // cancel dnd 7071 } 7072 } 7073 7074 // Prepare `dragstart` 7075 this._prepareDragStart(evt, touch, target, startIndex); 7076 }, 7077 7078 _prepareDragStart: function ( 7079 /** Event */ evt, 7080 /** Touch */ touch, 7081 /** HTMLElement */ target, 7082 /** Number */ startIndex 7083 ) { 7084 var _this = this, 7085 el = _this.el, 7086 options = _this.options, 7087 ownerDocument = el.ownerDocument, 7088 dragStartFn; 7089 7090 if (target && !dragEl && target.parentNode === el) { 7091 tapEvt = evt; 7092 7093 rootEl = el; 7094 dragEl = target; 7095 parentEl = dragEl.parentNode; 7096 nextEl = dragEl.nextSibling; 7097 activeGroup = options.group; 7098 oldIndex = startIndex; 7099 7100 this._lastX = (touch || evt).clientX; 7101 this._lastY = (touch || evt).clientY; 7102 7103 dragEl.style["will-change"] = "transform"; 7104 7105 dragStartFn = function () { 7106 // Delayed drag has been triggered 7107 // we can re-enable the events: touchmove/mousemove 7108 _this._disableDelayedDrag(); 7109 7110 // Make the element draggable 7111 dragEl.draggable = _this.nativeDraggable; 7112 7113 // Chosen item 7114 _toggleClass(dragEl, options.chosenClass, true); 7115 7116 // Bind the events: dragstart/dragend 7117 _this._triggerDragStart(touch); 7118 7119 // Drag start event 7120 _dispatchEvent(_this, rootEl, "choose", dragEl, rootEl, oldIndex); 7121 }; 7122 7123 // Disable "draggable" 7124 options.ignore.split(",").forEach(function (criteria) { 7125 _find(dragEl, criteria.trim(), _disableDraggable); 7126 }); 7127 7128 _on(ownerDocument, "mouseup", _this._onDrop); 7129 _on(ownerDocument, "touchend", _this._onDrop); 7130 _on(ownerDocument, "touchcancel", _this._onDrop); 7131 7132 if (options.delay) { 7133 // If the user moves the pointer or let go the click or touch 7134 // before the delay has been reached: 7135 // disable the delayed drag 7136 _on(ownerDocument, "mouseup", _this._disableDelayedDrag); 7137 _on(ownerDocument, "touchend", _this._disableDelayedDrag); 7138 _on(ownerDocument, "touchcancel", _this._disableDelayedDrag); 7139 _on(ownerDocument, "mousemove", _this._disableDelayedDrag); 7140 _on(ownerDocument, "touchmove", _this._disableDelayedDrag); 7141 7142 _this._dragStartTimer = setTimeout(dragStartFn, options.delay); 7143 } else { 7144 dragStartFn(); 7145 } 7146 } 7147 }, 7148 7149 _disableDelayedDrag: function () { 7150 var ownerDocument = this.el.ownerDocument; 7151 7152 clearTimeout(this._dragStartTimer); 7153 _off(ownerDocument, "mouseup", this._disableDelayedDrag); 7154 _off(ownerDocument, "touchend", this._disableDelayedDrag); 7155 _off(ownerDocument, "touchcancel", this._disableDelayedDrag); 7156 _off(ownerDocument, "mousemove", this._disableDelayedDrag); 7157 _off(ownerDocument, "touchmove", this._disableDelayedDrag); 7158 }, 7159 7160 _triggerDragStart: function (/** Touch */ touch) { 7161 if (touch) { 7162 // Touch device support 7163 tapEvt = { 7164 target: dragEl, 7165 clientX: touch.clientX, 7166 clientY: touch.clientY, 7167 }; 7168 7169 this._onDragStart(tapEvt, "touch"); 7170 } else if (!this.nativeDraggable) { 7171 this._onDragStart(tapEvt, true); 7172 } else { 7173 _on(dragEl, "dragend", this); 7174 _on(rootEl, "dragstart", this._onDragStart); 7175 } 7176 7177 try { 7178 if (document.selection) { 7179 // Timeout neccessary for IE9 7180 setTimeout(function () { 7181 document.selection.empty(); 7182 }); 7183 } else { 7184 window.getSelection().removeAllRanges(); 7185 } 7186 } catch (err) {} 7187 }, 7188 7189 _dragStarted: function () { 7190 if (rootEl && dragEl) { 7191 var options = this.options; 7192 7193 // Apply effect 7194 _toggleClass(dragEl, options.ghostClass, true); 7195 _toggleClass(dragEl, options.dragClass, false); 7196 7197 Sortable.active = this; 7198 7199 // Drag start event 7200 _dispatchEvent(this, rootEl, "start", dragEl, rootEl, oldIndex); 7201 } 7202 }, 7203 7204 _emulateDragOver: function () { 7205 if (touchEvt) { 7206 if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) { 7207 return; 7208 } 7209 7210 this._lastX = touchEvt.clientX; 7211 this._lastY = touchEvt.clientY; 7212 7213 if (!supportCssPointerEvents) { 7214 _css(ghostEl, "display", "none"); 7215 } 7216 7217 var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), 7218 parent = target, 7219 i = touchDragOverListeners.length; 7220 7221 if (parent) { 7222 do { 7223 if (parent[expando]) { 7224 while (i--) { 7225 touchDragOverListeners[i]({ 7226 clientX: touchEvt.clientX, 7227 clientY: touchEvt.clientY, 7228 target: target, 7229 rootEl: parent, 7230 }); 7231 } 7232 7233 break; 7234 } 7235 7236 target = parent; // store last element 7237 } while ( 7238 /* jshint boss:true */ 7239 (parent = parent.parentNode) 7240 ); 7241 } 7242 7243 if (!supportCssPointerEvents) { 7244 _css(ghostEl, "display", ""); 7245 } 7246 } 7247 }, 7248 7249 _onTouchMove: function (/**TouchEvent*/ evt) { 7250 if (tapEvt) { 7251 var options = this.options, 7252 fallbackTolerance = options.fallbackTolerance, 7253 fallbackOffset = options.fallbackOffset, 7254 touch = evt.touches ? evt.touches[0] : evt, 7255 dx = touch.clientX - tapEvt.clientX + fallbackOffset.x, 7256 dy = touch.clientY - tapEvt.clientY + fallbackOffset.
7256y, 7257 translate3d = evt.touches 7258 ? "translate3d(" + dx + "px," + dy + "px,0)" 7259 : "translate(" + dx + "px," + dy + "px)"; 7260 7261 // only set the status to dragging, when we are actually dragging 7262 if (!Sortable.active) { 7263 if ( 7264 fallbackTolerance && 7265 min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < 7266 fallbackTolerance 7267 ) { 7268 return; 7269 } 7270 7271 this._dragStarted(); 7272 } 7273 7274 // as well as creating the ghost element on the document body 7275 this._appendGhost(); 7276 7277 moved = true; 7278 touchEvt = touch; 7279 7280 _css(ghostEl, "webkitTransform", translate3d); 7281 _css(ghostEl, "mozTransform", translate3d); 7282 _css(ghostEl, "msTransform", translate3d); 7283 _css(ghostEl, "transform", translate3d); 7284 7285 evt.preventDefault(); 7286 } 7287 }, 7288 7289 _appendGhost: function () { 7290 if (!ghostEl) { 7291 var rect = dragEl.getBoundingClientRect(), 7292 css = _css(dragEl), 7293 options = this.options, 7294 ghostRect; 7295 7296 ghostEl = dragEl.cloneNode(true); 7297 7298 _toggleClass(ghostEl, options.ghostClass, false); 7299 _toggleClass(ghostEl, options.fallbackClass, true); 7300 _toggleClass(ghostEl, options.dragClass, true); 7301 7302 _css(ghostEl, "top", rect.top - parseInt(css.marginTop, 10)); 7303 _css(ghostEl, "left", rect.left - parseInt(css.marginLeft, 10)); 7304 _css(ghostEl, "width", rect.width); 7305 _css(ghostEl, "height", rect.height); 7306 _css(ghostEl, "opacity", "0.8"); 7307 _css(ghostEl, "position", "fixed"); 7308 _css(ghostEl, "zIndex", "100000"); 7309 _css(ghostEl, "pointerEvents", "none"); 7310 7311 (options.fallbackOnBody && document.body.appendChild(ghostEl)) || 7312 rootEl.appendChild(ghostEl); 7313 7314 // Fixing dimensions. 7315 ghostRect = ghostEl.getBoundingClientRect(); 7316 _css(ghostEl, "width", rect.width * 2 - ghostRect.width); 7317 _css(ghostEl, "height", rect.height * 2 - ghostRect.height); 7318 } 7319 }, 7320 7321 _onDragStart: function (/**Event*/ evt, /**boolean*/ useFallback) { 7322 var dataTransfer = evt.dataTransfer, 7323 options = this.options; 7324 7325 this._offUpEvents(); 7326 7327 if (activeGroup.checkPull(this, this, dragEl, evt) == "clone") { 7328 cloneEl = _clone(dragEl); 7329 _css(cloneEl, "display", "none"); 7330 rootEl.insertBefore(cloneEl, dragEl); 7331 _dispatchEvent(this, rootEl, "clone", dragEl); 7332 } 7333 7334 _toggleClass(dragEl, options.dragClass, true); 7335 7336 if (useFallback) { 7337 if (useFallback === "touch") { 7338 // Bind touch events 7339 _on(document, "touchmove", this._onTouchMove); 7340 _on(document, "touchend", this._onDrop); 7341 _on(document, "touchcancel", this._onDrop); 7342 } else { 7343 // Old brwoser 7344 _on(document, "mousemove", this._onTouchMove); 7345 _on(document, "mouseup", this._onDrop); 7346 } 7347 7348 this._loopId = setInterval(this._emulateDragOver, 50); 7349 } else { 7350 if (dataTransfer) { 7351 dataTransfer.effectAllowed = "move"; 7352 options.setData && options.setData.call(this, dataTransfer, dragEl); 7353 } 7354 7355 _on(document, "drop", this); 7356 setTimeout(this._dragStarted, 0); 7357 } 7358 }, 7359 7360 _onDragOver: function (/**Event*/ evt) { 7361 var el = this.el, 7362 target, 7363 dragRect, 7364 targetRect, 7365 revert, 7366 options = this.options, 7367 group = options.group, 7368 activeSortable = Sortable.active, 7369 isOwner = activeGroup === group, 7370 canSort = options.sort; 7371 7372 if (evt.preventDefault !== void 0) { 7373 evt.preventDefault(); 7374 !options.dragoverBubble && evt.stopPropagation(); 7375 } 7376 7377 moved = true; 7378 7379 if ( 7380 activeGroup && 7381 !options.disabled && 7382 (isOwner 7383 ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list 7384 : putSortable === this || 7385 (activeGroup.checkPull(this, activeSortable, dragEl, evt) && 7386 group.checkPut(this, activeSortable, dragEl, evt))) && 7387 (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback 7388 ) { 7389 // Smart auto-scrolling 7390 _autoScroll(evt, options, this.el); 7391 7392 if (_silent) { 7393 return; 7394 } 7395 7396 target = _closest(evt.target, options.draggable, el); 7397 dragRect = dragEl.getBoundingClientRect(); 7398 putSortable = this; 7399 7400 if (revert) { 7401 _cloneHide(true); 7402 parentEl = rootEl; // actualization 7403 7404 if (cloneEl || nextEl) { 7405 rootEl.insertBefore(dragEl, cloneEl || nextEl); 7406 } else if (!canSort) { 7407 rootEl.appendChild(dragEl); 7408 } 7409 7410 return; 7411 } 7412 7413 if ( 7414 el.children.length === 0 || 7415 el.children[0] === ghostEl || 7416 (el === evt.target && (target = _ghostIsLast(el, evt))) 7417 ) { 7418 if (target) { 7419 if (target.animated) { 7420 return; 7421 } 7422 7423 targetRect = target.getBoundingClientRect(); 7424 } 7425 7426 _cloneHide(isOwner); 7427 7428 if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { 7429 if (!dragEl.contains(el)) { 7430 el.appendChild(dragEl); 7431 parentEl = el; // actualization 7432 } 7433 7434 this._animate(dragRect, dragEl); 7435 target && this._animate(targetRect, target); 7436 } 7437 } else if ( 7438 target && 7439 !target.animated && 7440 target !== dragEl && 7441 target.parentNode[expando] !== void 0 7442 ) { 7443 if (lastEl !== target) { 7444 lastEl = target; 7445 lastCSS = _css(target); 7446 lastParentCSS = _css(target.parentNode); 7447 } 7448 7449 targetRect = target.getBoundingClientRect(); 7450 7451 var width = targetRect.right - targetRect.left, 7452 height = targetRect.bottom - targetRect.top, 7453 floating = 7454 /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display) || 7455 (lastParentCSS.display == "flex" && 7456 lastParentCSS["flex-direction"].indexOf("row") === 0), 7457 isWide = target.offsetWidth > dragEl.offsetWidth, 7458 isLong = target.offsetHeight > dragEl.offsetHeight, 7459 halfway = 7460 (floating 7461 ? (evt.clientX - targetRect.left) / width 7462 : (evt.clientY - targetRect.top) / height) > 0.5, 7463 nextSibling = target.nextElementSibling, 7464 moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt), 7465 after; 7466 7467 if (moveVector !== false) { 7468 _silent = true; 7469 setTimeout(_unsilent, 30); 7470 7471 _cloneHide(isOwner); 7472 7473 if (moveVector === 1 || moveVector === -1) { 7474 after = moveVector === 1; 7475 } else if (floating) { 7476 var elTop = dragEl.offsetTop, 7477 tgTop = target.offsetTop; 7478 7479 if (elTop === tgTop) { 7480 after = 7481 (target.previousElementSibling === dragEl && !isWide) || 7482 (halfway && isWide); 7483 } else if ( 7484 target.previousElementSibling === dragEl || 7485 dragEl.previousElementSibling === target 7486 ) { 7487 after = (evt.clientY - targetRect.top) / height > 0.5; 7488 } else { 7489 after = tgTop > elTop; 7490 } 7491 } else { 7492 after = (nextSibling !== dragEl && !isLong) || (halfway && isLong); 7493 } 7494 7495 if (!dragEl.contains(el)) { 7496 if (after && !nextSibling) { 7497 el.appendChild(dragEl); 7498 } else { 7499 target.parentNode.insertBefore( 7500 dragEl, 7501 after ? nextSibling : target 7502 ); 7503 } 7504 } 7505 7506 parentEl = dragEl.parentNode; // actualization 7507 7508 this._animate(dragRect, dragEl); 7509 this._animate(targetRect, target); 7510 } 7511 } 7512 } 7513 }, 7514 7515 _animate: function (prevRect, target) { 7516 var ms = this.options.animation; 7517 7518 if (ms) { 7519 var currentRect = target.getBoundingClientRect(); 7520 7521 _css(target, "transition", "none"); 7522 _css( 7523 target, 7524 "transform", 7525 "translate3d(" + 7526 (prevRect.left - currentRect.left) + 7527 "px," + 7528 (prevRect.top - currentRect.top) + 7529 "px,0)" 7530 ); 7531 7532 target.offsetWidth; // repaint 7533 7534 _css(target, "transition", "all " + ms + "ms");
7535 _css(target, "transform", "translate3d(0,0,0)"); 7536 7537 clearTimeout(target.animated); 7538 target.animated = setTimeout(function () { 7539 _css(target, "transition", ""); 7540 _css(target, "transform", ""); 7541 target.animated = false; 7542 }, ms); 7543 } 7544 }, 7545 7546 _offUpEvents: function () { 7547 var ownerDocument = this.el.ownerDocument; 7548 7549 _off(document, "touchmove", this._onTouchMove); 7550 _off(ownerDocument, "mouseup", this._onDrop); 7551 _off(ownerDocument, "touchend", this._onDrop); 7552 _off(ownerDocument, "touchcancel", this._onDrop); 7553 }, 7554 7555 _onDrop: function (/**Event*/ evt) { 7556 var el = this.el, 7557 options = this.options; 7558 7559 clearInterval(this._loopId); 7560 clearInterval(autoScroll.pid); 7561 clearTimeout(this._dragStartTimer); 7562 7563 // Unbind events 7564 _off(document, "mousemove", this._onTouchMove); 7565 7566 if (this.nativeDraggable) { 7567 _off(document, "drop", this); 7568 _off(el, "dragstart", this._onDragStart); 7569 } 7570 7571 this._offUpEvents(); 7572 7573 if (evt) { 7574 if (moved) { 7575 evt.preventDefault(); 7576 !options.dropBubble && evt.stopPropagation(); 7577 } 7578 7579 ghostEl && ghostEl.parentNode.removeChild(ghostEl); 7580 7581 if (dragEl) { 7582 if (this.nativeDraggable) { 7583 _off(dragEl, "dragend", this); 7584 } 7585 7586 _disableDraggable(dragEl); 7587 dragEl.style["will-change"] = ""; 7588 7589 // Remove class's 7590 _toggleClass(dragEl, this.options.ghostClass, false); 7591 _toggleClass(dragEl, this.options.chosenClass, false); 7592 7593 if (rootEl !== parentEl) { 7594 newIndex = _index(dragEl, options.draggable); 7595 7596 if (newIndex >= 0) { 7597 // Add event 7598 _dispatchEvent( 7599 null, 7600 parentEl, 7601 "add", 7602 dragEl, 7603 rootEl, 7604 oldIndex, 7605 newIndex 7606 ); 7607 7608 // Remove event 7609 _dispatchEvent( 7610 this, 7611 rootEl, 7612 "remove", 7613 dragEl, 7614 rootEl, 7615 oldIndex, 7616 newIndex 7617 ); 7618 7619 // drag from one list and drop into another 7620 _dispatchEvent( 7621 null, 7622 parentEl, 7623 "sort", 7624 dragEl, 7625 rootEl, 7626 oldIndex, 7627 newIndex 7628 ); 7629 _dispatchEvent( 7630 this, 7631 rootEl, 7632 "sort", 7633 dragEl, 7634 rootEl, 7635 oldIndex, 7636 newIndex 7637 ); 7638 } 7639 } else { 7640 // Remove clone 7641 cloneEl && cloneEl.parentNode.removeChild(cloneEl); 7642 7643 if (dragEl.nextSibling !== nextEl) { 7644 // Get the index of the dragged element within its parent 7645 newIndex = _index(dragEl, options.draggable); 7646 7647 if (newIndex >= 0) { 7648 // drag & drop within the same list 7649 _dispatchEvent( 7650 this, 7651 rootEl, 7652 "update", 7653 dragEl, 7654 rootEl, 7655 oldIndex, 7656 newIndex 7657 ); 7658 _dispatchEvent( 7659 this, 7660 rootEl, 7661 "sort", 7662 dragEl, 7663 rootEl, 7664 oldIndex, 7665 newIndex 7666 ); 7667 } 7668 } 7669 } 7670 7671 if (Sortable.active) { 7672 /* jshint eqnull:true */ 7673 if (newIndex == null || newIndex === -1) { 7674 newIndex = oldIndex; 7675 } 7676 7677 _dispatchEvent(this, rootEl, "end", dragEl, rootEl, oldIndex, newIndex); 7678 7679 // Save sorting 7680 this.save(); 7681 } 7682 } 7683 } 7684
7685 this._nulling(); 7686 }, 7687 7688 _nulling: function () { 7689 rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = scrollEl = scrollParentEl = tapEvt = touchEvt = moved = newIndex = lastEl = lastCSS = putSortable = activeGroup = Sortable.active = null; 7690 }, 7691 7692 handleEvent: function (/**Event*/ evt) { 7693 var type = evt.type; 7694 7695 if (type === "dragover" || type === "dragenter") { 7696 if (dragEl) { 7697 this._onDragOver(evt); 7698 _globalDragOver(evt); 7699 } 7700 } else if (type === "drop" || type === "dragend") { 7701 this._onDrop(evt); 7702 } 7703 }, 7704 7705 /** 7706 * Serializes the item into an array of string. 7707 * @returns {String[]} 7708 */ 7709 toArray: function () { 7710 var order = [], 7711 el, 7712 children = this.el.children, 7713 i = 0, 7714 n = children.length, 7715 options = this.options; 7716 7717 for (; i < n; i++) { 7718 el = children[i]; 7719 if (_closest(el, options.draggable, this.el)) { 7720 order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); 7721 } 7722 } 7723 7724 return order; 7725 }, 7726 7727 /** 7728 * Sorts the elements according to the array. 7729 * @param {String[]} order order of the items 7730 */ 7731 sort: function (order) { 7732 var items = {}, 7733 rootEl = this.el; 7734 7735 this.toArray().forEach(function (id, i) { 7736 var el = rootEl.children[i]; 7737 7738 if (_closest(el, this.options.draggable, rootEl)) { 7739 items[id] = el; 7740 } 7741 }, this); 7742 7743 order.forEach(function (id) { 7744 if (items[id]) { 7745 rootEl.removeChild(items[id]); 7746 rootEl.appendChild(items[id]); 7747 } 7748 }); 7749 }, 7750 7751 /** 7752 * Save the current sorting 7753 */ 7754 save: function () { 7755 var store = this.options.store; 7756 store && store.set(this); 7757 }, 7758 7759 /** 7760 * 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. 7761 * @param {HTMLElement} el 7762 * @param {String} [selector] default: `options.draggable` 7763 * @returns {HTMLElement|null} 7764 */ 7765 closest: function (el, selector) { 7766 return _closest(el, selector || this.options.draggable, this.el); 7767 }, 7768 7769 /** 7770 * Set/get option 7771 * @param {string} name 7772 * @param {*} [value] 7773 * @returns {*} 7774 */ 7775 option: function (name, value) { 7776 var options = this.options; 7777 7778 if (value === void 0) { 7779 return options[name]; 7780 } else { 7781 options[name] = value; 7782 7783 if (name === "group") { 7784 _prepareGroup(options); 7785 } 7786 } 7787 }, 7788 7789 /** 7790 * Destroy 7791 */ 7792 destroy: function () { 7793 var el = this.el; 7794 7795 el[expando] = null; 7796 7797 _off(el, "mousedown", this._onTapStart); 7798 _off(el, "touchstart", this._onTapStart); 7799 7800 if (this.nativeDraggable) { 7801 _off(el, "dragover", this); 7802 _off(el, "dragenter", this); 7803 } 7804 7805 // Remove draggable attributes 7806 Array.prototype.forEach.call(el.querySelectorAll("[draggable]"), function (el) { 7807 el.removeAttribute("draggable"); 7808 }); 7809 7810 touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); 7811 7812 this._onDrop(); 7813 7814 this.el = el = null; 7815 }, 7816 }; 7817 7818 function _cloneHide(state) { 7819 if (cloneEl && cloneEl.state !== state) { 7820 _css(cloneEl, "display", state ? "none" : ""); 7821 !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl); 7822 cloneEl.state = state; 7823 } 7824 } 7825 7826 function _closest(/**HTMLElement*/ el, /**String*/ selector, /**HTMLElement*/ ctx) { 7827 if (el) { 7828 ctx = ctx || document; 7829 7830 do { 7831 if ((selector === ">*" && el.parentNode === ctx) || _matches(el, selector)) { 7832 return el; 7833 } 7834 /* jshint boss:true */ 7835 } while ((el = _getParentOrHost(el))); 7836 } 7837 7838 return null; 7839 } 7840 7841 function _getParentOrHost(el) { 7842 var parent = el.host; 7843 7844 return parent && parent.nodeType ? parent : el.parentNode; 7845 } 7846 7847 function _globalDragOver(/**Event*/ evt) { 7848 if (evt.dataTransfer) { 7849 evt.dataTransfer.dropEffect = "move"; 7850 } 7851 evt.preventDefault(); 7852 } 7853 7854 function _on(el, event, fn) { 7855 el.addEventListener(event, fn, false); 7856 } 7857 7858 function _off(el, event, fn) { 7859 el.removeEventListener(event, fn, false); 7860 } 7861 7862 function _toggleClass(el, name, state) { 7863 if (el) { 7864 if (el.classList) { 7865 el.classList[state ? "add" : "remove"](name); 7866 } else { 7867 var className = (" " + el.className + " ") 7868 .replace(RSPACE, " ") 7869 .replace(" " + name + " ", " "); 7870 el.className = (className + (state ? " " + name : "")).replace(RSPACE, " "); 7871 } 7872 } 7873 } 7874 7875 function _css(el, prop, val) { 7876 var style = el && el.style; 7877 7878 if (style) { 7879 if (val === void 0) { 7880 if (document.defaultView && document.defaultView.getComputedStyle) { 7881 val = document.defaultView.getComputedStyle(el, ""); 7882 } else if (el.currentStyle) { 7883 val = el.currentStyle; 7884 } 7885 7886 return prop === void 0 ? val : val[prop]; 7887 } else { 7888 if (!(prop in style)) { 7889 prop = "-webkit-" + prop; 7890 } 7891 7892 style[prop] = val + (typeof val === "string" ? "" : "px"); 7893 } 7894 } 7895 } 7896 7897 function _find(ctx, tagName, iterator) { 7898 if (ctx) { 7899 var list = ctx.getElementsByTagName(tagName), 7900 i = 0, 7901 n = list.length; 7902 7903 if (iterator) { 7904 for (; i < n; i++) { 7905 iterator(list[i], i); 7906 } 7907 } 7908 7909 return list; 7910 } 7911 7912 return []; 7913 } 7914 7915 function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) { 7916 sortable = sortable || rootEl[expando]; 7917 7918 var evt = document.createEvent("Event"),
7919 options = sortable.options, 7920 onName = "on" + name.charAt(0).toUpperCase() + name.substr(1); 7921 7922 evt.initEvent(name, true, true); 7923 7924 evt.to = rootEl; 7925 evt.from = fromEl || rootEl; 7926 evt.item = targetEl || rootEl; 7927 evt.clone = cloneEl; 7928 7929 evt.oldIndex = startIndex; 7930 evt.newIndex = newIndex; 7931 7932 rootEl.dispatchEvent(evt); 7933 7934 if (options[onName]) { 7935 options[onName].call(sortable, evt); 7936 } 7937 } 7938 7939 function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt) { 7940 var evt, 7941 sortable = fromEl[expando], 7942 onMoveFn = sortable.options.onMove, 7943 retVal; 7944 7945 evt = document.createEvent("Event"); 7946 evt.initEvent("move", true, true); 7947 7948 evt.to = toEl; 7949 evt.from = fromEl; 7950 evt.dragged = dragEl; 7951 evt.draggedRect = dragRect; 7952 evt.related = targetEl || toEl; 7953 evt.relatedRect = targetRect || toEl.getBoundingClientRect(); 7954 7955 fromEl.dispatchEvent(evt); 7956 7957 if (onMoveFn) { 7958 retVal = onMoveFn.call(sortable, evt, originalEvt); 7959 } 7960 7961 return retVal; 7962 } 7963 7964 function _disableDraggable(el) { 7965 el.draggable = false; 7966 } 7967 7968 function _unsilent() { 7969 _silent = false; 7970 } 7971 7972 /** @returns {HTMLElement|false} */ 7973 function _ghostIsLast(el, evt) { 7974 var lastEl = el.lastElementChild, 7975 rect = lastEl.getBoundingClientRect(); 7976 7977 // 5 â min delta 7978 // abs â нелÑÐ·Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑÑ, а Ñо глÑки пÑи наведении ÑвеÑÑ Ñ 7979 return ( 7980 (evt.clientY - (rect.top + rect.height) > 5 || 7981 evt.clientX - (rect.right + rect.width) > 5) && 7982 lastEl 7983 ); 7984 } 7985 7986 /** 7987 * Generate id 7988 * @param {HTMLElement} el 7989 * @returns {String} 7990 * @private 7991 */ 7992 function _generateId(el) { 7993 var str = el.tagName + el.className + el.src + el.href + el.textContent, 7994 i = str.length, 7995 sum = 0; 7996 7997 while (i--) { 7998 sum += str.charCodeAt(i); 7999 } 8000 8001 return sum.toString(36); 8002 } 8003 8004 /** 8005 * Returns the index of an element within its parent for a selected set of 8006 * elements 8007 * @param {HTMLElement} el 8008 * @param {selector} selector 8009 * @return {number} 8010 */ 8011 function _index(el, selector) { 8012 var index = 0; 8013 8014 if (!el || !el.parentNode) { 8015 return -1; 8016 } 8017 8018 while (el && (el = el.previousElementSibling)) { 8019 if ( 8020 el.nodeName.toUpperCase() !== "TEMPLATE" && 8021 (selector === ">*" || _matches(el, selector)) 8022 ) { 8023 index++; 8024 } 8025 } 8026 8027 return index; 8028 } 8029 8030 function _matches(/**HTMLElement*/ el, /**String*/ selector) { 8031 if (el) { 8032 selector = selector.split("."); 8033 8034 var tag = selector.shift().toUpperCase(), 8035 re = new RegExp("\\s(" + selector.join("|") + ")(?=\\s)", "g"); 8036 8037 return ( 8038 (tag === "" || el.nodeName.toUpperCase() == tag) && 8039 (!selector.length || 8040 ((" " + el.className + " ").match(re) || []).length == selector.length) 8041 ); 8042 } 8043 8044 return false; 8045 } 8046 8047 function _throttle(callback, ms) { 8048 var args, _this; 8049 8050 return function () { 8051 if (args === void 0) { 8052 args = arguments; 8053 _this = this; 8054 8055 setTimeout(function () { 8056 if (args.length === 1) { 8057 callback.call(_this, args[0]); 8058 } else { 8059 callback.apply(_this, args); 8060 } 8061 8062 args = void 0; 8063 }, ms); 8064 } 8065 }; 8066 } 8067 8068 function _extend(dst, src) { 8069 if (dst && src) { 8070 for (var key in src) { 8071 if (src.hasOwnProperty(key)) { 8072 dst[key] = src[key]; 8073 } 8074 } 8075 } 8076 8077 return dst; 8078 } 8079 8080 function _clone(el) { 8081 return $ 8082 ? $(el).clone(true)[0] 8083 : Polymer && Polymer.dom 8084 ? Polymer.dom(el).cloneNode(true) 8085 : el.cloneNode(true); 8086 } 8087 8088 // Export utils 8089 Sortable.utils = { 8090 on: _on, 8091 off: _off, 8092 css: _css, 8093 find: _find, 8094 is: function (el, selector) { 8095 return !!_closest(el, selector, el); 8096 }, 8097 extend: _extend, 8098 throttle: _throttle, 8099 closest: _closest, 8100 toggleClass: _toggleClass, 8101 clone: _clone, 8102 index: _index, 8103 }; 8104 8105 /** 8106 * Create sortable instance 8107 * @param {HTMLElement} el 8108 * @param {Object} [options] 8109 */ 8110 Sortable.create = function (el, options) { 8111 return new Sortable(el, options); 8112 }; 8113 8114 // Export
8115 Sortable.version = "1.4.2"; 8116 return Sortable; 8117 }); 8118 }); 8119 8120 const $$h = jQuery; 8121 class ImagesFormElement extends FormElement { 8122 constructor(options, formBuilder, external) { 8123 super(options, formBuilder, external); 8124 this.searchType = options.searchType || "fulltext"; 8125 this.mediaUploader = external.mediaUploader; 8126 this.button_text = options.button_text || "Browse..."; 8127 this.db_type = "text"; 8128 this.label = options.label || "Images"; 8129 this.name = options.name || "images"; 8130 this.images = this.value || []; 8131 this.value = JSON.stringify(this.value); 8132 } 8133 init() { 8134 super.init(); 8135 this.redrawImages(); 8136 } 8137 setDomElements() { 8138 super.setDomElements(); 8139 } 8140 getData() { 8141 this.updateData(); 8142 return { name: this.name, value: this.images }; 8143 } 8144 getSchema() { 8145 const schema = super.getSchema(); 8146 schema.button_text = this.button_text; 8147 return schema; 8148 } 8149 updateData() { 8150 const newListOfImages = []; 8151 $$h(this.domElements.main) 8152 .find(".mapsvg-thumbnail-wrap") 8153 .each(function (index, el) { 8154 const imageData = $$h(el).data("image"); 8155 newListOfImages.push(imageData); 8156 }); 8157 this.images = newListOfImages; 8158 this.value = JSON.stringify(this.images); 8159 $$h(this.domElements.main).find("input").val(this.value); 8160 } 8161 setEventHandlers() { 8162 super.setEventHandlers(); 8163 if (this.formBuilder.editMode) { 8164 return; 8165 } 8166 const _this = this; 8167 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 8168 this.external.mediaUploader.on("select", () => { 8169 if (_this.formBuilder.mediaUploaderisOpenedFor !== _this) 8170 return false; 8171 const attachments = _this.external.mediaUploader.state().get("selection").toJSON(); 8172 attachments.forEach(function (img) { 8173 const image = { sizes: {} }; 8174 for (const type in img.sizes) { 8175 image[type] = img.sizes[type].url 8176 .replace("http://", "//") 8177 .replace("https://", "//"); 8178 image.sizes[type] = { 8179 width: img.sizes[type].width, 8180 height: img.sizes[type].height, 8181 }; 8182 } 8183 if (!image.thumbnail) { 8184 image.thumbnail = image.full; 8185 image.sizes.thumbnail = { 8186 width: img.sizes.full.width, 8187 height: img.sizes.full.height, 8188 }; 8189 } 8190 if (!image.medium) { 8191 image.medium = image.full; 8192 image.sizes.medium = { 8193 width: img.sizes.full.width, 8194 height: img.sizes.full.height, 8195 }; 8196 } 8197 image.caption = img.caption; 8198 image.description = img.description; 8199 _this.images.push(image); 8200 }); 8201 this.setValue(this.images); 8202 _this.redrawImages(); 8203 }); 8204 $$h(_this.domElements.main).on("click", ".mapsvg-upload-image", function (e) { 8205 e.preventDefault(); 8206 _this.formBuilder.mediaUploaderisOpenedFor = _this; 8207 _this.external.mediaUploader.open(); 8208 }); 8209 $$h(_this.domElements.main).on("click", ".mapsvg-image-delete", function (e) { 8210 e.preventDefault(); 8211 $$h(this).closest(".mapsvg-thumbnail-wrap").remove(); 8212 _this.updateData(); 8213 }); 8214 _this.sortable = new sortable_min(imageDOM[0], { 8215 animation: 150, 8216 onStart: function () { 8217 $$h(_this.domElements.main).addClass("sorting"); 8218 }, 8219 onEnd: function (evt) { 8220 _this.images = []; 8221 $$h(_this.domElements.main) 8222 .find("img") 8223 .each(function (i, image) { 8224 _this.images.push($$h(image).data("image")); 8225 }); 8226 this.value = JSON.stringify(_this.images); 8227 $$h(_this.domElements.main).find("input").val(this.value); 8228 $$h(_this.domElements.main).removeClass("sorting"); 8229 }, 8230 }); 8231 } 8232 redrawImages() { 8233 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 8234 imageDOM.empty(); 8235 this.images &&
8236 this.images.forEach(function (image) { 8237 const img = $$h('<img class="mapsvg-data-thumbnail" />') 8238 .attr("src", image.thumbnail) 8239 .data("image", image); 8240 const imgContainer = $$h('<div class="mapsvg-thumbnail-wrap"></div>').data("image", image); 8241 imgContainer.append(img); 8242 imgContainer.append('<i class="mfa mfa-times mapsvg-image-delete"></i>'); 8243 imageDOM.append(imgContainer); 8244 }); 8245 $$h(this.domElements.main).find("input").val(this.value); 8246 } 8247 destroy() { 8248 super.destroy(); 8249 this.external.mediaUploader.off("select"); 8250 } 8251 } 8252 8253 const $$i = jQuery; 8254 class LocationFormElement extends FormElement { 8255 constructor(options, formBuilder, external) { 8256 super(options, formBuilder, external); 8257 this.label = this.label || (options.label === undefined ? "Location" : options.label); 8258 this.name = "location"; 8259 this.db_type = "text"; 8260 this.languages = [ 8261 { value: "sq", label: "Albanian" }, 8262 { value: "ar", label: "Arabic" }, 8263 { 8264 value: "eu", 8265 label: "Basque", 8266 }, 8267 { value: "be", label: "Belarusian" }, 8268 { value: "bg", label: "Bulgarian" }, 8269 { 8270 value: "my", 8271 label: "Burmese", 8272 }, 8273 { value: "bn", label: "Bengali" }, 8274 { value: "ca", label: "Catalan" }, 8275 { 8276 value: "zh-cn", 8277 label: "Chinese (simplified)", 8278 }, 8279 { value: "zh-tw", label: "Chinese (traditional)" }, 8280 { 8281 value: "hr", 8282 label: "Croatian", 8283 }, 8284 { value: "cs", label: "Czech" }, 8285 { value: "da", label: "Danish" }, 8286 { 8287 value: "nl", 8288 label: "Dutch", 8289 }, 8290 { value: "en", label: "English" }, 8291 { 8292 value: "en-au", 8293 label: "English (australian)", 8294 }, 8295 { value: "en-gb", label: "English (great Britain)" }, 8296 { 8297 value: "fa", 8298 label: "Farsi", 8299 }, 8300 { value: "fi", label: "Finnish" }, 8301 { value: "fil", label: "Filipino" }, 8302 { 8303 value: "fr", 8304 label: "French", 8305 }, 8306 { value: "gl", label: "Galician" }, 8307 { value: "de", label: "German" }, 8308 { 8309 value: "el", 8310 label: "Greek", 8311 }, 8312 { value: "gu", label: "Gujarati" }, 8313 { value: "iw", label: "Hebrew" }, 8314 { 8315 value: "hi", 8316 label: "Hindi", 8317 }, 8318 { value: "hu", label: "Hungarian" }, 8319 { value: "id", label: "Indonesian" }, 8320 { 8321 value: "it", 8322 label: "Italian", 8323 }, 8324 { value: "ja", label: "Japanese" }, 8325 { value: "kn", label: "Kannada" }, 8326 { 8327 value: "kk", 8328 label: "Kazakh", 8329 }, 8330 { value: "ko", label: "Korean" }, 8331 { value: "ky", label: "Kyrgyz" }, 8332 { 8333 value: "lt", 8334 label: "Lithuanian", 8335 }, 8336 { value: "lv", label: "Latvian" }, 8337 { value: "mk", label: "Macedonian" }, 8338 { 8339 value: "ml", 8340 label: "Malayalam", 8341 }, 8342 { value: "mr", label: "Marathi" },
8343 { value: "no", label: "Norwegian" }, 8344 { 8345 value: "pl", 8346 label: "Polish", 8347 }, 8348 { value: "pt", label: "Portuguese" }, 8349 { 8350 value: "pt-br", 8351 label: "Portuguese (brazil)", 8352 }, 8353 { value: "pt-pt", label: "Portuguese (portugal)" }, 8354 { 8355 value: "pa", 8356 label: "Punjabi", 8357 }, 8358 { value: "ro", label: "Romanian" }, 8359 { value: "ru", label: "Russian" }, 8360 { 8361 value: "sr", 8362 label: "Serbian", 8363 }, 8364 { value: "sk", label: "Slovak" }, 8365 { value: "sl", label: "Slovenian" }, 8366 { 8367 value: "es", 8368 label: "Spanish", 8369 }, 8370 { value: "sv", label: "Swedish" }, 8371 { value: "tl", label: "Tagalog" }, 8372 { 8373 value: "ta", 8374 label: "Tamil", 8375 }, 8376 { value: "te", label: "Telugu" }, 8377 { value: "th", label: "Thai" }, 8378 { 8379 value: "tr", 8380 label: "Turkish", 8381 }, 8382 { value: "uk", label: "Ukrainian" }, 8383 { value: "uz", label: "Uzbek" }, 8384 { 8385 value: "vi", 8386 label: "Vietnamese", 8387 }, 8388 ]; 8389 this.language = options.language; 8390 this.markerImages = MapSVG.markerImages; 8391 this.markersByField = options.markersByField; 8392 this.markerField = options.markerField; 8393 this.markersByFieldEnabled = MapSVG.parseBoolean(options.markersByFieldEnabled); 8394 this.defaultMarkerPath = 8395 options.defaultMarkerPath || 8396 this.formBuilder.mapsvg.getData().options.defaultMarkerImage; 8397 this.templates.marker = Handlebars.compile($$i("#mapsvg-data-tmpl-marker").html()); 8398 } 8399 init() { 8400 super.init(); 8401 if (this.value) { 8402 this.renderMarker(); 8403 } 8404 this.renderMarkerSelector(); 8405 } 8406 getSchema() { 8407 const schema = super.getSchema(); 8408 schema.language = this.language; 8409 schema.defaultMarkerPath = this.defaultMarkerPath; 8410 schema.markersByField = this.markersByField; 8411 schema.markerField = this.markerField; 8412 schema.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8413 return schema; 8414 } 8415 getData() { 8416 return { name: this.name, value: this.value }; 8417 } 8418 getDataForTemplate() { 8419 const data = super.getDataForTemplate(); 8420 if (this.formBuilder.admin) { 8421 data.languages = this.languages; 8422 data.markerImages = MapSVG.markerImages; 8423 data.markersByField = this.markersByField; 8424 data.markerField = this.markerField; 8425 data.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8426 const _this = this; 8427 data.markerImages.forEach(function (m) { 8428 if (m.relativeUrl === _this.defaultMarkerPath) { 8429 m.default = true; 8430 } 8431 else { 8432 m.default = false;
8433 } 8434 }); 8435 } 8436 data.language = this.language; 8437 if (this.value) { 8438 data.location = this.value; 8439 if (data.location.marker) { 8440 data.location.img = 8441 (this.value.marker.src.indexOf(MapSVG.urls.uploads) === 0 ? "uploads/" : "") + 8442 this.value.marker.src.split("/").pop(); 8443 } 8444 } 8445 data.showUploadBtn = data.external.filtersMode; 8446 return data; 8447 } 8448 initEditor() { 8449 super.initEditor(); 8450 this.renderMarkerSelector(); 8451 this.fillMarkersByFieldOptions(this.markerField); 8452 } 8453 setDomElements() { 8454 super.setDomElements(); 8455 this.domElements.markerImageButton = $$i(this.domElements.main).find("img")[0]; 8456 } 8457 setEventHandlers() { 8458 super.setEventHandlers(); 8459 const _this = this; 8460 const server = new Server(); 8461 if (_this.formBuilder.mapsvg.isGeo()) { 8462 const locations = new Bloodhound({ 8463 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 8464 queryTokenizer: Bloodhound.tokenizers.whitespace, 8465 remote: { 8466 url: server.getUrl("geocoding") + "?address=%QUERY%&language=" + this.language, 8467 wildcard: "%QUERY%", 8468 transform: function (response) { 8469 if (response.error_message) { 8470 alert(response.error_message); 8471 } 8472 return response.results; 8473 }, 8474 rateLimitWait: 600, 8475 }, 8476 }); 8477 const thContainer = $$i(this.domElements.main).find(".typeahead"); 8478 const tH = thContainer 8479 .typeahead({ minLength: 3 }, { 8480 name: "mapsvg-addresses", 8481 display: "formatted_address", 8482 async: true, 8483 source: (query, sync, async) => { 8484 const preg = new RegExp(/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/); 8485 if (preg.test(query)) { 8486 const latlng = query.split(",").map((item) => item.trim()); 8487 const item = { 8488 formatted_address: latlng.join(","), 8489 address_components: [], 8490 geometry: { 8491 location: { 8492 lat: () => latlng[0], 8493 lng: () => latlng[1], 8494 }, 8495 }, 8496 }; 8497 sync([item]); 8498 return; 8499 } 8500 MapSVG.geocode({ address: query }, async); 8501 }, 8502 }) 8503 .on("typeahead:asyncrequest", function (e) { 8504 $$i(e.target).addClass("tt-loading"); 8505 }) 8506 .on("typeahead:asynccancel typeahead:asyncreceive", function (e) { 8507 $$i(e.target).removeClass("tt-loading"); 8508 }); 8509 thContainer.on("typeahead:select", (ev, item) => { 8510 this.setValue(null, false); 8511 const address = {}; 8512 address.formatted = item.formatted_address; 8513 item.address_components.forEach((addr_item) => { 8514 const type = addr_item.types[0]; 8515 address[type] = addr_item.long_name; 8516 if (addr_item.short_name != addr_item.long_name) { 8517 address[type + "_short"] = addr_item.short_name; 8518 } 8519 }); 8520 const locationData = { 8521 address: address, 8522 geoPoint: new GeoPoint(item.geometry.location.lat(), item.geometry.location.lng()), 8523 img: this.getMarkerImage(this.formBuilder.getData()), 8524 imagePath: this.getMarkerImage(this.formBuilder.getData()), 8525 }; 8526 this.setValue(locationData, false); 8527 thContainer.typeahead("val", ""); 8528 this.triggerChanged(); 8529 }); 8530 } 8531 $$i(this.domElements.main).on("change", ".marker-file-uploader", function () { 8532 _this.markerIconUpload(this); 8533 }); 8534 $$i(this.domElements.main).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8535 e.preventDefault(); 8536 $$i(this).toggleClass("active"); 8537 _this.toggleMarkerSelector(); 8538 }); 8539 $$i(this.domElements.main).on("click", ".mapsvg-marker-delete", function (e) { 8540 e.preventDefault(); 8541 _this.setValue(null); 8542 _this.triggerChanged(); 8543 }); 8544 } 8545 setEditorEventHandlers() { 8546 super.setEditorEventHandlers(); 8547 const _this = this; 8548 $$i(this.domElements.edit).on("change", ".marker-file-uploader", function () { 8549 _this.markerIconUpload(this); 8550 }); 8551 $$i(this.domElements.edit).on("change", 'select[name="markerField"]', function () { 8552 const fieldName = $$i(this).val(); 8553 _this.resetMarkersByField(); 8554 const newOptions = _this.fillMarkersByFieldOptions(fieldName); 8555 _this.setMarkersByField(newOptions); 8556 }); 8557 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-selector button", function (e) { 8558 e.preventDefault(); 8559 const src = $$i(this).find("img").attr("src"); 8560 $$i(this).parent().find("button").removeClass("active"); 8561 $$i(this).addClass("active"); 8562 _this.setDefaultMarkerPath(src); 8563 }); 8564 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8565 $$i(this).toggleClass("active"); 8566 _this.toggleMarkerSelectorInLocationEditor.call(_this, $$i(this), e); 8567 }); 8568 } 8569 markerIconUpload(input) { 8570 const uploadBtn = $$i(input).closest(".btn-file").buttonLoading(true); 8571 for (let i = 0; i < input.files.length; i++) { 8572 const data = new FormData(); 8573 data.append("file", input.files[0]); 8574 const server = new Server(); 8575 server 8576 .ajax("markers", { 8577 type: "POST", 8578 data: data, 8579 processData: false, 8580 contentType: false, 8581 }) 8582 .done((resp) => { 8583 if (resp.error) { 8584 alert(resp.error); 8585 } 8586 else { 8587 const marker = resp.marker; 8588 const newMarker = ` 8589 <button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose active"> 8590 <img src="${marker.relativeUrl}" /> 8591 </button> 8592 </button> 8593 `; 8594 $$i(this.domElements.markerSelector) 8595 .find(".mapsvg-marker-image-btn.active") 8596 .removeClass("active"); 8597 $$i(newMarker).appendTo(this.domElements.markerSelector); 8598 this.setMarkerImage(marker.relativeUrl); 8599 MapSVG.markerImages.push(marker); 8600 } 8601 }) 8602 .always(function () { 8603 uploadBtn.buttonLoading(false); 8604 }); 8605 } 8606 } 8607 mayBeAddDistanceRow() { 8608 const _this = this; 8609 if (!this.domElements.editDistanceRow) { 8610 this.domElements.editDistanceRow = $$i($$i("#mapsvg-edit-distance-row").html())[0]; 8611 } 8612 const z = $$i(this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 8613 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 8614 const newRow = $$i(this.templates.editDistanceRow).clone(); 8615 newRow.insertAfter($$i(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 8616 } 8617 const rows = $$i(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 8618 const row1 = rows.eq(rows.length - 2); 8619 const row2 = rows.eq(rows.length - 1); 8620 if (row1.length && 8621 row2.length && 8622 !row1.find("input:eq(0)").val().toString().trim() && 8623 !row2.find("input:eq(0)").val().toString().trim()) { 8624 row2.remove(); 8625 } 8626 } 8627 fillMarkersByFieldOptions(fieldName) { 8628 const _this = this; 8629 const field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 8630 const options = {}; 8631 if (field) { 8632 const markerImg = _this.formBuilder.mapsvg.options.defaultMarkerImage; 8633 const rows = []; 8634 field.options.forEach(function (option) { 8635 const value = field.type === "region" ? option.id : option.value; 8636 const label = field.type === "region" ? option.title || option.id : option.label; 8637 const img = _this.markersByField && _this.markersByField[value] 8638 ? _this.markersByField[value] 8639 : markerImg; 8640 rows.push('<tr data-option-id="' + 8641 value + 8642 '"><td>' + 8643 label + 8644 '</td><td><button class="btn dropdown-toggle btn-outline-secondary mapsvg-marker-image-btn-trigger mapsvg-marker-image-btn"><img src="' + 8645 img + 8646 '" class="new-marker-img" /><span class="caret"></span></button></td></tr>'); 8647 options[value] = img; 8648 }); 8649 $$i("#markers-by-field").empty().append(rows); 8650 } 8651 return options; 8652 } 8653 renderMarker(marker) { 8654 if (marker && marker.location) { 8655 this.value = marker.location.getData(); 8656 } 8657 this.renderMarkerHtml(); 8658 } 8659 renderMarkerHtml() { 8660 if (!this.value) { 8661 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8662 } 8663 else { 8664 $$i(this.domElements.main) 8665 .find(".mapsvg-new-marker") 8666 .show() 8667 .html(this.templates.marker(this.value)); 8668 } 8669 } 8670 toggleMarkerSelector() { 8671 if (this.domElements.markerSelectorWrap && 8672 $$i(this.domElements.markerSelectorWrap).is(":visible")) { 8673 $$i(this.domElements.markerSelectorWrap).hide(); 8674 return; 8675 } 8676 if (this.domElements.markerSelectorWrap && 8677 $$i(this.domElements.markerSelectorWrap).not(":visible")) { 8678 $$i(this.domElements.markerSelector).find(".active").removeClass("active"); 8679 if (this.value && this.value.markerImagePath) { 8680 $$i(this.domElements.markerSelector) 8681 .find('[src="' + this.value.markerImagePath + '"]') 8682 .parent() 8683 .addClass("active"); 8684 } 8685 $$i(this.domElements.markerSelectorWrap).show(); 8686 return; 8687 } 8688 } 8689 renderMarkerSelector() { 8690 const _this = this; 8691 const view = this.formBuilder.editMode ? this.domElements.edit : this.domElements.main; 8692 if (!view) 8693 return; 8694 const currentImage = this.value ? this.value.markerImagePath : null; 8695 const images = MapSVG.markerImages.map(function (image) { 8696 return ('<button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose ' + 8697 (currentImage == image.relativeUrl ? "active" : "") + 8698 '"><img src="' + 8699 image.relativeUrl + 8700 '" /></button>'); 8701 }); 8702 this.domElements.markerSelectorWrap = $$i(view).find(".mapsvg-marker-image-selector")[0]; 8703 this.domElements.markerSelector = $$i(this.domElements.markerSelectorWrap).find(".mapsvg-marker-images")[0]; 8704 if (this.domElements.markerSelector) { 8705 $$i(this.domElements.markerSelector).empty(); 8706 } 8707 if (!this.formBuilder.editMode) { 8708 this.domElements.markerSelectorWrap.style.display = "none"; 8709 $$i(this.domElements.markerSelector).on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8710 e.preventDefault(); 8711 const src = $$i(this).find("img").attr("src"); 8712 $$i(_this.domElements.markerSelectorWrap).hide(); 8713 $$i(_this.domElements.markerSelector).find(".active").removeClass("active"); 8714 $$i(this).addClass("active"); 8715 $$i(_this.domElements.main) 8716 .find(".mapsvg-marker-image-btn-trigger") 8717 .toggleClass("active", false); 8718 $$i(_this.domElements.markerImageButton).attr("src", src); 8719 _this.setMarkerImage(src); 8720 }); 8721 } 8722 $$i(this.domElements.markerSelector).html(images.join("")); 8723 } 8724 setMarkerImage(src) { 8725 this.setDefaultMarkerPath(src); 8726 const value = this.value; 8727 if (value) { 8728 value.img = src; 8729 value.imagePath = src; 8730 this.setValue(value); 8731 this.triggerChanged(); 8732 this.renderMarker(); 8733 } 8734 } 8735 toggleMarkerSelectorInLocationEditor(jQueryObj, e) { 8736 e.preventDefault(); 8737 const _this = this; 8738 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").is(":visible")) { 8739 jQueryObj.data("markerSelector").hide(); 8740 return; 8741 } 8742 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").not(":visible")) { 8743 jQueryObj.data("markerSelector").show(); 8744 return; 8745 } 8746 const markerBtn = $$i(this).closest("td").find(".mapsvg-marker-image-btn-trigger"); 8747 const currentImage = markerBtn.attr("src"); 8748 const images = MapSVG.markerImages.map(function (image) { 8749 return ('<button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose ' + 8750 (currentImage == image.relativeUrl ? "active" : "") + 8751 '"><img src="' + 8752 image.relativeUrl + 8753 '" /></button>'); 8754 }); 8755 if (!jQueryObj.data("markerSelector")) { 8756 const ms = $$i('<div class="mapsvg-marker-image-selector"></div>'); 8757 jQueryObj.closest("td").append(ms); 8758 jQueryObj.data("markerSelector", ms); 8759 } 8760 else { 8761 jQueryObj.data("markerSelector").empty(); 8762 } 8763 jQueryObj.data("markerSelector").html(images.join("")); 8764 jQueryObj 8765 .data("markerSelector") 8766 .on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8767 e.preventDefault(); 8768 const src = $$i(this).find("img").attr("src"); 8769 jQueryObj.data("markerSelector").hide(); 8770 const td = $$i(this).closest("td"); 8771
8771 const fieldId = $$i(this).closest("tr").data("option-id"); 8772 const btn = td.find(".mapsvg-marker-image-btn-trigger"); 8773 btn.toggleClass("active", false); 8774 btn.find("img").attr("src", src); 8775 _this.setMarkerByField(fieldId, src); 8776 }); 8777 } 8778 setMarkersByField(options) { 8779 this.markersByField = options; 8780 } 8781 resetMarkersByField() { 8782 this.markersByField = {}; 8783 } 8784 setMarkerByField(fieldId, markerImg) { 8785 this.markersByField = this.markersByField || {}; 8786 this.markersByField[fieldId] = markerImg; 8787 } 8788 deleteMarker() { 8789 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8790 $$i(this.domElements.main).find(".mapsvg-marker-id").attr("disabled", "disabled"); 8791 } 8792 destroy() { 8793 if ($$i().mselect2) { 8794 const sel = $$i(this.domElements.main).find(".mapsvg-select2"); 8795 if (sel.length) { 8796 sel.mselect2("destroy"); 8797 } 8798 } 8799 this.domElements.markerSelector && $$i(this.domElements.markerSelector).popover("dispose"); 8800 } 8801 setDefaultMarkerPath(path) { 8802 this.defaultMarkerPath = path; 8803 this.formBuilder.mapsvg.setDefaultMarkerImage(path); 8804 } 8805 getMarkerImage(data) { 8806 let fieldValue; 8807 if (this.markersByFieldEnabled) { 8808 fieldValue = data[this.markerField]; 8809 if (!fieldValue) { 8810 return this.defaultMarkerPath || MapSVG.defaultMarkerImage; 8811 } 8812 else { 8813 if (this.markerField === "regions") { 8814 fieldValue = fieldValue[0] && fieldValue[0].id; 8815 } 8816 else if (typeof fieldValue === "object" && fieldValue.length) { 8817 fieldValue = fieldValue[0].value; 8818 } 8819 if (this.markersByField[fieldValue]) { 8820 return (this.markersByField[fieldValue] || 8821 this.defaultMarkerPath || 8822 MapSVG.defaultMarkerImage); 8823 } 8824 } 8825 } 8826 else { 8827 return this.defaultMarkerPath || MapSVG.defaultMarkerImage; 8828 } 8829 } 8830 setValue(value, updateInput = true) { 8831 this.value = value; 8832 if (this.value) { 8833 if (!this.value.address) { 8834 this.value.address = {}; 8835 } 8836 if (Object.keys(this.value.address).length < 2 && this.value.geoPoint) { 8837 this.value.address.formatted = 8838 this.value.geoPoint.lat + "," + this.value.geoPoint.lng; 8839 } 8840 } 8841 this.renderMarker(); 8842 } 8843 } 8844 8845 const $$j = jQuery; 8846 class ModalFormElement extends FormElement { 8847 constructor(options, formBuilder, external) { 8848 super(options, formBuilder, external); 8849 this.showButtonText = options.showButtonText; 8850 } 8851 getSchema() { 8852 const schema = super.getSchema(); 8853 schema.showButtonText = this.showButtonText; 8854 return schema; 8855 } 8856 } 8857 8858 const $$k = jQuery; 8859 class PostFormElement extends FormElement { 8860 constructor(options, formBuilder, external) { 8861 super(options, formBuilder, external); 8862 if (this.formBuilder.admin) 8863 this.post_types = this.formBuilder.admin.getPostTypes(); 8864 this.post_type = options.post_type || this.post_types[0]; 8865 this.add_fields = MapSVG.parseBoolean(options.add_fields); 8866 this.db_type = "int(11)"; 8867 this.name = "post"; 8868 this.post = options.post; 8869 } 8870 setDomElements() { 8871 super.setDomElements(); 8872 this.inputs.postSelect = ($$k(this.domElements.main).find(".mapsvg-find-post")[0]); 8873 } 8874 getSchema() { 8875 const schema = super.getSchema(); 8876 schema.post_type = this.post_type; 8877 schema.add_fields = this.add_fields; 8878 return schema; 8879 } 8880 destroy() { 8881 if ($$k().mselect2) { 8882 const sel = $$k(this.domElements.main).find(".mapsvg-select2"); 8883 if (sel.length) { 8884 sel.mselect2("destroy"); 8885 } 8886 } 8887 } 8888 getDataForTemplate() { 8889 const data = super.getDataForTemplate(); 8890 if (this.formBuilder.admin) 8891 data.post_types = this.formBuilder.admin.getPostTypes(); 8892 data.post_type = this.post_type; 8893 data.post = this.post; 8894 data.add_fields = this.add_fields || 0; 8895 return data; 8896 } 8897 setEventHandlers() { 8898 super.setEventHandlers(); 8899 const server = new Server(); 8900 $$k(this.inputs.postSelect) 8901 .mselect2({ 8902 placeholder: "Search post by title", 8903 allowClear: true, 8904 disabled: this.readonly, 8905 ajax: { 8906 url: server.getUrl("posts"), 8907 dataType: "json", 8908 delay: 250, 8909 data: (params) => { 8910 return { 8911 filters: { post_type: this.post_type }, 8912 search: params.term, 8913 page: params.page, 8914 }; 8915 }, 8916 processResults: (data, params) => { 8917 params.page = params.page || 1; 8918 return { 8919 results: data.posts ? data.posts : [], 8920 pagination: { 8921 more: false, 8922 }, 8923 }; 8924 }, 8925 cache: true, 8926 }, 8927 escapeMarkup: (markup) => { 8928 return markup; 8929 }, 8930 minimumInputLength: 1, 8931 templateResult: this.formatRepo, 8932 templateSelection: this.formatRepoSelection, 8933 }) 8934 .on("select2:select", (e) => { 8935 const post = e.params.data; 8936 this.setValue(post); 8937 this.setInputValue(post); 8938 this.triggerChanged(); 8939 }) 8940 .on("change", (e) => { 8941 if (e.target.value === "") { 8942 $$k(this.domElements.main).find(".mapsvg-post-id").text(""); 8943 $$k(this.domElements.main).find(".mapsvg-post-url").text(""); 8944 this.setValue(null, false); 8945 this.triggerChanged(); 8946 } 8947 }); 8948 } 8949 formatRepo(repo) { 8950 if (repo.loading) { 8951 return repo.text; 8952 } 8953 else { 8954 return "<div class='select2-result-repository clearfix'>" + repo.post_title + "</div>"; 8955 } 8956 } 8957 formatRepoSelection(repo) { 8958 return repo.post_title || repo.text; 8959 } 8960 setValue(post, updateInput = true) { 8961 this.value = post; 8962 if (updateInput) { 8963 this.setInputValue(post); 8964 } 8965 } 8966 setInputValue(post) { 8967 $$k(this.domElements.main).find(".mapsvg-post-id").text(post.id); 8968 $$k(this.domElements.main).find(".mapsvg-post-url").text(post.url).attr("href", post.url); 8969 } 8970 } 8971 8972 const $$l = jQuery; 8973 class RadioFormElement extends FormElement { 8974 constructor(options, formBuilder, external) { 8975 super(options, formBuilder, external); 8976 this.setOptions(options.options); 8977 } 8978 setDomElements() { 8979 super.setDomElements(); 8980 this.inputs.radios = this.formBuilder.getForm().elements[this.name]; 8981 this.$radios = $$l(this.domElements.main).find('input[type="radio"]'); 8982 } 8983 setEventHandlers() { 8984 super.setEventHandlers(); 8985 this.$radios.on("change", (e) => { 8986 this.setValue(e.target.value, false); 8987 this.triggerChanged(); 8988 }); 8989 } 8990 setInputValue(value) { 8991 if (value === null) { 8992 this.$radios.prop("checked", false); 8993 } 8994 else { 8995 this.inputs.radios.value = value; 8996 } 8997 } 8998 } 8999 9000 const $$m = jQuery; 9001 class RegionsFormElement extends FormElement { 9002 constructor(options, formBuilder, external) { 9003 super(options, formBuilder, external); 9004 this.searchable = MapSVG.parseBoolean(options.searchable); 9005 this.options = this.formBuilder.getRegionsList(); 9006 this.label = options.label === undefined ? "Regions" : options.label;
9007 this.name = "regions"; 9008 this.db_type = "text"; 9009 if (typeof this.value === "undefined") { 9010 this.value = []; 9011 } 9012 this.regionsTableName = this.formBuilder.mapsvg.regionsRepository.getSchema().name; 9013 } 9014 setDomElements() { 9015 super.setDomElements(); 9016 this.inputs.select = $$m(this.domElements.main).find("select")[0]; 9017 } 9018 getData() { 9019 return { name: "regions", value: this.value }; 9020 } 9021 getSchema() { 9022 const schema = super.getSchema(); 9023 if (schema.multiselect) 9024 schema.db_type = "text"; 9025 const opts = $$m.extend(true, {}, { options: this.options }); 9026 schema.options = opts.options; 9027 schema.optionsDict = {}; 9028 schema.options.forEach(function (option) { 9029 schema.optionsDict[option.id] = option.title || option.id; 9030 }); 9031 return schema; 9032 } 9033 getDataForTemplate() { 9034 const data = super.getDataForTemplate(); 9035 data.regionsTableName = this.regionsTableName; 9036 data.regionsFromCurrentTable = this.getRegionsForCurrentTable(); 9037 return data; 9038 } 9039 getRegionsForCurrentTable() { 9040 return this.value 9041 ? this.value.filter((region) => region.tableName === this.regionsTableName) 9042 : []; 9043 } 9044 setEventHandlers() { 9045 super.setEventHandlers(); 9046 $$m(this.inputs.select).on("change", (e) => { 9047 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 9048 const selectedValues = selectedOptions.map((option) => option.value); 9049 this.setValue(selectedValues, false); 9050 this.triggerChanged(); 9051 }); 9052 } 9053 destroy() { 9054 if ($$m().mselect2) { 9055 const sel = $$m(this.domElements.main).find(".mapsvg-select2"); 9056 if (sel.length) { 9057 sel.mselect2("destroy"); 9058 } 9059 } 9060 } 9061 setValue(regionIds, updateInput = true) { 9062 const regionsFromOtherTables = this.value.filter((region) => region.tableName !== this.regionsTableName); 9063 const regions = []; 9064 regionIds.forEach((regionId) => { 9065 const region = this.formBuilder.mapsvg.getRegion(regionId); 9066 regions.push({ id: region.id, title: region.title, tableName: this.regionsTableName }); 9067 }); 9068 this.value = regions.concat(regionsFromOtherTables); 9069 if (updateInput) { 9070 this.setInputValue(regionIds); 9071 } 9072 } 9073 } 9074 9075 const $$n = jQuery; 9076 class SaveFormElement extends FormElement { 9077 constructor(options, formBuilder, external) { 9078 super(options, formBuilder, external); 9079 this.readonly = true; 9080 } 9081 setDomElements() { 9082 super.setDomElements(); 9083 this.inputs.btnSave = $$n(this.domElements.main).find(".btn-save")[0]; 9084 this.inputs.btnClose = $$n(this.domElements.main).find(".mapsvg-close")[0]; 9085 } 9086 setEventHandlers() { 9087 super.setEventHandlers(); 9088 $$n(this.inputs.btnSave).on("click", (e) => { 9089 e.preventDefault(); 9090 this.events.trigger("click.btn.save"); 9091 }); 9092 $$n(this.inputs.btnClose).on("click", (e) => { 9093 e.preventDefault(); 9094 this.events.trigger("click.btn.close"); 9095 }); 9096 } 9097 } 9098 9099 const $$o = jQuery; 9100 class SearchFormElement extends FormElement { 9101 constructor(options, formBuilder, external) { 9102 super(options, formBuilder, external); 9103 this.searchFallback = MapSVG.parseBoolean(options.searchFallback) || false; 9104 this.width = options.width || "100%"; 9105 this.name = "search"; 9106 } 9107 setDomElements() { 9108 super.setDomElements(); 9109 this.inputs.text = $$o(this.domElements.main).find("input")[0]; 9110 } 9111 setEventHandlers() { 9112 super.setEventHandlers(); 9113 $$o(this.inputs.text).on("change keyup paste", (e) => { 9114 this.setValue(e.target.value, false); 9115 this.triggerChanged(); 9116 }); 9117 } 9118 setInputValue(value) { 9119 this.inputs.text.value = value; 9120 } 9121 getSchema() { 9122 const schema = super.getSchema(); 9123 schema.searchFallback = MapSVG.parseBoolean(this.searchFallback); 9124 schema.placeholder = this.placeholder; 9125 schema.width = this.width; 9126 return schema; 9127 } 9128 } 9129 9130 const $$p = jQuery; 9131 class SelectFormElement extends FormElement { 9132 constructor(options, formBuilder, external) { 9133 super(options, formBuilder, external); 9134 this.searchable = MapSVG.parseBoolean(options.searchable); 9135 this.multiselect = MapSVG.parseBoolean(options.multiselect); 9136 this.optionsGrouped = options.optionsGrouped; 9137 this.db_type = this.multiselect ? "text" : "varchar(255)"; 9138 this.setOptions(options.options); 9139 } 9140 setDomElements() { 9141 super.setDomElements(); 9142 this.inputs.select = $$p(this.domElements.main).find("select")[0]; 9143 } 9144 getSchema() { 9145 const schema = super.getSchema(); 9146 schema.multiselect = MapSVG.parseBoolean(this.multiselect); 9147 if (schema.multiselect) 9148 schema.db_type = "text"; 9149 schema.optionsGrouped = this.optionsGrouped; 9150 const opts = $$p.extend(true, {}, { options: this.options }); 9151 schema.options = opts.options || []; 9152 schema.optionsDict = {}; 9153 schema.options.forEach(function (option) { 9154 schema.optionsDict[option.value] = option.label; 9155 }); 9156 return schema; 9157 } 9158 setEventHandlers() { 9159 super.setEventHandlers(); 9160 $$p(this.inputs.select).on("change", (e) => { 9161 if (this.multiselect) { 9162 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 9163 const selectedValues = selectedOptions.map((option) => { 9164 return { label: option.label, value: option.value }; 9165 }); 9166 this.setValue(selectedValues, false); 9167 this.triggerChanged(); 9168 } 9169 else { 9170 this.setValue(this.inputs.select.value, false); 9171 this.triggerChanged(); 9172 } 9173 }); 9174 } 9175 addSelect2() { 9176 if ($$p().mselect2) { 9177 const select2Options = {}; 9178 if (this.formBuilder.filtersMode && this.type == "select") { 9179 select2Options.placeholder = this.placeholder; 9180 if (!this.multiselect) { 9181 select2Options.allowClear = true; 9182 } 9183 } 9184 $$p(this.domElements.main) 9185 .find("select") 9186 .css({ width: "100%", display: "block" }) 9187 .mselect2(select2Options) 9188 .on("select2:focus", function () { 9189 $$p(this).mselect2("open"); 9190 }); 9191 $$p(this.domElements.main) 9192 .find(".select2-selection--multiple .select2-search__field") 9193 .css("width", "100%"); 9194 } 9195 } 9196 setOptions(options) { 9197 if (options) { 9198 this.options = []; 9199 this.optionsDict = {}; 9200 options.forEach((value, key) => { 9201 this.options.push(value); 9202 if (this.optionsGrouped) { 9203 value.options.forEach((value2, key2) => { 9204 this.optionsDict[value2.value] = value2; 9205 }); 9206 } 9207 else { 9208 this.optionsDict[key] = value; 9209 } 9210 }); 9211 return this.options; 9212 } 9213 else { 9214 return this.setOptions([ 9215 { label: "Option one", name: "option_one", value: 1 }, 9216 { label: "Option two", name: "option_two", value: 2 }, 9217 ]); 9218 } 9219 } 9220 setInputValue(value) { 9221 if (this.multiselect) { 9222 if (this.value) { 9223 $$p(this.inputs.select).val(this.value.map((el) => el.value)); 9224 } 9225 else { 9226 $$p(this.inputs.select).val([]); 9227 } 9228 } 9229 else { 9230 this.inputs.select.value = this.value; 9231 } 9232 $$p(this.inputs.select).trigger("change.select2"); 9233 } 9234 } 9235 9236 const $$q = jQuery; 9237 class StatusFormElement extends FormElement { 9238 constructor(options, formBuilder, external) { 9239 super(options, formBuilder, external); 9240 this.label = options.label || "Status"; 9241 this.name = "status"; 9242 this.setOptions(options.options); 9243 } 9244 setDomElements() { 9245 super.setDomElements(); 9246 this.inputs.select = $$q(this.domElements.main).find("select")[0]; 9247 if ($$q().colorpicker) { 9248 $$q(this.domElements.main) 9249 .find(".cpicker") 9250 .colorpicker() 9251 .on("changeColor.colorpicker", function (event) { 9252 const input = $$q(this).find("input"); 9253 if (input.val() == "") 9254 $$q(this).find("i").css({ "background-color": "" }); 9255 }); 9256 this.domElements.edit && 9257 $$q(this.domElements.edit) 9258 .find(".cpicker") 9259 .colorpicker() 9260 .on("changeColor.colorpicker", function (event) { 9261 const input = $$q(this).find("input"); 9262 if (input.val() == "") 9263 $$q(this).find("i").css({ "background-color": "" }); 9264 }); 9265 } 9266 } 9267 destroy() { 9268 if ($$q().mselect2) { 9269 const sel = $$q(this.domElements.main).find(".mapsvg-select2"); 9270 if (sel.length) { 9271 sel.mselect2("destroy"); 9272 } 9273 } 9274 } 9275 setEditorEventHandlers() { 9276 super.setEditorEventHandlers(); 9277 const _this = this; 9278 $$q(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-status-row input", function () { 9279 _this.mayBeAddStatusRow(); 9280 }); 9281 } 9282 initEditor() { 9283 super.initEditor(); 9284 const _this = this; 9285 $$q(_this.domElements.edit) 9286 .find(".cpicker") 9287 .colorpicker() 9288 .on("changeColor.colorpicker", function (event) { 9289 const input = $$q(this).find("input"); 9290 const index = $$q(this).closest("tr").index(); 9291 if (input.val() == "") 9292 $$q(this).find("i").css({ "background-color": "" }); 9293 _this.options[index] = _this.options[index] || { 9294 label: "", 9295 value: "", 9296 color: "", 9297 disabled: false, 9298 }; 9299 _this.options[index]["color"] = input.val(); 9300 }); 9301 _this.mayBeAddStatusRow(); 9302 } 9303 mayBeAddStatusRow() { 9304 const _this = this; 9305 const editStatusRow = $$q($$q("#mapsvg-edit-status-row").html()); 9306 const z = $$q(_this.domElements.edit).find(".mapsvg-edit-status-label:last-child"); 9307 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 9308 const newRow = editStatusRow.clone(); 9309 newRow.insertAfter($$q(_this.domElements.edit).find(".mapsvg-edit-status-row:last-child")); 9310 newRow 9311 .find(".cpicker") 9312 .colorpicker() 9313 .on("changeColor.colorpicker", function (event) { 9314 const input = $$q(this).find("input"); 9315 const index = $$q(this).closest("tr").index(); 9316 if (input.val() == "") 9317 $$q(this).find("i").css({ "background-color": "" }); 9318 _this.options[index] = _this.options[index] || { 9319 label: "", 9320 value: "", 9321 color: "", 9322 disabled: false, 9323 }; 9324 _this.options[index]["color"] = input.val(); 9325 }); 9326 } 9327 const rows = $$q(_this.domElements.edit).find(".mapsvg-edit-status-row"); 9328 const row1 = rows.eq(rows.length - 2); 9329 const row2 = rows.eq(rows.length - 1); 9330 if (row1.length && 9331 row2.length && 9332 !(row1.find("input:eq(0)").val().toString().trim() || 9333 row1.find("input:eq(1)").val().toString().trim() || 9334 row1.find("input:eq(2)").val().toString().trim()) && 9335 !(row2.find("input:eq(0)").val().toString().trim() || 9336 row2.find("input:eq(1)").val().toString().trim() || 9337 row2.find("input:eq(2)").val().toString().trim())) { 9338 row2.remove(); 9339 } 9340 } 9341 setEventHandlers() { 9342 super.setEventHandlers(); 9343 $$q(this.inputs.select).on("change keyup paste", (e) => { 9344 this.setValue(e.target.value, false); 9345 this.triggerChanged(); 9346 }); 9347 } 9348 getSchema() { 9349 const schema = super.getSchema(); 9350 const opts = $$q.extend(true, {}, { options: this.options }); 9351 schema.options = opts.options; 9352 schema.optionsDict = {}; 9353 schema.options.forEach(function (option, index) { 9354 if (schema.options[index].value === "") { 9355 schema.options.splice(index, 1); 9356 } 9357 else { 9358 schema.options[index].disabled = MapSVG.parseBoolean(schema.options[index].disabled); 9359 schema.optionsDict[option.value] = option; 9360 } 9361 }); 9362 return schema; 9363 } 9364 setInputValue(value) { 9365 this.inputs.select.value = value; 9366 } 9367 } 9368 9369 const $$r = jQuery; 9370 class TextareaFormElement extends FormElement { 9371 constructor(options, formBuilder, external) { 9372 super(options, formBuilder, external); 9373 this.searchType = options.searchType || "fulltext"; 9374 this.searchable = MapSVG.parseBoolean(options.searchable); 9375 this.autobr = options.autobr; 9376 this.html = options.html; 9377 this.db_type = "text"; 9378 } 9379 setDomElements() { 9380 super.setDomElements(); 9381 this.inputs.textarea = $$r(this.domElements.main).find("textarea")[0]; 9382 if (this.html) { 9383 this.editor = CodeMirror.fromTextArea(this.inputs.textarea, { 9384 mode: { name: "handlebars", base: "text/html" }, 9385 matchBrackets: true, 9386 lineNumbers: true, 9387 }); 9388 if (this.formBuilder.admin) { 9389 this.editor.on("change", this.setTextareaValue); 9390 } 9391 } 9392 } 9393 setEventHandlers() { 9394 super.setEventHandlers(); 9395 $$r(this.inputs.textarea).on("change keyup paste", (e) => { 9396 this.setValue(e.target.value, false); 9397 this.triggerChanged(); 9398 }); 9399 } 9400 getSchema() { 9401 const schema = super.getSchema(); 9402 schema.autobr = this.autobr; 9403 schema.html = this.html; 9404 return schema; 9405 } 9406 getDataForTemplate() { 9407 const data = super.getDataForTemplate(); 9408 data.html = this.html; 9409 return data; 9410 } 9411 setTextareaValue(codemir
9411ror, changeobj) { 9412 const handler = codemirror.getValue(); 9413 const textarea = $$r(codemirror.getTextArea()); 9414 textarea.val(handler).trigger("change"); 9415 } 9416 destroy() { 9417 const cm = $$r(this.domElements.main).find(".CodeMirror"); 9418 if (cm.length) { 9419 cm.empty().remove(); 9420 } 9421 } 9422 } 9423 9424 const $$s = jQuery; 9425 class TextFormElement extends FormElement { 9426 constructor(options, formBuilder, external) { 9427 super(options, formBuilder, external); 9428 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9429 this.searchType = options.searchType; 9430 this.width = 9431 this.formBuilder.filtersHide && !this.formBuilder.modal 9432 ? null 9433 : options.width || "100%"; 9434 this.db_type = "varchar(255)"; 9435 } 9436 setDomElements() { 9437 super.setDomElements(); 9438 this.inputs.text = $$s(this.domElements.main).find('input[type="text"]')[0]; 9439 } 9440 getSchema() { 9441 const schema = super.getSchema(); 9442 schema.searchType = this.searchType; 9443 return schema; 9444 } 9445 setEventHandlers() { 9446 super.setEventHandlers(); 9447 $$s(this.inputs.text).on("change keyup paste", (e) => { 9448 this.setValue(e.target.value, false); 9449 this.triggerChanged(); 9450 }); 9451 } 9452 setInputValue(value) { 9453 this.inputs.text.value = value; 9454 } 9455 } 9456 9457 const $$t = jQuery; 9458 class TitleFormElement extends FormElement { 9459 constructor(options, formBuilder, external) { 9460 super(options, formBuilder, external); 9461 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9462 this.width = 9463 this.formBuilder.filtersHide && !this.formBuilder.modal 9464 ? null 9465 : options.width || "100%"; 9466 this.db_type = "varchar(255)"; 9467 } 9468 setDomElements() { 9469 super.setDomElements(); 9470 this.inputs.text = $$t(this.domElements.main).find('input[type="text"]')[0]; 9471 } 9472 getSchema() { 9473 const schema = super.getSchema(); 9474 schema.searchType = this.searchType; 9475 return schema; 9476 } 9477 setEventHandlers() { 9478 super.setEventHandlers(); 9479 $$t(this.inputs.text).on("change keyup paste", (e) => { 9480 this.setValue(e.target.value, false); 9481 this.triggerChanged(); 9482 }); 9483 } 9484 setInputValue(value) { 9485 this.inputs.text.value = value; 9486 } 9487 } 9488 9489 const $$u = jQuery; 9490 class ColorPickerFormElement extends FormElement { 9491 constructor(options, formBuilder, external) { 9492 super(options, formBuilder, external); 9493 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9494 this.width = 9495 this.formBuilder.filtersHide && !this.formBuilder.modal 9496 ? null 9497 : options.width || "100%"; 9498 this.db_type = "varchar(255)"; 9499 } 9500 setDomElements() { 9501 super.setDomElements(); 9502 this.inputs.text = $$u(this.domElements.main).find("input.cpicker")[0]; 9503 $$u(this.domElements.main).find(".colorpicker-element").colorpicker(); 9504 } 9505 getSchema() { 9506 const schema = super.getSchema(); 9507 schema.searchType = this.searchType; 9508 return schema; 9509 } 9510 setEventHandlers() { 9511 super.setEventHandlers(); 9512 $$u(this.inputs.text).on("change keyup paste", (e) => { 9513 this.setValue(e.target.value, false); 9514 this.triggerChanged(); 9515 }); 9516 $$u(this.domElements.main).find(".colorpicker-element").colorpicker().on("changeColor.colorpicker", (e) => { 9517 this.setValue(this.inputs.text.value, false); 9518 this.triggerChanged(); 9519 }); 9520 } 9521 setInputValue(value) { 9522 this.inputs.text.value = value; 9523 } 9524 } 9525 9526 const $$v = jQuery; 9527 class FormElementFactory { 9528 constructor(options) { 9529 this.mapsvg = options.mapsvg; 9530 this.editMode = options.editMode; 9531 this.filtersMode = options.filtersMode; 9532 this.namespace = options.namespace; 9533 this.mediaUploader = options.mediaUploader; 9534 this.formBuilder = options.formBuilder; 9535 this.showNames = options.showNames !== false; 9536 } 9537 create(options) { 9538 const types = { 9539 checkbox: CheckboxFormElement, 9540 checkboxes: CheckboxesFormElement, 9541 date: DateFormElement, 9542 distance: DistanceFormElement, 9543 empty: EmptyFormElement, 9544 id: IdFormElement, 9545 image: ImagesFormElement, 9546 location: LocationFormElement, 9547 modal: ModalFormElement, 9548 post: PostFormElement, 9549 radio: RadioFormElement, 9550 region: RegionsFormElement, 9551 save: SaveFormElement, 9552 search: SearchFormElement, 9553 select: SelectFormElement, 9554 status: StatusFormElement, 9555 text: TextFormElement, 9556 textarea: TextareaFormElement, 9557 title: TitleFormElement, 9558 colorpicker: ColorPickerFormElement, 9559 }; 9560 const formElement = new types[options.type](options, this.formBuilder, this.getExtraParams()); 9561 formElement.init(); 9562 return formElement; 9563 } 9564 getExtraParams() { 9565 const databaseFields = []; 9566 const databaseFieldsFilterable = []; 9567 const databaseFieldsFilterableShort = []; 9568 const regionFields = []; 9569 const regionFieldsFilterable = []; 9570 const regions = new ArrayIndexed("id"); 9571 let mapIsGeo = false;
9572 if (this.mapsvg) { 9573 mapIsGeo = this.mapsvg.isGeo(); 9574 const schemaObjects = this.mapsvg.objectsRepository.getSchema(); 9575 if (schemaObjects) { 9576 schemaObjects.getFields().forEach(function (obj) { 9577 if (obj.type == "text" || 9578 obj.type == "region" || 9579 obj.type == "textarea" || 9580 obj.type == "post" || 9581 obj.type == "select" || 9582 obj.type == "radio" || 9583 obj.type == "checkbox") { 9584 if (obj.type == "post") { 9585 databaseFields.push("Object.post.post_title"); 9586 } 9587 else { 9588 databaseFields.push("Object." + obj.name); 9589 } 9590 } 9591 if (obj.type == "region" || obj.type == "select" || obj.type == "radio") { 9592 databaseFieldsFilterable.push("Object." + obj.name); 9593 databaseFieldsFilterableShort.push(obj.name); 9594 } 9595 }); 9596 } 9597 const schemaRegions = this.mapsvg.regionsRepository.getSchema(); 9598 if (schemaRegions) { 9599 schemaRegions.getFieldsAsArray().forEach(function (obj) { 9600 if (obj.type == "status" || 9601 obj.type == "text" || 9602 obj.type == "textarea" || 9603 obj.type == "post" || 9604 obj.type == "select" || 9605 obj.type == "radio" || 9606 obj.type == "checkbox") { 9607 if (obj.type == "post") { 9608 regionFields.push("Region.post.post_title"); 9609 } 9610 else { 9611 regionFields.push("Region." + obj.name); 9612 } 9613 } 9614 if (obj.type == "status" || obj.type == "select" || obj.type == "radio") { 9615 regionFieldsFilterable.push("Region." + obj.name); 9616 } 9617 }); 9618 } 9619 this.mapsvg.regions.forEach((region) => { 9620 regions.push({ id: region.id, title: region.title }); 9621 }); 9622 } 9623 return { 9624 databaseFields: databaseFields, 9625 databaseFieldsFilterable: databaseFieldsFilterable, 9626 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 9627 regionFields: regionFields, 9628 regionFieldsFilterable: regionFieldsFilterable, 9629 regions: regions, 9630 mapIsGeo: mapIsGeo, 9631 mediaUploader: this.mediaUploader, 9632 filtersMode: this.filtersMode, 9633 showNames: this.showNames, 9634 }; 9635 } 9636 } 9637 9638 const $$w = jQuery; 9639 class FormBuilder { 9640 constructor(options) { 9641 const _this = this; 9642 this.events = new Events(); 9643 this.container = options.container; 9644 this.namespace = options.namespace; 9645 this.mediaUploader = options.mediaUploader; 9646 this.schema = options.schema || []; 9647 this.editMode = options.editMode == undefined ? false : options.editMode; 9648 this.filtersMode = options.filtersMode == undefined ? false : options.filtersMode; 9649 this.filtersHide = options.filtersHide == undefined ? false : options.filtersHide; 9650 this.modal = options.modal == undefined ? false : options.modal; 9651 this.admin = options.admin; 9652 this.mapsvg = options.mapsvg; 9653 this.data = options.data || {}; 9654 this.clearButton = options.clearButton || false; 9655 this.clearButtonText = options.clearButtonText || ""; 9656 this.searchButton = options.searchButton || false; 9657 this.searchButtonText = options.searchButtonText || ""; 9658 this.showButtonText = options.showButtonText || ""; 9659 this.scrollable = 9660 typeof options.scrollable !== "undefined" 9661 ? options.scrollable 9662 : !_this.editMode && !_this.filtersMode; 9663 this.showNames = typeof options.showNames !== "undefined" ? options.showNames : true; 9664 this.formElementFactory = new FormElementFactory({ 9665 mapsvg: this.mapsvg, 9666 formBuilder: this, 9667 mediaUploader: this.mediaUploader, 9668 editMode: this.editMode, 9669 filtersMode: this.filtersMode, 9670 namespace: this.namespace, 9671 showNames: this.showNames, 9672 }); 9673 this.events = new Events(this); 9674 if (options.events && Object.keys(options.events).length > 0) { 9675 for (const eventName in options.events) { 9676 this.events.on(eventName, options.events[eventName]); 9677 } 9678 } 9679 this.template = "form-builder"; 9680 this.closeOnSave = options.closeOnSave === true; 9681 this.newRecord = options.newRecord === true; 9682 this.types = options.types || [ 9683 "text", 9684 "textarea", 9685 "checkbox", 9686 "radio", 9687 "select", 9688 "image", 9689 "region", 9690 "location", 9691 "post", 9692 "date", 9693 ]; 9694 this.templates = {}; 9695 this.elements = {}; 9696 this.view = $$w("<div />").addClass("mapsvg-form-builder")[0]; 9697 if (this.editMode) 9698 $$w(this.view).addClass("full-flex"); 9699 if (!this.showNames) { 9700 $$w(this.view).addClass("hide-names"); 9701 } 9702 this.formElements = new ArrayIndexed("name"); 9703 if (!MapSVG.templatesLoaded[this.template]) { 9704 this.loadTemplates(() => this.init()); 9705 } 9706 else { 9707 this.init(); 9708 } 9709 } 9710 loadTemplates(callback) { 9711 $$w.get(MapSVG.urls.root + "dist/" + this.template + ".html", (data) => { 9712 $$w(data).appendTo("body");
9713 MapSVG.templatesLoaded[this.template] = true; 9714 Handlebars.registerPartial("dataMarkerPartial", $$w("#mapsvg-data-tmpl-marker").html()); 9715 if (this.editMode) { 9716 Handlebars.registerPartial("markerByFieldPartial", $$w("#mapsvg-markers-by-field-tmpl-partial").html()); 9717 } 9718 callback(); 9719 }); 9720 } 9721 init() { 9722 const _this = this; 9723 MapSVG.formBuilder = this; 9724 this.form = document.createElement("form"); 9725 this.form.className = "mapsvg-data-form-view"; 9726 if (!this.filtersMode) { 9727 this.form.classList.add("form-horizontal"); 9728 } 9729 if (this.editMode) { 9730 const template = document.getElementById("mapsvg-form-editor-tmpl-ui").innerHTML; 9731 const templateCompiled = Handlebars.compile(template); 9732 this.view.innerHTML = templateCompiled({ types: this.types }); 9733 this.view.classList.add("edit"); 9734 this.form.classList.add("mapsvg-data-flex-full"); 9735 this.form.classList.add("mapsvg-data-container"); 9736 $$w(this.view).find(".mapsvg-data-preview").prepend(this.form); 9737 this.formEditor = $$w(this.view).find("#mapsvg-data-form-edit")[0]; 9738 } 9739 else { 9740 this.view.appendChild(this.form); 9741 } 9742 _this.elements = { 9743 buttons: { 9744 text: $$w(_this.view).find("#mapsvg-data-btn-text")[0], 9745 textarea: $$w(_this.view).find("#mapsvg-data-btn-textarea")[0], 9746 checkbox: $$w(_this.view).find("#mapsvg-data-btn-checkbox")[0], 9747 radio: $$w(_this.view).find("#mapsvg-data-btn-radio")[0], 9748 select: $$w(_this.view).find("#mapsvg-data-btn-select")[0], 9749 image: $$w(_this.view).find("#mapsvg-data-btn-image")[0], 9750 region: $$w(_this.view).find("#mapsvg-data-btn-region")[0], 9751 marker: $$w(_this.view).find("#mapsvg-data-btn-marker")[0], 9752 saveSchema: $$w(_this.view).find("#mapsvg-data-btn-save-schema")[0], 9753 }, 9754 containers: { 9755 buttons_add: $$w(_this.view).find("#mapsvg-data-buttons-add")[0], 9756 }, 9757 }; 9758 _this.redraw(); 9759 } 9760 getForm() { 9761 return this.form; 9762 } 9763 getFormEditor() { 9764 return this.formEditor; 9765 } 9766 viewDidLoad() { } 9767 setEventHandlers() { 9768 const _this = this; 9769 $$w(this.getForm()).on("submit", (e) => { 9770 e.preventDefault(); 9771 }); 9772 if (this.filtersMode && this.clearButton) { 9773 $$w(this.elements.buttons.clearButton).on("click", (e) => { 9774 e.preventDefault(); 9775 this.clearAllFields(); 9776 }); 9777 } 9778 $$w(window) 9779 .off("keydown.form.mapsvg") 9780 .on("keydown.form.mapsvg", function (e) { 9781 if (MapSVG.formBuilder) { 9782 if ((e.metaKey || e.ctrlKey) && e.keyCode == 13) 9783 MapSVG.formBuilder.save(); 9784 else if (e.keyCode == 27) 9785 MapSVG.formBuilder.close(); 9786 } 9787 }); 9788 if (this.editMode) { 9789 $$w(this.view).on("click", "#mapsvg-data-buttons-add button", function (e) { 9790 e.preventDefault(); 9791 const type = $$w(this).data("create"); 9792 const formElement = _this.formElementFactory.create({ type: type }); 9793 _this.addField(formElement); 9794 }); 9795 $$w(this.view).on("click", "#mapsvg-data-btn-save-schema", function (e) { 9796 e.preventDefault(); 9797 const fields = _this.getSchema(); 9798 const counts = {}; 9799 _this.formElements.forEach(function (elem) { 9800 counts[elem.name] = (counts[elem.name] || 0) + 1; 9801 }); 9802 $$w(_this.getForm()).find(".form-group").removeClass("has-error"); 9803 const errors = []; 9804 const reservedFields = [ 9805 "lat", 9806 "lon", 9807 "lng", 9808 "location", 9809 "location_lat", 9810 "location_lon", 9811 "location_lng", 9812 "location_address", 9813 "location_img", 9814 "marker", 9815 "marker_id", 9816 "regions", 9817 "region_id", 9818 "post", 9819 "post_title", 9820 "post_url", 9821 "keywords", 9822 "status", 9823 ]; 9824 const reservedFieldsToTypes = { 9825 regions: "region", 9826 status: "status", 9827 post: "post", 9828 marker: "marker", 9829 location: "location", 9830 }; 9831 let errUnique, errEmpty;
9832 _this.formElements.forEach(function (formElement, index) { 9833 let err = false; 9834 if (!_this.filtersMode) { 9835 if (counts[formElement.name] > 1) { 9836 if (!errUnique) { 9837 errUnique = "Field names should be unique"; 9838 errors.push(errUnique); 9839 err = true; 9840 } 9841 } 9842 else if (formElement.name.length === 0) { 9843 if (!errEmpty) { 9844 errEmpty = "Field name can't be empty"; 9845 errors.push(errEmpty); 9846 err = true; 9847 } 9848 } 9849 else if (reservedFields.indexOf(formElement.name) != -1) { 9850 if (!reservedFieldsToTypes[formElement.name] || 9851 (reservedFieldsToTypes[formElement.name] && 9852 reservedFieldsToTypes[formElement.name] != formElement.type)) { 9853 const msg = 'Field name "' + 9854 formElement.name + 9855 '" is reserved, please set another name'; 9856 errors.push(msg); 9857 err = true; 9858 } 9859 } 9860 } 9861 if (formElement.options && 9862 formElement.type != "region" && 9863 formElement.type != "marker") { 9864 const vals = formElement.options.map(function (obj) { 9865 return obj.value; 9866 }); 9867 const uniq = [...Array.from(new Set(vals).values())]; 9868 if (vals.length != uniq.length) { 9869 errors.push('Check "Options" list - values should not repeat'); 9870 err = true; 9871 } 9872 } 9873 err && $$w(formElement.domElements.main).addClass("has-error"); 9874 }); 9875 if (errors.length === 0) { 9876 _this.events.trigger("saveSchema", _this, [_this, fields]); 9877 } 9878 else { 9879 jQuery.growl.error({ title: "Errors", message: errors.join("<br />") }); 9880 } 9881 }); 9882 setTimeout(function () { 9883 const el = _this.getForm(); 9884 _this.sortable = new Sortable(el, { 9885 animation: 150, 9886 onStart: function () { 9887 $$w(_this.getForm()).addClass("sorting"); 9888 }, 9889 onEnd: function () { 9890 setTimeout(function () { 9891 $$w(_this.getForm()).removeClass("sorting"); 9892 _this.formElements.clear(); 9893 $$w(el) 9894 .find(".form-group") 9895 .each(function (index, elem) { 9896 _this.formElements.push($$w(elem).data("formElement")); 9897 }); 9898 }, 500); 9899 }, 9900 }); 9901 }, 1000); 9902 } 9903 new ResizeSensor(this.view, function () { 9904 _this.scrollApi && _this.scrollApi.reinitialise(); 9905 }); 9906 } 9907 clearAllFields() { 9908 this.formElements.forEach((f) => f.setValue(null)); 9909 this.events.trigger("cleared"); 9910 } 9911 setFormElementEventHandlers(formElement) { 9912 if (this.editMode) { 9913 formElement.events.on("click", (elem) => { 9914 this.edit(elem); 9915 }); 9916 formElement.events.on("delete", (elem) => { 9917 this.deleteField(elem); 9918 }); 9919 } 9920 else { 9921 formElement.events.on("changed", (_formElement) => { 9922 const name = _formElement.name; 9923 const value = _formElement.getValue(); 9924 if (_formElement.type !== "search") { 9925 this.events.trigger("changed.field", _formElement, [_formElement, name, value]); 9926 } 9927 else { 9928 this.events.trigger("changed.search", _formElement, [_formElement, value]); 9929 } 9930 }); 9931 } 9932 } 9933 save() { 9934 const _this = this; 9935 if (_this.markerBackup) { 9936 const marker = _this.mapsvg.getEditingMarker(); 9937 marker.events.off("change"); 9938 _this.markerBackup = marker.getOptions(); 9939 _this.mapsvg.unsetEditingMarker(); 9940 } 9941 const data = _this.getData(); 9942 _this.saved = true; 9943 this.events.trigger("save", _this, [_this, data]); 9944 } 9945 getFormElementByType(type) { 9946 return this.formElements.find((el) => el.type === type); 9947 } 9948 getData() { 9949 const data = {};
9950 this.formElements.forEach((formElement) => { 9951 if (formElement.readonly === false || formElement.type === "id") { 9952 const _formElementData = formElement.getData(); 9953 data[_formElementData.name] = _formElementData.value; 9954 } 9955 }); 9956 return data; 9957 } 9958 reset() { 9959 this.formElements.forEach((formElement) => { 9960 formElement.setValue(null); 9961 }); 9962 } 9963 update(data) { 9964 this.schema.getFields().forEach((field) => { 9965 const formElement = this.formElements.get(field.name); 9966 if (formElement) { 9967 if (typeof data[field.name] !== "undefined") { 9968 if (formElement.getValue() !== data[field.name]) { 9969 formElement.setValue(data[field.name]); 9970 } 9971 } 9972 else { 9973 formElement.setValue(null); 9974 } 9975 } 9976 }); 9977 } 9978 redraw() { 9979 const _this = this; 9980 delete _this.markerBackup; 9981 $$w(this.container).empty(); 9982 $$w(this.getForm()).empty(); 9983 this.formElements.clear(); 9984 this.schema && 9985 this.schema.fields.length > 0 && 9986 this.schema.fields.forEach((fieldSettings) => { 9987 if (this.filtersMode) { 9988 if (fieldSettings.type == "distance") { 9989 fieldSettings.value = this.data.distance 9990 ? this.data.distance 9991 : fieldSettings.value !== undefined 9992 ? fieldSettings.value 9993 : null; 9994 } 9995 else { 9996 fieldSettings.value = this.data[fieldSettings.parameterNameShort]; 9997 } 9998 } 9999 else { 10000 fieldSettings.value = this.data 10001 ? this.data[fieldSettings.name] 10002 : fieldSettings.value !== undefined 10003 ? fieldSettings.value 10004 : null; 10005 } 10006 if (fieldSettings.type == "location" && !this.editMode) { 10007 if (fieldSettings.value && 10008 fieldSettings.value.marker && 10009 fieldSettings.value.marker.id) ; 10010 this.admin && this.admin.setMode && this.admin.setMode("editMarkers"); 10011 this.admin && this.admin.enableMarkersMode(true); 10012 } 10013 else if (fieldSettings.type == "post") { 10014 fieldSettings.post = this.data["post"]; 10015 } 10016 else if (fieldSettings.type === "region") { 10017 fieldSettings.options = new ArrayIndexed("id", this.getRegionsList()); 10018 } 10019 const formElement = this.formElementFactory.create(fieldSettings); 10020 if (this.filtersMode) { 10021 if (!this.filtersHide || 10022 (this.filtersHide && this.modal && fieldSettings.type !== "search") || 10023 (!this.modal && fieldSettings.type === "search")) { 10024 this.addField(formElement); 10025 } 10026 } 10027 else { 10028 this.addField(formElement); 10029 } 10030 }); 10031 if (!_this.editMode) { 10032 if (this.schema.fields.length === 0 && !this.filtersMode) { 10033 const formElement = this.formElementFactory.create({ type: "empty" }); 10034 _this.addField(formElement); 10035 } 10036 else { 10037 if (_this.admin && !_this.admin.isMetabox) { 10038 const formElement = this.formElementFactory.create({ type: "save" }); 10039 formElement.events.on("click.btn.save", () => { 10040 this.save(); 10041 }); 10042 formElement.events.on("click.btn.close", () => { 10043 this.close(); 10044 }); 10045 _this.addField(formElement); 10046 } 10047 } 10048 } 10049 if (_this.filtersMode && _this.filtersHide && !_this.modal) { 10050 const formElement = this.formElementFactory.create({ 10051 type: "modal", 10052 showButtonText: _this.showButtonText, 10053 });
10054 this.showFiltersButton = _this.addField(formElement); 10055 } 10056 if (this.scrollable) { 10057 const nano = $$w('<div class="nano"></div>'); 10058 const nanoContent = $$w('<div class="nano-content"></div>'); 10059 nano.append(nanoContent); 10060 nanoContent.append(this.view); 10061 $$w(_this.container).append(nano); 10062 nano.jScrollPane({ contentWidth: "0px", mouseWheelSpeed: 30 }); 10063 _this.scrollApi = nano.data("jsp"); 10064 } 10065 else { 10066 $$w(_this.container).append(this.view); 10067 } 10068 if (_this.filtersMode && _this.clearButton) { 10069 _this.elements.buttons.clearButton = $$w('<div class="form-group mapsvg-filters-reset-container">' + 10070 '<button type="button" class="btn btn-outline-secondary mapsvg-filters-reset">' + 10071 _this.clearButtonText + 10072 "</button></div>")[0]; 10073 $$w(this.getForm()).append(_this.elements.buttons.clearButton); 10074 } 10075 if (_this.filtersMode && _this.searchButton) { 10076 _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">' + 10077 _this.searchButtonText + 10078 "</button></div>")[0]; 10079 $$w(this.getForm()).append(_this.elements.buttons.searchButton); 10080 } 10081 if (!this.editMode && !_this.filtersMode) 10082 $$w(this.view).find("input:visible,textarea:visible").not(".tt-hint").first().focus(); 10083 const cm = $$w(this.container).find(".CodeMirror"); 10084 cm.each(function (index, el) { 10085 el && el.CodeMirror.refresh(); 10086 }); 10087 _this.setEventHandlers(); 10088 this.events.trigger("init", this, [this, this.getData()]); 10089 this.events.trigger("loaded", this, [this]); 10090 } 10091 updateExtraParamsInFormElements() { 10092 this.formElements.forEach((formElement) => { 10093 formElement.setExternal(this.formElementFactory.getExtraParams()); 10094 if (formElement.type === "location") { 10095 formElement.redraw(); 10096 } 10097 }); 10098 } 10099 deleteField(formElement) { 10100 const _this = this; 10101 _this.formElements.delete(formElement.name); 10102 } 10103 getExtraParams() { 10104 const databaseFields = []; 10105 this.mapsvg.objectsRepository 10106 .getSchema() 10107 .getFields() 10108 .forEach(function (obj) { 10109 if (obj.type == "text" || 10110 obj.type == "region" || 10111 obj.type == "textarea" || 10112 obj.type == "post" || 10113 obj.type == "select" || 10114 obj.type == "radio" || 10115 obj.type == "checkbox") { 10116 if (obj.type == "post") { 10117 databaseFields.push("Object.post.post_title"); 10118 } 10119 else { 10120 databaseFields.push("Object." + obj.name); 10121 } 10122 } 10123 }); 10124 let databaseFieldsFilterableShort = []; 10125 databaseFieldsFilterableShort = this.mapsvg.objectsRepository 10126 .getSchema() 10127 .getFieldsAsArray() 10128 .filter(function (obj) { 10129 return obj.type == "select" || obj.type == "radio" || obj.type == "region"; 10130 }) 10131 .map(function (obj) { 10132 return obj.name; 10133 }); 10134 let markerFieldsShort = []; 10135 markerFieldsShort = databaseFieldsFilterableShort.filter((o) => o.type === "select" || o.type === "radio"); 10136 const regionFields = this.mapsvg.regionsRepository 10137 .getSchema() 10138 .getFieldsAsArray() 10139 .map(function (obj) { 10140 if (obj.type == "status" || 10141 obj.type == "text" || 10142 obj.type == "textarea" || 10143 obj.type == "post" || 10144 obj.type == "select" || 10145 obj.type == "radio" || 10146 obj.type == "checkbox") { 10147 if (obj.type == "post") { 10148 return "Region.post.post_title"; 10149 } 10150 else { 10151 return "Region." + obj.name; 10152 } 10153 } 10154 }); 10155 return { 10156 databaseFields: databaseFields, 10157 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 10158 regionFields: regionFields, 10159 markerFieldsShort: markerFieldsShort, 10160 }; 10161 } 10162 addField(formElement) { 10163 const _this = this; 10164 if (["region", "marker", "post", "status", "distance", "location", "search"].indexOf(formElement.type) != -1) { 10165 let repeat = false;
10166 _this.formElements.forEach(function (control) { 10167 if (control.type == formElement.type) 10168 repeat = true; 10169 }); 10170 if (repeat) { 10171 jQuery.growl.error({ 10172 title: "Error", 10173 message: 'You can add only 1 "' + MapSVG.ucfirst(formElement.type) + '" field', 10174 }); 10175 return; 10176 } 10177 } 10178 _this.formElements.push(formElement); 10179 _this.getForm().append(formElement.domElements.main); 10180 this.setFormElementEventHandlers(formElement); 10181 if (this.editMode) { 10182 if (formElement.protected) { 10183 formElement.hide(); 10184 } 10185 else { 10186 this.edit(formElement); 10187 } 10188 } 10189 return formElement; 10190 } 10191 edit(formElement) { 10192 const _this = this; 10193 _this.currentlyEditing && _this.currentlyEditing.destroyEditor(); 10194 this.getFormEditor().appendChild(formElement.getEditor()); 10195 formElement.initEditor(); 10196 _this.currentlyEditing = formElement; 10197 $$w(_this.getForm()).find(".form-group.active").removeClass("active"); 10198 $$w(formElement.domElements.main).addClass("active"); 10199 } 10200 get() { 10201 } 10202 getSchema() { 10203 return this.formElements.map(function (formElement) { 10204 return formElement.getSchema(); 10205 }); 10206 } 10207 close() { 10208 this.formElements.forEach((formElement) => formElement.destroy()); 10209 this.mediaUploader && this.mediaUploader.off("select"); 10210 MapSVG.formBuilder = null; 10211 this.events.trigger("close", this, [this]); 10212 } 10213 destroy() { 10214 $$w(this.view).empty().remove(); 10215 this.sortable = null; 10216 } 10217 toJSON(addEmpty) { 10218 const obj = {}; 10219 function add(obj, name, value) { 10220 if (!addEmpty && !value) 10221 return false; 10222 if (name.length == 1) { 10223 obj[name[0]] = value; 10224 } 10225 else { 10226 if (obj[name[0]] == null) { 10227 if (name[1] === "") { 10228 obj[name[0]] = []; 10229 } 10230 else { 10231 obj[name[0]] = {}; 10232 } 10233 } 10234 if (obj[name[0]].length !== undefined) { 10235 obj[name[0]].push(value); 10236 } 10237 else { 10238 add(obj[name[0]], name.slice(1), value); 10239 } 10240 } 10241 } 10242 $$w(this.elements.containers.formView) 10243 .find("input, textarea, select") 10244 .each(function () { 10245 if (!$$w(this).data("skip") && 10246 !$$w(this).prop("disabled") && 10247 $$w(this).attr("name") && 10248 !(!addEmpty && 10249 $$w(this).attr("type") == "checkbox" && 10250 $$w(this).attr("checked") == undefined) && 10251 !($$w(this).attr("type") == "radio" && $$w(this).attr("checked") == undefined)) { 10252 let value; 10253 if ($$w(this).attr("type") == "checkbox") { 10254 value = $$w(this).prop("checked"); 10255 } 10256 else { 10257 value = $$w(this).val(); 10258 } 10259 add(obj, $$w(this).attr("name").replace(/]/g, "").split("["), value); 10260 } 10261 }); 10262 return obj; 10263 } 10264 getRegionsList() { 10265 return this.mapsvg.regions.map(function (r) { 10266 return { id: r.id, title: r.title }; 10267 }); 10268 } 10269 getRegionsAsArray() { 10270 return this.mapsvg.regions; 10271 } 10272 setRegions(location) { 10273 const regionsFormElement = this.formElements.get("regions"); 10274 if (this.mapsvg.options.source.indexOf("/geo-calibrated/us
10274a.svg") !== -1) { 10275 regionsFormElement.setValue(["US-" + location.address.state_short]); 10276 } 10277 else if (this.mapsvg.options.source.indexOf("/geo-calibrated/world.svg") !== -1) { 10278 if (location.address.country_short) { 10279 regionsFormElement.setValue([location.address.country_short]); 10280 } 10281 } 10282 else { 10283 if (location.address.administrative_area_level_1) { 10284 this.mapsvg.regions.forEach((_region) => { 10285 if (_region.title === location.address.administrative_area_level_1 || 10286 _region.title === location.address.administrative_area_level_2 || 10287 _region.id === 10288 location.address.country_short + 10289 "-" + 10290 location.address.administrative_area_level_1_short) { 10291 regionsFormElement.setValue([_region.id]); 10292 } 10293 }); 10294 } 10295 } 10296 } 10297 } 10298 10299 const $$x = jQuery; 10300 class FiltersController extends DetailsController { 10301 constructor(options) { 10302 super(options); 10303 this.showButtonText = options.showButtonText; 10304 this.clearButton = options.clearButton; 10305 this.clearButtonText = options.clearButtonText; 10306 this.searchButton = options.searchButton; 10307 this.searchButtonText = options.searchButtonText; 10308 this.padding = options.padding; 10309 this.schema = options.schema; 10310 this.hideFilters = options.hide; 10311 this.query = options.query; 10312 } 10313 viewDidLoad() { 10314 super.viewDidLoad(); 10315 const _this = this; 10316 this.formBuilder = new FormBuilder({ 10317 container: this.containers.contentView, 10318 filtersMode: true, 10319 schema: this.schema, 10320 modal: this.modal, 10321 filtersHide: this.hideFilters, 10322 showButtonText: this.showButtonText, 10323 clearButton: this.clearButton, 10324 clearButtonText: this.clearButtonText, 10325 searchButton: this.searchButton, 10326 searchButtonText: this.searchButtonText, 10327 editMode: false, 10328 mapsvg: this.mapsvg, 10329 data: {}, 10330 admin: false, 10331 events: { 10332 "changed.field": (formElement, field, value) => { 10333 const filters = {}; 10334 let _value = value; 10335 if (field === "regions") { 10336 _value = {}; 10337 _value.region_ids = value instanceof Array ? value : [value]; 10338 _value.table_name = this.mapsvg.options.database.regionsTableName; 10339 if (_value.region_ids.length === 0 || _value.region_ids[0] === "") { 10340 _value = null; 10341 } 10342 } 10343 filters[field] = _value; 10344 this.query.setFilters(filters); 10345 _this.events.trigger("changed.field", _this, [field, value]); 10346 _this.events.trigger("changed.fields", _this, [field, value]); 10347 }, 10348 "changed.search": (formElement, value) => { 10349 this.query.setSearch(value); 10350 _this.events.trigger("changed.search", _this, [value]); 10351 }, 10352 cleared: (formBuilder) => { 10353 this.query.clearFilters(); 10354 this.events.trigger("cleared", _this, []); 10355 }, 10356 loaded: (formBuilder) => { 10357 $$x(formBuilder.container).find(".mapsvg-form-builder").css({ 10358 padding: _this.padding, 10359 }); 10360 this.updateScroll(); 10361 this.events.trigger("loaded"); 10362 }, 10363 }, 10364 }); 10365 } 10366 reset() { 10367 this.formBuilder && this.formBuilder.reset(); 10368 } 10369 update(query) { 10370 const _query = Object.assign({}, query.filters); 10371 _query.search = query.search; 10372 this.formBuilder && this.formBuilder.update(_query); 10373 } 10374 setFiltersCounter() { 10375 if (this.hideFilters) { 10376 const filtersCounter = Object.keys(this.query.filters).length; 10377 const filtersCounterString = filtersCounter === 0 ? "" : f
10377iltersCounter.toString(); 10378 this.formBuilder && 10379 this.formBuilder.showFiltersButton && 10380 $$x(this.formBuilder.showFiltersButton.domElements.main) 10381 .find("button") 10382 .html(this.showButtonText + " <b>" + filtersCounterString + "</b>"); 10383 } 10384 } 10385 setEventHandlers() { 10386 super.setEventHandlers(); 10387 const _this = this; 10388 $$x(this.containers.view).on("click", ".mapsvg-btn-show-filters", function () { 10389 _this.events.trigger("click.btn.showFilters"); 10390 }); 10391 $$x(this.containers.view).on("click", "#mapsvg-search-container", function () { 10392 _this.events.trigger("click.btn.searchButton"); 10393 }); 10394 } 10395 } 10396 10397 const $$y = jQuery; 10398 class PopoverController extends Controller { 10399 constructor(options) { 10400 super(options); 10401 this.autoresize = true; 10402 this.point = options.point; 10403 this.yShift = options.yShift; 10404 this.mapObject = options.mapObject; 10405 this.id = this.mapObject.id + "_" + Math.random(); 10406 $$y(this.containers.main).data("popover-id", this.id); 10407 } 10408 setPoint(point) { 10409 this.point = point; 10410 } 10411 getToolbarTemplate() { 10412 if (this.withToolbar) 10413 return '<div class="mapsvg-popover-close"></div>'; 10414 else 10415 return ""; 10416 } 10417 viewDidLoad() { 10418 super.viewDidLoad.call(this); 10419 if (MapSVG.isPhone && 10420 this.mapsvg.options.popovers.mobileFullscreen && 10421 !this.mobileCloseBtn) { 10422 this.mobileCloseBtn = $$y('<button class="mapsvg-mobile-modal-close mapsvg-btn">' + 10423 this.mapsvg.getData().options.mobileView.labelClose + 10424 "</button>")[0]; 10425 $$y(this.containers.view).append(this.mobileCloseBtn); 10426 } 10427 this.adjustScreenPosition(); 10428 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10429 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10430 this.adjustHeight(); 10431 this.updateScroll(); 10432 this.autoresize && this.resizeSensor.setScroll(); 10433 this.events.trigger("shown", this, [this]); 10434 } 10435 adjustHeight() { 10436 $$y(this.containers.main).height($$y(this.containers.main).find(".mapsvg-auto-height").outerHeight() + 10437 (this.containers.toolbar ? $$y(this.containers.toolbar).outerHeight() : 0)); 10438 } 10439 adjustScreenPosition() { 10440 if (this.point) { 10441 const pos = this.mapsvg.converter.convertSVGToPixel(this.point); 10442 pos.y -= this.yShift; 10443 pos.x = Math.round(pos.x); 10444 pos.y = Math.round(pos.y); 10445 this.setScreenPosition(pos.x, pos.y); 10446 } 10447 } 10448 moveSrceenPositionBy(deltaX, deltaY) { 10449 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 10450 this.setScreenPosition(x, y); 10451 } 10452 setScreenPosition(x, y) { 10453 this.screenPoint = new ScreenPoint(x, y); 10454 $$y(this.containers.main).css({ 10455 transform: "translateX(-50%) translate(" + x + "px," + y + "px)", 10456 }); 10457 } 10458 setEventHandlers() { 10459 $$y("body").off(".popover.mapsvg"); 10460 $$y(this.containers.view).on("click touchend", ".mapsvg-popover-close, .mapsvg-mobile-modal-close", (e) => { 10461 e.stopImmediatePropagation(); 10462 this.close(); 10463 }); 10464 $$y("body").on("mouseup.popover.mapsvg touchend.popover.mapsvg", (e) => { 10465 if (this.mapsvg.isScrolling || 10466 $$y(e.target).closest(".mapsvg-directory").length || 10467 $$y(e.target).closest(".mapsvg-popover").length || 10468 $$y(e.target).hasClass("mapsvg-btn-map")) 10469 return; 10470 this.close(); 10471 }); 10472 } 10473 close() { 10474 if ($$y(this.containers.main).data("popover-id") != this.id || 10475 !$$y(this.containers.main).is(":visible")) 10476 return; 10477 this.destroy(); 10478 if (this.mapObject instanceof Region) { 10479 this.mapsvg.deselectRegion(this.mapObject); 10480 } 10481 if (this.mapObject instanceof Marker) { 10482 this.mapsvg.deselectAllMarkers(); 10483 } 10484 this.events.trigger("closed", this, [this]); 10485 } 10486 destroy() { 10487 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", false); 10488 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", false); 10489 super.destroy.call(this); 10490 } 10491 show() { 10492 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10493 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10494 } 10495 } 10496 10497 const $$z = jQuery; 10498 class Tooltip extends Controller { 10499 constructor(options) { 10500 super(options); 10501 this.scrollable = false;
10502 this.withToolbar = false; 10503 this.autoresize = false; 10504 this.screenPoint = new ScreenPoint(0, 0); 10505 this.posOriginal = {}; 10506 this.posShifted = {}; 10507 this.posShiftedPrev = {}; 10508 this.mirror = {}; 10509 this.noPadding = true; 10510 this.setPosition(options.position); 10511 this.setSize(options.minWidth, options.maxWidth); 10512 } 10513 setSize(minWidth, maxWidth) { 10514 this.minWidth = minWidth; 10515 this.maxWidth = maxWidth; 10516 this.containers.main.style["min-width"] = this.minWidth + "px"; 10517 this.containers.main.style["max-width"] = this.maxWidth + "px"; 10518 } 10519 setPosition(position) { 10520 const ex = position.split("-"); 10521 if (ex[0].indexOf("top") != -1 || ex[0].indexOf("bottom") != -1) { 10522 this.posOriginal.topbottom = ex[0]; 10523 } 10524 if (ex[0].indexOf("left") != -1 || ex[0].indexOf("right") != -1) { 10525 this.posOriginal.leftright = ex[0]; 10526 } 10527 if (ex[1]) { 10528 this.posOriginal.leftright = ex[1]; 10529 } 10530 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10531 this.containers.main.classList.add("mapsvg-tt-" + position); 10532 } 10533 setScreenPoint(x, y) { 10534 this.screenPoint.x = x; 10535 this.screenPoint.y = y; 10536 } 10537 viewDidLoad() { 10538 super.viewDidLoad.call(this); 10539 } 10540 viewDidAppear() { 10541 super.viewDidAppear(); 10542 this.events.trigger("shown", this, [this]); 10543 } 10544 setScreenPosition(x, y) { 10545 this.setScreenPoint(x, y); 10546 this.containers.main.style.transform = 10547 "translateX(-50%) translate(" + x + "px," + y + "px)"; 10548 } 10549 setEventHandlers() { 10550 const event = "mousemove.tooltip.mapsvg-" + this.mapsvg.id; 10551 $$z("body") 10552 .off(event) 10553 .on(event, (e) => { 10554 MapSVG.mouse = MapSVG.mouseCoords(e); 10555 this.containers.main.style.left = 10556 e.clientX + 10557 $$z(window).scrollLeft() - 10558 $$z(this.mapsvg.containers.map).offset().left + 10559 "px"; 10560 this.containers.main.style.top = 10561 e.clientY + 10562 $$z(window).scrollTop() - 10563 $$z(this.mapsvg.containers.map).offset().top + 10564 "px"; 10565 const m = new ScreenPoint(e.clientX + $$z(window).scrollLeft(), e.clientY + $$z(window).scrollTop()); 10566 const _tbbox = this.containers.main.getBoundingClientRect(); 10567 const _mbbox = this.mapsvg.containers.wrap.getBoundingClientRect(); 10568 const tbbox = { 10569 top: _tbbox.top + $$z(window).scrollTop(), 10570 bottom: _tbbox.bottom + $$z(window).scrollTop(), 10571 left: _tbbox.left + $$z(window).scrollLeft(), 10572 right: _tbbox.right + $$z(window).scrollLeft(), 10573 width: _tbbox.width, 10574 height: _tbbox.height, 10575 }; 10576 const mbbox = { 10577 top: _mbbox.top + $$z(window).scrollTop(), 10578 bottom: _mbbox.bottom + $$z(window).scrollTop(), 10579 left: _mbbox.left + $$z(window).scrollLeft(), 10580 right: _mbbox.right + $$z(window).scrollLeft(), 10581 width: _mbbox.width, 10582 height: _mbbox.height, 10583 }; 10584 if (m.x > mbbox.right || 10585 m.y > mbbox.bottom || 10586 m.x < mbbox.left || 10587 m.y < mbbox.top) { 10588 return; 10589 } 10590 if (this.mirror.top || this.mirror.bottom) { 10591 if (this.mirror.top && m.y > this.mirror.top) { 10592 this.mirror.top = 0; 10593 delete this.posShifted.topbottom; 10594 } 10595 else if (this.mirror.bottom && m.y < this.mirror.bottom) { 10596 this.mirror.bottom = 0; 10597 delete this.posShifted.topbottom; 10598 } 10599 } 10600 else { 10601 if (tbbox.bottom < mbbox.top + tbbox.height) { 10602 this.posShifted.topbottom = "bottom"; 10603 this.mirror.top = m.y; 10604 } 10605 else if (tbbox.top > mbbox.bottom - tbbox.height) { 10606 this.posShifted.topbottom = "top"; 10607 this.mirror.bottom = m.y; 10608 } 10609 } 10610 if (this.mirror.right || this.mirror.left) { 10611 if (this.mirror.left && m.x > this.mirror.left) { 10612 this.mirror.left = 0; 10613 delete this.posShifted.leftright; 10614 } 10615 else if (this.mirror.right && m.x < this.mirror.right) { 10616 this.mirror.right = 0; 10617 delete this.posShifted.leftright; 10618 } 10619 } 10620 else { 10621 if (tbbox.right < mbbox.left + tbbox.width) { 10622 this.posShifted.leftright = "right"; 10623 this.mirror.left = m.x; 10624 } 10625 else if (tbbox.left > mbbox.right - tbbox.width) { 10626 this.posShifted.leftright = "left"; 10627 this.mirror.right = m.x; 10628 } 10629 } 10630 let pos = $$z.extend({}, this.posOriginal, this.posShifted); 10631 const _pos = []; 10632 pos.topbottom && _pos.push(pos.topbottom); 10633 pos.leftright && _pos.push(pos.leftright); 10634 pos = _pos.join("-"); 10635 if (this.posShifted.topbottom != this.posOriginal.topbottom || 10636 this.posShifted.leftright != this.posOriginal.leftright) { 10637 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10638 this.containers.main.classList.add("mapsvg-tt-" + pos); 10639 this.posShiftedPrev = pos; 10640 } 10641 }); 10642 } 10643 setContent(template, data) { 10644 this.containers.main.innerHTML = template(data); 10645 return this; 10646 } 10647 show() { 10648 this.containers.main.classList.add("mapsvg-tooltip-visible"); 10649 return this; 10650 } 10651 hide() { 10652 this.containers.main.classList.remove("mapsvg-tooltip-visible"); 10653 return this; 10654 } 10655 } 10656 10657 const $$A = jQuery; 10658 class MapSVGMap { 10659 constructor(containerId, mapParams, externalParams) { 10660 this.markerOptions = { src: MapSVG.urls.root + "markers/pin1_red.png" }; 10661 const options = mapParams.options; 10662 this.updateOutdatedOptions(options); 10663 this.dirtyFields = []; 10664 this.containerId = containerId; 10665 this.options = $$A.extend(true, {}, DefaultOptions, options); 10666 this.options.source = this.urlToRelativePath(this.options.source); 10667 this.editMode = this.options.editMode; 10668 delete this.options.editMode; 10669 this.id = mapParams.id; 10670 this.svgFileLastChanged = mapParams.svgFileLastChanged; 10671 this.regions = new ArrayIndexed("id"); 10672 this.objects = new ArrayIndexed("id"); 10673 this.events = new Events(this); 10674 this.highlightedRegions = []; 10675 this.editRegions = { on: false }; 10676 this.editMarkers = { on: false }; 10677 this.editData = { on: false }; 10678 this.controllers = {}; 10679 this.containers = { 10680 map: document.getElementById(this.containerId), 10681 scrollpane: $$A('<div class="mapsvg-scrollpane"></div>')[0], 10682 scrollpaneWrap: $$A('<div class="mapsvg-scrollpane-wrap"></div>')[0], 10683 layers: $$A('<div class="mapsvg-layers-wrap"></div>')[0], 10684 }; 10685 this.containers.map.appendChild(this.containers.layers); 10686 this.containers.map.appendChild(this.containers.scrollpaneWrap); 10687 this.containers.scrollpaneWrap.appendChild(this.containers.scrollpane); 10688 this.whRatio = 0; 10689 this.isScrolling = false;
10690 this.markerOptions = {}; 10691 this.svgDefault = {}; 10692 this.scale = 1; 10693 this._scale = 1; 10694 this.selected_id = []; 10695 this.regions = new ArrayIndexed("id"); 10696 if (!this.options.database.regionsTableName) { 10697 this.options.database.regionsTableName = "regions_" + this.id; 10698 } 10699 if (!this.options.database.objectsTableName) { 10700 this.options.database.objectsTableName = "objects_" + this.id; 10701 } 10702 this.regionsRepository = new Repository("region", "regions/" + this.options.database.regionsTableName); 10703 this.regionsRepository.query.update({ perpage: 0 }); 10704 this.objectsRepository = new Repository("object", "objects/" + this.options.database.objectsTableName); 10705 if (this.options.database.noFiltersNoLoad) { 10706 this.objectsRepository.setNoFiltersNoLoad(true); 10707 } 10708 this.objectsRepository.query.update({ 10709 perpage: this.options.database.pagination.on 10710 ? this.options.database.pagination.perpage 10711 : 0, 10712 }); 10713 this.schemaRepository = new SchemaRepository(); 10714 this.markers = new ArrayIndexed("id"); 10715 this.markersClusters = new ArrayIndexed("id"); 10716 this._viewBox = new ViewBox(0, 0, 0, 0); 10717 this.viewBox = new ViewBox(0, 0, 0, 0); 10718 this.zoomLevel = 0; 10719 this.scroll = { 10720 tx: 0, 10721 ty: 0, 10722 vxi: 0, 10723 vyi: 0, 10724 x: 0, 10725 y: 0, 10726 dx: 0, 10727 dy: 0, 10728 vx: 0, 10729 vy: 0, 10730 gx: 0, 10731 gy: 0, 10732 touchScrollStart: 0, 10733 }; 10734 this.layers = {}; 10735 this.geoCoordinates = false; 10736 this.geoViewBox = new GeoViewBox(new GeoPoint(0, 0), new GeoPoint(0, 0)); 10737 this.eventsPreventList = {}; 10738 this.googleMaps = { 10739 loaded: false, 10740 initialized: false, 10741 map: null, 10742 zoomLimit: true, 10743 maxZoomService: null, 10744 }; 10745 this.afterLoadBlockers = 1; 10746 this.loaded = false; 10747 if (this.id) { 10748 this.afterLoadBlockers += 2; 10749 } 10750 if (this.options.googleMaps.on) { 10751 this.afterLoadBlockers++; 10752 } 10753 if (this.filtersShouldBeShown()) { 10754 this.afterLoadBlockers++; 10755 } 10756 this.init(); 10757 } 10758 urlToRelativePath(url) { 10759 if (url.indexOf("//") === 0) 10760 url = url.replace(/^\/\/[^/]+/, "").replace("//", "/"); 10761 else 10762 url = url.replace(/^.*:\/\/[^/]+/, "").replace("//", "/"); 10763 return url; 10764 } 10765 setGroups(groups) { 10766 const _this = this; 10767 if (!this.groups) { 10768 _this.groups = new ArrayIndexed("id", _this.options.groups, { 10769 autoId: true, 10770 unique: true, 10771 }); 10772 } 10773 else { 10774 this.options.groups = this.groups; 10775 } 10776 _this.groups.forEach(function (g) { 10777 g.objects && 10778 g.objects.length && 10779 g.objects.forEach(function (obj) { 10780 _this.containers.svg 10781 .querySelector("#" + obj.value) 10782 .classList.toggle("mapsvg-hidden", !g.visible); 10783 }); 10784 }); 10785 } 10786 getGroupSelectOptions() { 10787 const _this = this; 10788 const optionGroups = []; 10789 const options = []; 10790 const options2 = []; 10791 $$A(_this.containers.svg) 10792 .find("g") 10793 .each(function (index) { 10794 const id = $$A(this)[0].getAttribute("id"); 10795 if (id) { 10796 const title = $$A(this)[0].getAttribute("title"); 10797 options.push({ label: title || id, value: id }); 10798 } 10799 }); 10800 optionGroups.push({ title: "SVG Layers / Groups", options: options }); 10801 $$A(_this.containers.svg) 10802 .find("path,ellipse,circle,polyline,polygon,rectangle,img,text") 10803 .each(function (index) { 10804 const id = $$A(this)[0].getAttribute("id"); 10805 if (id) { 10806 const title = $$A(this)[0].getAttribute("title"); 10807 options2.push({ label: title || id, value: id }); 10808 } 10809 }); 10810 optionGroups.push({ title: "Other SVG objects", options: options2 }); 10811 return optionGroups; 10812 } 10813 setLayersControl(options) { 10814 const _this = this; 10815 if (options) 10816 $$A.extend(true, this.options.layersControl, options); 10817 if (this.options.layersControl.on) { 10818 if (!this.containers.layersControl) { 10819 this.containers.layersControl = document.createElement("div"); 10820 this.containers.layersControl.classList.add("mapsvg-layers-control"); 10821 this.containers.layersControlLabel = document.createElement("div"); 10822 this.containers.layersControlLabel.classList.add("mapsvg-layers-label"); 10823 this.containers.layersControl.appendChild(this.containers.layersControlLabel); 10824 const layersControlWrap = document.createElement("div"); 10825 layersControlWrap.classList.add("mapsvg-layers-list-wrap"); 10826 this.containers.layersControl.appendChild(layersControlWrap); 10827 this.containers.layersControlListNano = document.createElement("div"); 10828 this.containers.layersControlListNano.classList.add("nano"); 10829 layersControlWrap.appendChild(this.containers.layersControlListNano); 10830 this.containers.layersControlList = document.createElement("div"); 10831 this.containers.layersControlList.classList.add("mapsvg-layers-list"); 10832 this.containers.layersControlList.classList.add("nano-content"); 10833 this.containers.layersControlListNano.appendChild(this.containers.layersControlList); 10834 this.containers.mapContainer.appendChild(this.containers.layersControl); 10835 } 10836 this.containers.layersControl.style.display = "block"; 10837 this.containers.layersControlLabel.innerHTML = this.options.layersControl.label; 10838 this.containers.layersControlLabel.style.display = "block"; 10839 this.containers.layersControlList.innerHTML = ""; 10840 while (this.containers.layersControlList.firstChild) { 10841 this.containers.layersControlList.removeChild(this.containers.layersControlList.firstChild); 10842 } 10843 this.containers.layersControl.classList.remove("mapsvg-top-left", "mapsvg-top-right", "mapsvg-bottom-left", "mapsvg-bottom-right"); 10844 this.containers.layersControl.classList.add("mapsvg-" + this.options.layersControl.position); 10845 if (this.options.menu.on && 10846 !this.options.menu.customContainer && 10847 this.options.layersControl.position.indexOf("left") !== -1) { 10848 this.containers.layersControl.style.left = this.options.menu.width; 10849 } 10850 this.containers.layersControl.style.maxHeight = this.options.layersControl.maxHeight; 10851 this.options.groups.forEach((g) => { 10852 const item = document.createElement("div"); 10853 item.classList.add("mapsvg-layers-item"); 10854 item.setAttribute("data-group-id", g.id); 10855 item.innerHTML = 10856 '<input type="checkbox" class="ios8-switch ios8-switch-sm" ' + 10857 (g.visible ? "checked" : "") + 10858 " /><label>" + 10859 g.title + 10860 "</label>"; 10861 this.containers.layersControlList.appendChild(item); 10862 }); 10863 $$A(this.containers.layersControlListNano).nanoScroller({ 10864 preventPageScrolling: true, 10865 iOSNativeScrolling: true, 10866 }); 10867 $$A(this.containers.layersControl).off(); 10868 $$A(this.containers.layersControl).on("click", ".mapsvg-layers-item", function () { 10869 const id = $$A(this).data("group-id"); 10870 const input = $$A(this).find("input"); 10871 input.prop("checked", !input.prop("checked")); 10872 _this.groups.forEach(function (g) { 10873 if (g.id === id) 10874 g.visible = !g.visible; 10875 }); 10876 _this.setGroups(); 10877 }); 10878 $$A(this.containers.layersControlLabel).off(); 10879 $$A(this.containers.layersControlLabel).on("click", () => { 10880 $$A(_this.containers.layersControl).toggleClass("closed"); 10881 }); 10882 $$A(this.containers.layersControl).toggleClass("closed", !this.options.layersControl.expanded); 10883 } 10884 else { 10885 if (this.containers.layersControl) { 10886 this.containers.layersControl.style.display = "none"; 10887 } 10888 } 10889 }
10890 loadDataObjects(params) { 10891 return this.objectsRepository.find(params); 10892 } 10893 loadDirectory() { 10894 if (!this.editMode && 10895 this.options.menu.source === "database" && 10896 !this.objectsRepository.loaded) { 10897 return; 10898 } 10899 if (this.options.menu.on) { 10900 this.controllers.directory.loadItemsToDirectory(); 10901 } 10902 this.setPagination(); 10903 } 10904 setPagination() { 10905 const _this = this; 10906 this.containers.pagerMap && $$A(this.containers.pagerMap).empty().remove(); 10907 this.containers.pagerDir && $$A(this.containers.pagerDir).empty().remove(); 10908 if (_this.options.database.pagination.on && 10909 _this.options.database.pagination.perpage !== 0) { 10910 this.containers.directory.classList.toggle("mapsvg-with-pagination", ["directory", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10911 this.containers.map.classList.toggle("mapsvg-with-pagination", ["map", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10912 if (_this.options.menu.on) { 10913 this.containers.pagerDir = _this.getPagination(); 10914 _this.controllers.directory.addPagination(this.containers.pagerDir); 10915 } 10916 this.containers.pagerMap = _this.getPagination(); 10917 this.containers.map.appendChild(this.containers.pagerMap); 10918 } 10919 } 10920 getPagination(callback) { 10921 const _this = this; 10922 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="#">← ' + 10923 _this.options.database.pagination.prev + 10924 " " + 10925 _this.options.database.pagination.perpage + 10926 '</a></li><li class="mapsvg-next"><a href="#">' + 10927 _this.options.database.pagination.next + 10928 " " + 10929 _this.options.database.pagination.perpage + 10930 ' →</a></li><!--<li class="mapsvg-last"><a href="#">Last</a></li>--></ul></nav>'); 10931 if (this.objectsRepository.onFirstPage() && this.objectsRepository.onLastPage()) { 10932 pager.hide(); 10933 } 10934 else { 10935 pager.find(".mapsvg-prev").removeClass("disabled"); 10936 pager.find(".mapsvg-first").removeClass("disabled"); 10937 pager.find(".mapsvg-last").removeClass("disabled"); 10938 pager.find(".mapsvg-next").removeClass("disabled"); 10939 this.objectsRepository.onLastPage() && 10940 pager.find(".mapsvg-next").addClass("disabled") && 10941 pager.find(".mapsvg-last").addClass("disabled"); 10942 this.objectsRepository.onFirstPage() && 10943 pager.find(".mapsvg-prev").addClass("disabled") && 10944 pager.find(".mapsvg-first").addClass("disabled"); 10945 } 10946 pager 10947 .on("click", ".mapsvg-next:not(.disabled)", (e) => { 10948 e.preventDefault(); 10949 if (this.objectsRepository.onLastPage()) 10950 return; 10951 const query = new Query({ page: this.objectsRepository.query.page + 1 }); 10952 this.objectsRepository.find(query).done(function () { 10953 callback && callback(); 10954 }); 10955 }) 10956 .on("click", ".mapsvg-prev:not(.disabled)", function (e) { 10957 e.preventDefault(); 10958 if (_this.objectsRepository.onFirstPage()) 10959 return; 10960 const query = new Query({ page: _this.objectsRepository.query.page - 1 }); 10961 _this.objectsRepository.find(query).done(function () { 10962 callback && callback(); 10963 }); 10964 }) 10965 .on("click", ".mapsvg-first:not(.disabled)", function (e) { 10966 e.preventDefault(); 10967 if (_this.objectsRepository.onFirstPage()) 10968 return; 10969 const query = new Query({ page: 1 }); 10970 _this.objectsRepository.find(query).done(function () { 10971 callback && callback(); 10972 }); 10973 }) 10974 .on("click", ".mapsvg-last:not(.disabled)", function (e) { 10975 e.preventDefault(); 10976 if (_this.objectsRepository.onLastPage()) 10977 return; 10978 const query = new Query({ lastpage: true }); 10979 _this.objectsRepository.find(query).done(function () { 10980 callback && callback(); 10981 }); 10982 }); 10983 return pager[0]; 10984 } 10985 deleteMarkers() { 10986 while (this.markers.length) { 10987 this.markerDelete(this.markers[0]); 10988 } 10989 }
10990 deleteClusters() { 10991 if (this.markersClusters) { 10992 this.markersClusters.forEach(function (markerCluster) { 10993 markerCluster.destroy(); 10994 }); 10995 this.markersClusters.clear(); 10996 } 10997 } 10998 addLocations() { 10999 const _this = this; 11000 this.firstDataLoad = this.firstDataLoad === undefined; 11001 let locationField = this.objectsRepository.getSchema().getFieldByType("location"); 11002 if (!locationField) { 11003 return; 11004 } 11005 locationField = locationField.name; 11006 if (locationField) { 11007 if (this.firstDataLoad) { 11008 this.setMarkerImagesDependency(); 11009 } 11010 _this.deleteMarkers(); 11011 _this.deleteClusters(); 11012 _this.clusters = {}; 11013 _this.clustersByZoom = []; 11014 if (this.objectsRepository.getLoaded().length > 0) { 11015 this.objectsRepository.getLoaded().forEach(function (object) { 11016 if (object[locationField]) { 11017 if (object[locationField].img && 11018 (object[locationField].geoPoint || object[locationField].svgPoint)) { 11019 new Marker({ 11020 location: object[locationField], 11021 object: object, 11022 mapsvg: _this, 11023 }); 11024 } 11025 } 11026 }); 11027 if (_this.options.clustering.on) { 11028 _this.startClusterizer(); 11029 } 11030 else { 11031 this.objectsRepository.getLoaded().forEach(function (object) { 11032 if (object.location && object.location.marker) { 11033 _this.markerAdd(object.location.marker); 11034 } 11035 }); 11036 _this.mayBeFitMarkers(); 11037 } 11038 } 11039 } 11040 } 11041 addClustersFromWorker(zoomLevel, clusters) { 11042 const _this = this; 11043 _this.clustersByZoom[zoomLevel] = []; 11044 for (const cell in clusters) { 11045 const markers = clusters[cell].markers.map(function (marker) { 11046 return _this.objectsRepository.objects.findById(marker.id).location.marker; 11047 }); 11048 _this.clustersByZoom[zoomLevel].push(new MarkerCluster({ 11049 markers: markers, 11050 svgPoint: new SVGPoint(clusters[cell].x, clusters[cell].y), 11051 cellX: clusters[cell].cellX, 11052 cellY: clusters[cell].cellY, 11053 }, _this)); 11054 } 11055 if (_this.zoomLevel === zoomLevel) { 11056 _this.clusterizeMarkers(); 11057 } 11058 } 11059 startClusterizer() { 11060 if (!this.objectsRepository || this.objectsRepository.getLoaded().length === 0) { 11061 return; 11062 } 11063 const locationField = this.objectsRepository.getSchema().getFieldByType("location"); 11064 if (!locationField) { 11065 return false; 11066 } 11067 if (!this.clusterizerWorker) { 11068 this.clusterizerWorker = new Worker(MapSVG.urls.root + "js/mapsvg/Core/clustering.js"); 11069 this.clusterizerWorker.onmessage = (evt) => { 11070 if (evt.data.clusters) { 11071 this.addClustersFromWorker(evt.data.zoomLevel, evt.data.clusters); 11072 } 11073 }; 11074 } 11075 const objectsData = []; 11076 this.objectsRepository 11077 .getLoaded() 11078 .filter((o) => { 11079 return o.location && o.location.marker; 11080 }) 11081 .forEach((o) => { 11082 objectsData.push({ 11083 id: o.id, 11084 x: o.location.marker.svgPoint.x, 11085 y: o.location.marker.svgPoint.y, 11086 }); 11087 }); 11088 this.clusterizerWorker.postMessage({ 11089 objects: objectsData, 11090 cellSize: 50, 11091 mapWidth: this.containers.map.clientWidth, 11092 zoomLevels: this.zoomLevels, 11093 zoomLevel: this.zoomLevel, 11094 zoomDelta: this.zoomDelta, 11095 svgViewBox: this.svgDefault.viewBox, 11096 }); 11097 this.events.on("zoom", () => { 11098 this.clusterizerWorker.postMessage({ 11099 message: "zoom", 11100 zoomLevel: this.zoomLevel, 11101 }); 11102 }); 11103 } 11104 clusterizeMarkers(skipFitMarkers) { 11105 $$A(this.layers.markers) 11106 .children() 11107 .each((i, obj) => { 11108 $$A(obj).detach(); 11109 }); 11110 this.markers.clear(); 11111 this.markersClusters.clear();
11112 this.clustersByZoom && 11113 this.clustersByZoom[this.zoomLevel] && 11114 this.clustersByZoom[this.zoomLevel].forEach((cluster) => { 11115 if (this.options.googleMaps.on && 11116 this.googleMaps.map && 11117 this.googleMaps.map.getZoom() >= 17) { 11118 this.markerAdd(cluster.markers[0]); 11119 } 11120 else { 11121 if (cluster.markers.length > 1) { 11122 this.markersClusterAdd(cluster); 11123 } 11124 else { 11125 this.markerAdd(cluster.markers[0]); 11126 } 11127 } 11128 }); 11129 if (this.editingMarker) { 11130 this.markerAdd(this.editingMarker); 11131 } 11132 if (!skipFitMarkers) { 11133 this.mayBeFitMarkers(); 11134 } 11135 if (this.options.labelsMarkers.on) { 11136 this.setLabelsMarkers(); 11137 } 11138 } 11139 getCssUrl() { 11140 return MapSVG.urls.root + "css/mapsvg.css"; 11141 } 11142 isGeo() { 11143 return this.mapIsGeo; 11144 } 11145 functionFromString(string) { 11146 let func; 11147 let error; 11148 const fn = string.trim(); 11149 if (fn.indexOf("{") == -1 || fn.indexOf("function") !== 0 || fn.indexOf("(") == -1) { 11150 return new SyntaxError("MapSVG user function error: no function body."); 11151 } 11152 const fnBody = fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")); 11153 const params = fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")); 11154 try { 11155 func = new Function(params, fnBody); 11156 } 11157 catch (err) { 11158 error = err; 11159 } 11160 if (!error) 11161 return func; 11162 else 11163 return error; 11164 } 11165 getOptions(forTemplate, forWeb) { 11166 const options = $$A.extend(true, {}, this.options); 11167 function clearEmpties(o) { 11168 for (const k in o) { 11169 if (!o[k] || typeof o[k] !== "object") { 11170 continue; 11171 } 11172 clearEmpties(o[k]); 11173 if (Object.keys(o[k]).length === 0) { 11174 delete o[k]; 11175 } 11176 } 11177 } 11178 clearEmpties(options.regions); 11179 $$A.extend(true, options, this.optionsDelta); 11180 options.viewBox = this._viewBox.toArray(); 11181 options.filtersSchema = this.filtersSchema.getFieldsAsArray(); 11182 if (options.filtersSchema.length > 0) { 11183 options.filtersSchema.forEach((field) => { 11184 if (field.type === "distance") { 11185 field.value = ""; 11186 } 11187 }); 11188 } 11189 delete options.markers; 11190 if (forTemplate) { 11191 options.svgFilename = options.source.split("/").pop(); 11192 options.svgFiles = MapSVG.svgFiles; 11193 } 11194 if (forWeb) 11195 $$A.each(options, (key, val) => { 11196 if (JSON.stringify(val) == JSON.stringify(this.defaults[key])) 11197 delete options[key]; 11198 }); 11199 delete options.backend; 11200 return options; 11201 } 11202 restoreDeltaOptions() { 11203 this.update(this.optionsDelta); 11204 this.optionsDelta = {}; 11205 } 11206 setEvents(functions) { 11207 let compiledFunction; 11208 for (const eventName in functions) { 11209 if (typeof functions[eventName] === "string") { 11210 compiledFunction = 11211 functions[eventName] != "" 11212 ? this.functionFromString(functions[eventName]) 11213 : null; 11214 if (!compiledFunction || 11215 compiledFunction.error || 11216 compiledFunction instanceof TypeError || 11217 compiledFunction instanceof SyntaxError) { 11218 continue; 11219 } 11220 } 11221 else if (typeof functions[eventName] === "function") { 11222 compiledFunction = functions[eventName]; 11223 } 11224 this.events.off(eventName); 11225 this.events.on(eventName, compiledFunction); 11226 if (eventName.indexOf("directory") !== -1) { 11227 const event = eventName.split(".")[0]; 11228 if (this.controllers && this.controllers.directory) { 11229 this.controllers.directory.events.off(event); 11230 this.controllers.directory.events.on(event, compiledFunction); 11231 } 11232 } 11233 } 11234 $$A.extend(true, this.options.events, functions); 11235 }
11236 setActions(options) { 11237 $$A.extend(true, this.options.actions, options); 11238 } 11239 setDetailsView(options) { 11240 options = options || this.options.detailsView || {}; 11241 $$A.extend(true, this.options.detailsView, options); 11242 if (this.options.detailsView.location === "top" && this.options.menu.position === "left") { 11243 this.options.detailsView.location = "leftSidebar"; 11244 } 11245 else if (this.options.detailsView.location === "top" && 11246 this.options.menu.position === "right") { 11247 this.options.detailsView.location = "rightSidebar"; 11248 } 11249 if (this.options.detailsView.location === "near" || 11250 this.options.detailsView.location === "mapContainer") { 11251 this.options.detailsView.location = "map"; 11252 } 11253 if (!this.containers.detailsView) { 11254 this.containers.detailsView = $$A('<div class="mapsvg-details-container"></div>')[0]; 11255 } 11256 $$A(this.containers.detailsView).toggleClass("mapsvg-details-container-relative", !(MapSVG.isPhone && this.options.detailsView.mobileFullscreen) && 11257 !this.shouldBeScrollable(this.options.detailsView.location)); 11258 if (this.options.detailsView.location === "custom") { 11259 $$A("#" + this.options.detailsView.containerId).append($$A(this.containers.detailsView)); 11260 } 11261 else { 11262 if (MapSVG.isPhone && this.options.detailsView.mobileFullscreen) { 11263 $$A("body").append($$A(this.containers.detailsView)); 11264 $$A(this.containers.detailsView).addClass("mapsvg-container-fullscreen"); 11265 } 11266 else { 11267 this.containers[this.options.detailsView.location].append(this.containers.detailsView); 11268 } 11269 if (this.options.detailsView.margin) { 11270 $$A(this.containers.detailsView).css("margin", this.options.detailsView.margin); 11271 } 11272 $$A(this.containers.detailsView).css("width", this.options.detailsView.width); 11273 } 11274 } 11275 setMobileView(options) { 11276 $$A.extend(true, this.options.mobileView, options); 11277 } 11278 attachDataToRegions(object) { 11279 this.regions.forEach(function (region) { 11280 region.objects = []; 11281 }); 11282 this.objectsRepository.getLoaded().forEach((obj, index) => { 11283 const regions = obj.getRegionsForTable(this.options.database.regionsTableName); 11284 if (regions && regions.length) { 11285 regions.forEach((region) => { 11286 const r = this.getRegion(region.id); 11287 if (r) 11288 r.objects.push(obj); 11289 }); 11290 } 11291 }); 11292 } 11293 setTemplates(templates) { 11294 this.templates = this.templates || {}; 11295 for (let name in templates) { 11296 if (name != undefined) { 11297 this.options.templates[name] = templates[name]; 11298 let t = this.options.templates[name]; 11299 if (name == "directoryItem" || name == "directoryCategoryItem") { 11300 const dirItemTemplate = this.options.templates.directoryItem; 11301 t = 11302 '{{#each items}}<div id="mapsvg-directory-item-{{#if id_no_spaces}}{{id_no_spaces}}{{else}}{{id}}{{/if}}" class="mapsvg-directory-item" data-object-id="{{id}}">' + 11303 dirItemTemplate + 11304 "</div>{{/each}}"; 11305 if (this.options.menu.categories && 11306 this.options.menu.categories.on && 11307 this.options.menu.categories.groupBy) { 11308 const t2 = this.options.templates["directoryCategoryItem"]; 11309 t = 11310 '{{#each items}}{{#with category}}<div id="mapsvg-category-item-{{value}}" class="mapsvg-category-item" data-category-value="{{value}}">' + 11311 t2 + 11312 '</div><div class="mapsvg-category-block" data-category-id="{{value}}">{{/with}}' + 11313 t + 11314 "</div>{{/each}}"; 11315 } 11316 name = "directory"; 11317 } 11318 try { 11319 this.options.templates[name] = t; 11320 this.templates[name] = Handlebars.compile(t, { strict: false }); 11321 } 11322 catch (err) { 11323 console.error(err); 11324 this.templates[name] = Handlebars.compile("", { strict: false }); 11325 } 11326 if (this.editMode && 11327 (name == "directory" || name == "directoryCategoryItem") && 11328 this.controllers && 11329 this.controllers.directory) { 11330 this.controllers.directory.templates.main = this.templates[name]; 11331 this.loadDirectory(); 11332 } 11333 } 11334 } 11335 } 11336 update(options) { 11337 for (const key in options) { 11338 if (key == "regions") { 11339 for (const id in options.regions) { 11340 const region = this.getRegion(id); 11341 region && region.update(options.regions[id]); 11342 if (options.regions[id].disabled != undefined) { 11343 this.deselectRegion(region); 11344 this.options.regions[id] = this.options.regions[id] || {}; 11345 this.options.regions[id].disabled = region.disabled; 11346 } 11347 } 11348 } 11349 else { 11350 const setter = "set" + MapSVG.ucfirst(key); 11351 if (typeof this[setter] == "function") 11352 this[setter](options[key]); 11353 else { 11354 this.options[key] = options[key]; 11355 } 11356 } 11357 } 11358 } 11359 getDirtyFields() { 11360 return this.getData(); 11361 } 11362 clearDirtyFields() { 11363 this.dirtyFields = []; 11364 } 11365 setTitle(title) { 11366 title && (this.options.title = title); 11367 } 11368 setExtension(extension) { 11369 if (extension) { 11370 this.options.extension = extension; 11371 } 11372 else { 11373 delete this.options.extension; 11374 } 11375 } 11376 setDisableLinks(on) { 11377 on = MapSVG.parseBoolean(on); 11378 if (on) { 11379 $$A(this.containers.map).on("click.a.mapsvg", "a", function (e) { 11380 e.preventDefault(); 11381 }); 11382 } 11383 else { 11384 $$A(this.containers.map).off("click.a.mapsvg"); 11385 } 11386 this.disableLinks = on; 11387 }
11388 setLoadingText(val) { 11389 this.options.loadingText = val; 11390 } 11391 setLockAspectRatio(onoff) { 11392 this.options.lockAspectRatio = MapSVG.parseBoolean(onoff); 11393 } 11394 setMarkerEditHandler(handler) { 11395 this.markerEditHandler = handler; 11396 } 11397 setChoroplethSourceField(field) { 11398 this.options.choropleth.sourceField = field; 11399 this.redrawChoropleth(); 11400 } 11401 setRegionEditHandler(handler) { 11402 this.regionEditHandler = handler; 11403 } 11404 setDisableAll(on) { 11405 on = MapSVG.parseBoolean(on); 11406 $$A.extend(true, this.options, { disableAll: on }); 11407 $$A(this.containers.map).toggleClass("mapsvg-disabled-regions", on); 11408 } 11409 setRegionStatuses(_statuses) { 11410 this.options.regionStatuses = {}; 11411 const colors = {}; 11412 _statuses.forEach((statusOptions) => { 11413 this.options.regionStatuses[statusOptions.value] = statusOptions; 11414 colors[statusOptions.value] = statusOptions.color.length 11415 ? statusOptions.color 11416 : undefined; 11417 }); 11418 this.setColors({ status: colors }); 11419 } 11420 setColorsIgnore(val) { 11421 this.options.colorsIgnore = MapSVG.parseBoolean(val); 11422 this.regionsRedrawColors(); 11423 } 11424 setColors(colors) { 11425 for (const i in colors) { 11426 if (i === "status") { 11427 for (const s in colors[i]) { 11428 MapSVG.fixColorHash(colors[i][s]); 11429 } 11430 } 11431 else { 11432 if (typeof colors[i] == "string") { 11433 MapSVG.fixColorHash(colors[i]); 11434 } 11435 } 11436 } 11437 $$A.extend(true, this.options, { colors: colors }); 11438 if (colors && colors.status) 11439 this.options.colors.status = colors.status; 11440 if (this.options.colors.markers) { 11441 for (const z in this.options.colors.markers) { 11442 for (const x in this.options.colors.markers[z]) { 11443 this.options.colors.markers[z][x] = parseInt(this.options.colors.markers[z][x]); 11444 } 11445 } 11446 } 11447 if (this.options.colors.background) 11448 $$A(this.containers.map).css({ background: this.options.colors.background }); 11449 if (this.options.colors.hover) { 11450 this.options.colors.hover = !isNaN(this.options.colors.hover) 11451 ? parseInt(this.options.colors.hover + "") 11452 : this.options.colors.hover; 11453 } 11454 if (this.options.colors.selected) { 11455 this.options.colors.selected = !isNaN(this.options.colors.selected) 11456 ? parseInt(this.options.colors.selected + "") 11457 : this.options.colors.selected; 11458 } 11459 $$A(this.containers.leftSidebar).css({ 11460 "background-color": this.options.colors.leftSidebar, 11461 }); 11462 $$A(this.containers.rightSidebar).css({ 11463 "background-color": this.options.colors.rightSidebar, 11464 }); 11465 $$A(this.containers.header).css({ "background-color": this.options.colors.header }); 11466 $$A(this.containers.footer).css({ "background-color": this.options.colors.footer }); 11467 if ($$A(this.containers.detailsView) && this.options.colors.detailsView !== undefined) { 11468 $$A(this.containers.detailsView).css({ 11469 "background-color": this.options.colors.detailsView, 11470 }); 11471 } 11472 if ($$A(this.containers.directory) && this.options.colors.directory !== undefined) { 11473 $$A(this.containers.directory).css({ 11474 "background-color": this.options.colors.directory, 11475 }); 11476 } 11477 if ($$A(this.containers.filtersModal) && this.options.colors.modalFilters !== undefined) { 11478 $$A(this.containers.filtersModal).css({ 11479 "background-color": this.options.colors.modalFilters, 11480 }); 11481 } 11482 if ($$A(this.containers.filters) && this.options.colors.directorySearch) { 11483 $$A(this.containers.filters).css({ 11484 "background-color": this.options.colors.directorySearch, 11485 }); 11486 } 11487 else if ($$A(this.containers.filters)) { 11488 $$A(this.containers.filters).css({ 11489 "background-color": "", 11490 }); 11491 }
11492 if (!this.containers.clustersCss) { 11493 this.containers.clustersCss = ($$A("<style></style>").appendTo("body")[0]); 11494 } 11495 let css = ""; 11496 if (this.options.colors.clusters) { 11497 css += "background-color: " + this.options.colors.clusters + ";"; 11498 } 11499 if (this.options.colors.clustersBorders) { 11500 css += "border-color: " + this.options.colors.clustersBorders + ";"; 11501 } 11502 if (this.options.colors.clustersText) { 11503 css += "color: " + this.options.colors.clustersText + ";"; 11504 } 11505 $$A(this.containers.clustersCss).html(".mapsvg-marker-cluster {" + css + "}"); 11506 if (!this.containers.clustersHoverCss) { 11507 this.containers.clustersHoverCss = ($$A("<style></style>").appendTo("body")[0]); 11508 } 11509 let cssHover = ""; 11510 if (this.options.colors.clustersHover) { 11511 cssHover += "background-color: " + this.options.colors.clustersHover + ";"; 11512 } 11513 if (this.options.colors.clustersHoverBorders) { 11514 cssHover += "border-color: " + this.options.colors.clustersHoverBorders + ";"; 11515 } 11516 if (this.options.colors.clustersHoverText) { 11517 cssHover += "color: " + this.options.colors.clustersHoverText + ";"; 11518 } 11519 $$A(this.containers.clustersHoverCss).html(".mapsvg-marker-cluster:hover {" + cssHover + "}"); 11520 if (!this.containers.markersCss) { 11521 this.containers.markersCss = $$A("<style></style>").appendTo("head")[0]; 11522 } 11523 const markerCssText = ".mapsvg-with-marker-active .mapsvg-marker {\n" + 11524 " opacity: " + 11525 this.options.colors.markers.inactive.opacity / 100 + 11526 ";\n" + 11527 " -webkit-filter: grayscale(" + 11528 (100 - this.options.colors.markers.inactive.saturation) + 11529 "%);\n" + 11530 " filter: grayscale(" + 11531 (100 - this.options.colors.markers.inactive.saturation) + 11532 "%);\n" + 11533 "}\n" + 11534 ".mapsvg-with-marker-active .mapsvg-marker-active {\n" + 11535 " opacity: " + 11536 this.options.colors.markers.active.opacity / 100 + 11537 ";\n" + 11538 " -webkit-filter: grayscale(" + 11539 (100 - this.options.colors.markers.active.saturation) + 11540 "%);\n" + 11541 " filter: grayscale(" + 11542 (100 - this.options.colors.markers.active.saturation) + 11543 "%);\n" + 11544 "}\n" + 11545 ".mapsvg-with-marker-hover .mapsvg-marker {\n" + 11546 " opacity: " + 11547 this.options.colors.markers.unhovered.opacity / 100 + 11548 ";\n" + 11549 " -webkit-filter: grayscale(" + 11550 (100 - this.options.colors.markers.unhovered.saturation) + 11551 "%);\n" + 11552 " filter: grayscale(" + 11553 (100 - this.options.colors.markers.unhovered.saturation) + 11554 "%);\n" + 11555 "}\n" + 11556 ".mapsvg-with-marker-hover .mapsvg-marker-hover {\n" + 11557 " opacity: " + 11558 this.options.colors.markers.hovered.opacity / 100 + 11559 ";\n" + 11560 " -webkit-filter: grayscale(" + 11561 (100 - this.options.colors.markers.hovered.saturation) + 11562 "%);\n" + 11563 " filter: grayscale(" + 11564 (100 - this.options.colors.markers.hovered.saturation) + 11565 "%);\n" + 11566 "}\n"; 11567 $$A(this.containers.markersCss).html(markerCssText); 11568 $$A.each(this.options.colors, (key, color) => { 11569 if (color === null || color == "") 11570 delete this.options.colors[key]; 11571 }); 11572 this.regionsRedrawColors(); 11573 } 11574 setTooltips(options) { 11575 if (options.on !== undefined) 11576 options.on = MapSVG.parseBoolean(options.on); 11577 $$A.extend(true, this.options, { tooltips: options }); 11578 if (!this.containers.tooltip) { 11579 this.containers.tooltip = $$A("<div />").addClass("mapsvg-tooltip")[0]; 11580 $$A(this.containers.map).append(this.containers.tooltip); 11581 this.controllers.tooltip = new Tooltip({ 11582 mapsvg: this, 11583 container: this.containers.tooltip, 11584 position: this.options.tooltips.position, 11585 maxWidth: this.options.tooltips.maxWidth, 11586 minWidth: this.options.tooltips.minWidth, 11587 }); 11588 this.controllers.tooltip._init(); 11589 } 11590 if (typeof this.options.tooltips.position !== "undefined") { 11591 this.controllers.tooltip.setPosition(this.options.tooltips.position); 11592 } 11593 if (typeof this.options.tooltips.maxWidth !== "undefined" || 11594 typeof this.options.tooltips.minWidth !== "undefined") { 11595 this.controllers.tooltip.setSize(this.options.tooltips.minWidth, this.options.tooltips.maxWidth); 11596 } 11597 } 11598 setPopovers(options) { 11599 if (options.on !== undefined) 11600 options.on = MapSVG.parseBoolean(options.on); 11601 $$A.extend(this.options.popovers, options); 11602 if (!this.containers.popover) { 11603 this.containers.popover = $$A("<div />").addClass("mapsvg-popover")[0]; 11604 this.layers.popovers.append(this.containers.popover); 11605 } 11606 $$A(this.containers.popover).css({ 11607 width: this.options.popovers.width + (this.options.popovers.width == "auto" ? "" : "px"), 11608 "max-width": this.options.popovers.maxWidth + "%", 11609 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 100 + 11610 "px", 11611 }); 11612 if (this.options.popovers.mobileFullscreen && MapSVG.
11612isPhone) { 11613 $$A("body").toggleClass("mapsvg-fullscreen-popovers", true); 11614 $$A(this.containers.popover).appendTo("body"); 11615 } 11616 } 11617 setRegionPrefix(prefix) { 11618 this.options.regionPrefix = prefix; 11619 } 11620 setInitialViewBox(v) { 11621 if (typeof v == "string") 11622 v = v 11623 .trim() 11624 .split(" ") 11625 .map(function (v) { 11626 return parseFloat(v); 11627 }); 11628 this._viewBox.update(new ViewBox(v)); 11629 if (this.options.googleMaps.on) { 11630 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 11631 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 11632 } 11633 this.zoomLevel = 0; 11634 this.setZoomLevels(); 11635 } 11636 setViewBoxOnStart() { 11637 this.viewBoxFull = this.svgDefault.viewBox; 11638 this.viewBoxFake = this.viewBox; 11639 this.whRatioFull = this.viewBoxFull.width / this.viewBox.width; 11640 this.containers.svg.setAttribute("viewBox", this.viewBoxFull.toString()); 11641 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11642 this.iosDownscaleFactor = this.svgDefault.viewBox.width > 9999 ? 100 : 10; 11643 this.containers.svg.style.width = 11644 (this.svgDefault.viewBox.width / this.iosDownscaleFactor).toString() + "px"; 11645 } 11646 else { 11647 this.containers.svg.style.width = this.svgDefault.viewBox.width + "px"; 11648 } 11649 this.vbStart = true; 11650 } 11651 setViewBox(viewBox, adjustGoogleMap = true) { 11652 let initial = false; 11653 if (typeof viewBox === "undefined" || (viewBox.width === 0 && viewBox.height === 0)) {
11654 viewBox = this.svgDefault.viewBox; 11655 initial = true; 11656 } 11657 const isZooming = viewBox.width != this.viewBox.width || viewBox.height != this.viewBox.height; 11658 this.viewBox.update(viewBox); 11659 this.whRatio = this.viewBox.width / this.viewBox.height; 11660 !this.vbStart && this.setViewBoxOnStart(); 11661 if (initial) { 11662 if (this._viewBox.width === 0 && this._viewBox.height === 0) { 11663 this._viewBox.update(this.viewBox); 11664 } 11665 this._scale = 1; 11666 } 11667 this.scale = this.getScale(); 11668 this.superScale = (this.whRatioFull * this.svgDefault.viewBox.width) / this.viewBox.width; 11669 const w = this.svgDefault.viewBox.width / this.containers.map.clientWidth; 11670 this.superScale = this.superScale / w; 11671 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11672 this.superScale *= this.iosDownscaleFactor; 11673 } 11674 this.scroll.tx = Math.round((this.svgDefault.viewBox.x - this.viewBox.x) * this.scale); 11675 this.scroll.ty = Math.round((this.svgDefault.viewBox.y - this.viewBox.y) * this.scale); 11676 if (this.googleMaps.map && adjustGoogleMap !== false) { 11677 const googlePrevZoom = this.googleMaps.map.getZoom(); 11678 this.googleMaps.map.setCenter(this.getCenterGeoPoint()); 11679 this.googleMaps.map.setZoom(this.getZoomForGoogle()); 11680 } 11681 else { 11682 this.containers.scrollpane.style.transform = 11683 "translate(" + this.scroll.tx + "px," + this.scroll.ty + "px)"; 11684 this.containers.svg.style.transform = "scale(" + this.superScale + ")"; 11685 this.syncZoomLevelWithGoogle(); 11686 } 11687 this.movingItemsAdjustScreenPosition(); 11688 if (isZooming) { 11689 this.adjustStrokes(); 11690 this.toggleSvgLayerOnZoom(); 11691 if (this.options.clustering.on) { 11692 this.throttle(this.clusterizeOnZoom, 400, this); 11693 } 11694 else { 11695 this.events.trigger("zoom"); 11696 } 11697 } 11698 return true; 11699 } 11700 syncZoomLevelWithGoogle() { 11701 if (this.googleMaps.map && 11702 this.googleMaps.map.getZoom() !== this.getZoomForGoogle() && 11703 typeof this.zoomDelta !== "undefined") { 11704 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11705 } 11706 } 11707 getCenterGeoPoint() { 11708 return this.converter.convertSVGToGeo(this.getCenterSvgPoint()); 11709 } 11710 getCenterSvgPoint() { 11711 return new SVGPoint(this.viewBox.x + this.viewBox.width / 2, this.viewBox.y + this.viewBox.height / 2); 11712 } 11713 getZoomForGoogle() { 11714 if (typeof this.zoomLevel === "string") { 11715 this.zoomLevel = parseInt(this.zoomLevel); 11716 } 11717 return this.zoomLevel + this.zoomDelta; 11718 } 11719 getZoomRange() { 11720 const range = { min: 0, max: 0 }; 11721 if (this.options.googleMaps.on) { 11722 range.min = Math.max(0, this.options.zoom.limit[0] + this.zoomDelta) - this.zoomDelta; 11723 range.max = Math.min(22, this.options.zoom.limit[1] + this.zoomDelta) - this.zoomDelta; 11724 } 11725 else { 11726 range.min = this.options.zoom.limit[0]; 11727 range.max = this.options.zoom.limit[1]; 11728 } 11729 return range; 11730 } 11731 enableMovingElementsAnimation() { 11732 $$A(this.containers.map).removeClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11733 } 11734 disableMovingElementsAnimation() { 11735 $$A(this.containers.map).addClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11736 } 11737 clusterizeOnZoom() { 11738 if (this.options.googleMaps.on && this.googleMaps.map && this.zoomDelta) { 11739 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11740 } 11741 this.events.trigger("zoom"); 11742 this.clusterizeMarkers(true); 11743 } 11744 throttle(method, delay, scope, params) { 11745 clearTimeout(method._tId); 11746 method._tId = setTimeout(function () { 11747 method.apply(scope, params); 11748 }, delay); 11749 }
11750 setViewBoxByGoogleMapBounds() { 11751 const googleMapBounds = this.googleMaps.map.getBounds(); 11752 if (!googleMapBounds) 11753 return; 11754 const googleMapBoundsJSON = googleMapBounds.toJSON(); 11755 if (googleMapBoundsJSON.west == -180 && googleMapBoundsJSON.east == 180) { 11756 const center = this.googleMaps.map.getCenter().toJSON(); 11757 } 11758 const ne = new GeoPoint(googleMapBounds.getNorthEast().lat(), googleMapBounds.getNorthEast().lng()); 11759 const sw = new GeoPoint(googleMapBounds.getSouthWest().lat(), googleMapBounds.getSouthWest().lng()); 11760 const xyNE = this.converter.convertGeoToSVG(ne); 11761 const xySW = this.converter.convertGeoToSVG(sw); 11762 if (xyNE.x < xySW.y) { 11763 const mapPointsWidth = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 360; 11764 xySW.x = -(mapPointsWidth - xySW.y); 11765 } 11766 const width = xyNE.x - xySW.x; 11767 const height = xySW.y - xyNE.y; 11768 const viewBox = new ViewBox(xySW.x, xyNE.y, width, height); 11769 this.setViewBox(viewBox); 11770 } 11771 redraw() { 11772 this.disableAnimation(); 11773 if (MapSVG.browser.ie) { 11774 $$A(this.containers.svg).css({ height: this.svgDefault.viewBox.height }); 11775 } 11776 if (this.options.googleMaps.on && this.googleMaps.map) { 11777 google.maps.event.trigger(this.googleMaps.map, "resize"); 11778 } 11779 else { 11780 this.setViewBox(this.viewBox); 11781 } 11782 $$A(this.containers.popover) && 11783 $$A(this.containers.popover).css({ 11784 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 11785 100 + 11786 "px", 11787 }); 11788 if (this.controllers && this.controllers.directory) { 11789 this.controllers.directory.updateTopShift(); 11790 this.controllers.directory.updateScroll(); 11791 } 11792 this.movingItemsAdjustScreenPosition(); 11793 this.adjustStrokes(); 11794 this.enableAnimation(); 11795 } 11796 setSize(width, height, responsive) { 11797 this.options.width = width; 11798 this.options.height = height; 11799 this.options.responsive = 11800 responsive != null && responsive != undefined 11801 ? MapSVG.parseBoolean(responsive) 11802 : this.options.responsive; 11803 if (!this.options.width && !this.options.height) { 11804 this.options.width = this.svgDefault.width; 11805 this.options.height = this.svgDefault.height; 11806 } 11807 else if (!this.options.width && this.options.height) { 11808 this.options.width = 11809 (this.options.height * this.svgDefault.width) / this.svgDefault.height; 11810 } 11811 else if (this.options.width && !this.options.height) { 11812 this.options.height = 11813 (this.options.width * this.svgDefault.height) / this.svgDefault.width; 11814 } 11815 this.whRatio = this.options.width / this.options.height; 11816 this.scale = this.getScale(); 11817 this.setResponsive(responsive); 11818 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 11819 this.redrawBubbles(); 11820 } 11821 this.movingItemsAdjustScreenPosition(); 11822 } 11823 setResponsive(on) { 11824 on = on != undefined ? MapSVG.parseBoolean(on) : this.options.responsive; 11825 $$A(this.containers.map).css({ 11826 width: "100%", 11827 height: "0", 11828 "padding-bottom": (this.viewBox.height * 100) / this.viewBox.width + "%", 11829 }); 11830 if (on) { 11831 $$A(this.containers.wrap).css({ 11832 width: "100%", 11833 height: "auto", 11834 }); 11835 } 11836 else { 11837 $$A(this.containers.wrap).css({ 11838 width: this.options.width + "px", 11839 height: this.options.height + "px", 11840 }); 11841 } 11842 $$A.extend(true, this.options, { responsive: on }); 11843 if (!this.resizeSensor) { 11844 this.resizeSensor = new ResizeSensor(this.containers.map, () => { 11845 this.redraw(); 11846 }); 11847 } 11848 this.redraw(); 11849 } 11850 setScroll(options, skipEvents) { 11851 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11852 options.limit != undefined && (options.limit = MapSVG.parseBoolean(options.limit)); 11853 $$A.extend(true, this.options, { scroll: options }); 11854 !skipEvents && this.setEventHandlers(); 11855 } 11856 setZoom(options) { 11857 options = options || {}; 11858 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11859 options.fingers != undefined && (options.fingers = MapSVG.parseBoolean(options.fingers)); 11860 options.mousewheel != undefined && 11861 (options.mousewheel = MapSVG.parseBoolean(options.mousewheel)); 11862 options.delta = 2; 11863 if (options.limit) { 11864 if (typeof options.limit == "string") 11865 options.limit = options.limit.split(";"); 11866 options.limit = [parseInt(options.limit[0]), parseInt(options.limit[1])]; 11867 } 11868 if (!this.zoomLevels) { 11869 this.setZoomLevels(); 11870 } 11871 $$A.extend(true, this.options, { zoom: options }); 11872 $$A(this.containers.scrollpaneWrap).off("wheel.mapsvg"); 11873 if (this.options.zoom.mousewheel) { 11874 if (MapSVG.browser.firefox) { 11875 this.firefoxScroll = { insideIframe: false, scrollX: 0, scrollY: 0 }; 11876 $$A(this.containers.scrollpaneWrap) 11877 .on("mouseenter", () => { 11878 this.firefoxScroll.insideIframe = true; 11879 this.firefoxScroll.scrollX = window.scrollX; 11880 this.firefoxScroll.scrollY = window.scrollY; 11881 }) 11882 .on("mouseleave", () => { 11883 this.firefoxScroll.insideIframe = false;
11884 }); 11885 $$A(document).scroll(() => { 11886 if (this.firefoxScroll.insideIframe) 11887 window.scrollTo(this.firefoxScroll.scrollX, this.firefoxScroll.scrollY); 11888 }); 11889 } 11890 $$A(this.containers.scrollpaneWrap).on("wheel.mapsvg", (event) => { 11891 event.preventDefault(); 11892 this.mouseWheelZoom(event); 11893 return false; 11894 }); 11895 $$A(this.layers.markers).on("wheel.mapsvg", (event) => { 11896 event.preventDefault(); 11897 this.mouseWheelZoom(event); 11898 return false; 11899 }); 11900 } 11901 this.canZoom = true; 11902 } 11903 mouseWheelZoom(event) { 11904 event.preventDefault(); 11905 const d = Math.sign(-event.originalEvent.deltaY); 11906 const center = this.getSvgPointAtClick(event.originalEvent); 11907 d > 0 ? this.zoomIn(center) : this.zoomOut(center); 11908 } 11909 setControls(options) { 11910 options = options || {}; 11911 $$A.extend(true, this.options, { controls: options }); 11912 this.options.controls.zoom = MapSVG.parseBoolean(this.options.controls.zoom); 11913 this.options.controls.zoomReset = MapSVG.parseBoolean(this.options.controls.zoomReset); 11914 this.options.controls.userLocation = MapSVG.parseBoolean(this.options.controls.userLocation); 11915 this.options.controls.previousMap = MapSVG.parseBoolean(this.options.controls.previousMap); 11916 const loc = this.options.controls.location || "right"; 11917 if (!this.containers.controls) { 11918 const buttons = $$A("<div />").addClass("mapsvg-buttons"); 11919 const zoomGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11920 const zoomIn = $$A("<div />").addClass("mapsvg-btn-map mapsvg-in"); 11921 zoomIn.on("touchend click", (e) => { 11922 if (e.cancelable) { 11923 e.preventDefault(); 11924 } 11925 e.stopPropagation(); 11926 this.zoomIn(); 11927 }); 11928 const zoomOut = $$A("<div />").addClass("mapsvg-btn-map mapsvg-out"); 11929 zoomOut.on("touchend click", (e) => { 11930 if (e.cancelable) { 11931 e.preventDefault(); 11932 } 11933 e.stopPropagation(); 11934 this.zoomOut(); 11935 }); 11936 zoomGroup.append(zoomIn).append(zoomOut); 11937 const location = $$A("<div />").addClass("mapsvg-btn-map mapsvg-btn-location"); 11938 location.on("touchend click", (e) => { 11939 if (e.cancelable) { 11940 e.preventDefault(); 11941 } 11942 e.stopPropagation(); 11943 this.showUserLocation((location) => { 11944 if (this.options.scroll.on) { 11945 this.centerOn(location.marker); 11946 } 11947 }); 11948 }); 11949 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>'; 11950 location.html(userLocationIcon); 11951 const locationGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11952 locationGroup.append(location); 11953 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>'; 11954 const zoomResetButton = $$A("<div />") 11955 .html(zoomResetIcon) 11956 .addClass("mapsvg-btn-map mapsvg-btn-zoom-reset"); 11957 zoomResetButton.on("touchend click", (e) => { 11958 if (e.cancelable) { 11959 e.preventDefault(); 11960 } 11961 e.stopPropagation(); 11962 this.viewBoxReset(true); 11963 }); 11964 const zoomResetGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11965 zoomResetGroup.append(zoomResetButton); 11966 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="">' + 11967 '<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)">' + 11968 '<g id="g4">
11968<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" ' + 11969 'id="path8" inkscape:connector-curvature="0" /></g></g></svg>'; 11970 const previousMapButton = $$A("<div />") 11971 .html(previousMapIcon) 11972 .addClass("mapsvg-btn-map mapsvg-btn-previous-map"); 11973 previousMapButton.on("touchend click", (e) => { 11974 if (e.cancelable) { 11975 e.preventDefault(); 11976 } 11977 e.stopPropagation(); 11978 this.loadPreviousMap(); 11979 }); 11980 const previousMapGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11981 previousMapGroup.append(previousMapButton); 11982 this.containers.controls = buttons[0]; 11983 this.controls = { 11984 zoom: zoomGroup[0], 11985 userLocation: locationGroup[0], 11986 zoomReset: zoomResetGroup[0], 11987 previousMap: previousMapGroup[0], 11988 }; 11989 $$A(this.containers.map).append($$A(this.containers.controls)); 11990 } 11991 $$A(this.controls.zoom).toggle(this.options.controls.zoom); 11992 $$A(this.controls.userLocation).toggle(this.options.controls.userLocation); 11993 $$A(this.controls.zoomReset).toggle(this.options.controls.zoomReset); 11994 $$A(this.controls.previousMap).toggle(this.options.controls.previousMap && this.options.previousMapsIds.length > 0); 11995 $$A(this.containers.controls).removeClass("left"); 11996 $$A(this.containers.controls).removeClass("right"); 11997 (loc == "right" && $$A(this.containers.controls).addClass("right")) || 11998 (loc == "left" && $$A(this.containers.controls).addClass("left")); 11999 } 12000 setZoomLevels() { 12001 if (!this.zoomLevels) { 12002 this.zoomLevels = new ArrayIndexed("zoomLevel"); 12003 } 12004 else { 12005 this.zoomLevels.clear(); 12006 } 12007 for (let i = -20; i < 0; i++) { 12008 const _scale = 1 / Math.pow(this.options.zoom.delta, Math.abs(i)); 12009 this.zoomLevels.push({ 12010 zoomLevel: i, 12011 _scale: _scale,
12012 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12013 }); 12014 } 12015 for (let z = 0; z <= 20; z++) { 12016 const _scale = Math.pow(this.options.zoom.delta, Math.abs(z)); 12017 this.zoomLevels.push({ 12018 zoomLevel: z, 12019 _scale: _scale, 12020 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12021 }); 12022 } 12023 } 12024 setCursor(type) { 12025 type = type == "pointer" ? "pointer" : "default"; 12026 this.options.cursor = type; 12027 if (type == "pointer") 12028 $$A(this.containers.map).addClass("mapsvg-cursor-pointer"); 12029 else 12030 $$A(this.containers.map).removeClass("mapsvg-cursor-pointer"); 12031 } 12032 setMultiSelect(on, deselect) { 12033 this.options.multiSelect = MapSVG.parseBoolean(on); 12034 if (deselect !== false) 12035 this.deselectAllRegions(); 12036 } 12037 _new_setChoropleth(options) { 12038 options = options || this.options.choropleth; 12039 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12040 if (typeof options.coloring === "undefined" || 12041 typeof options.coloring.palette === "undefined" || 12042 typeof options.coloring.palette.colors === "undefined") { 12043 if (typeof options.sourceFieldSelect === "undefined" || 12044 typeof options.sourceFieldSelect.variants === "undefined") { 12045 $$A.extend(true, this.options.choropleth, options); 12046 } 12047 else { 12048 this.options.choropleth.sourceFieldSelect.variants = 12049 options.sourceFieldSelect.variants; 12050 } 12051 } 12052 else { 12053 const paletteColorsIndexes = Object.keys(options.coloring.palette.colors); 12054 if (paletteColorsIndexes.length > 1 || 12055 (paletteColorsIndexes[0] == "0" && 12056 Object.keys(options.coloring.palette.colors[0]).length > 1)) { 12057 this.options.choropleth.coloring.palette.colors = options.coloring.palette.colors; 12058 } 12059 else { 12060 const paletteColorIndex = Object.keys(options.coloring.palette.colors)[0]; 12061 $$A.extend(true, this.options.choropleth.coloring.palette.colors[paletteColorIndex], options.coloring.palette.colors[paletteColorIndex]); 12062 } 12063 } 12064 this.updateChoroplethMinMax(); 12065 if (this.options.choropleth.on && 12066 this.options.choropleth.sourceFieldSelect.on && 12067 this.options.choropleth.sourceFieldSelect.variants) { 12068 if (!this.containers.choroplethSourceSelect) { 12069 const sourceSelectOptions = []; 12070 this.options.choropleth.sourceFieldSelect.variants.forEac
12070h((variant) => { 12071 sourceSelectOptions.push($$A('<option value="' + 12072 variant + 12073 '" ' + 12074 (variant === this.options.choropleth.sourceField 12075 ? "selected" 12076 : "") + 12077 ">" + 12078 variant + 12079 "</option>")); 12080 }); 12081 this.containers.choroplethSourceSelect = { 12082 container: $$A('<div class="mapsvg-choropleth-source-field"></div>')[0], 12083 select: $$A('<select id="mapsvg-choropleth-source-field-select" class="mapsvg-select2"></select>')[0], 12084 options: sourceSelectOptions, 12085 }; 12086 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12087 $$A(this.containers.choroplethSourceSelect.container).append($$A(this.containers.choroplethSourceSelect.select)); 12088 $$A(this.containers.map).append($$A(this.containers.choroplethSourceSelect.container)); 12089 $$A(this.containers.choroplethSourceSelect.select).mselect2(); 12090 $$A(this.containers.choroplethSourceSelect.select) 12091 .mselect2() 12092 .on("select2:select select2:unselecting", (e) => { 12093 if (e.cancelable) { 12094 e.preventDefault(); 12095 } 12096 e.stopPropagation(); 12097 this.setChoropleth({ sourceField: $$A(e.target).mselect2().val() }); 12098 }); 12099 } 12100 else { 12101 $$A(this.containers.choroplethSourceSelect.select).mselect2("destroy"); 12102 $$A(this.containers.choroplethSourceSelect.select).find("option").remove(); 12103 this.containers.choroplethSourceSelect.options = []; 12104 this.options.choropleth.sourceFieldSelect.variants.forEac
12104h((variant) => { 12105 this.containers.choroplethSourceSelect.options.push($$A('<option value="' + 12106 variant + 12107 '" ' + 12108 (variant === this.options.choropleth.sourceField 12109 ? "selected" 12110 : "") + 12111 ">" + 12112 variant + 12113 "</option>")[0]); 12114 }); 12115 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12116 $$A(this.containers.choroplethSourceSelect.select).mselect2({ width: "100%" }); 12117 } 12118 } 12119 if ((!this.options.choropleth.on || !this.options.choropleth.sourceFieldSelect.on) && 12120 this.containers.choroplethSourceSelect && 12121 $$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12122 $$A(this.containers.choroplethSourceSelect.container).hide(); 12123 } 12124 else if (this.options.choropleth.on && 12125 this.options.choropleth.sourceFieldSelect.on && 12126 this.containers.choroplethSourceSelect && 12127 !$$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12128 $$A(this.containers.choroplethSourceSelect.container).show(); 12129 } 12130 $$A(this.containers.map).find(".mapsvg-choropleth-legend").remove(); 12131 if (this.options.choropleth.on && this.options.choropleth.coloring.legend.on) { 12132 const legend = this.options.choropleth.coloring.legend; 12133 let coloring = ""; 12134 if (this.options.choropleth.coloring.mode === "gradient") { 12135 coloring += 12136 '<div class="mapsvg-choropleth-legend-gradient-no-data">' + 12137 this.options.choropleth.coloring.noData.description + 12138 "</div>"; 12139 let legendGradient = ""; 12140 for (let chunkIdx = 1; chunkIdx < 5; chunkIdx++) { 12141 legendGradient += 12142 '<div class="mapsvg-choropleth-legend-gradient-chunk">' + 12143 ((this.options.choropleth.coloring.gradient.values.maxAdjusted * chunkIdx) / 12144 5 + 12145 this.options.choropleth.coloring.gradient.values.min) + 12146 "</div>"; 12147 } 12148 coloring += 12149 '<div class="mapsvg-choropleth-legend-gradient-colors">' + 12150 legendGradient + 12151 "</div>"; 12152 } 12153 else { 12154 coloring += 12155 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="no-data">' + 12156 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12157 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12158 this.options.choropleth.coloring.noData.description + 12159 "</div>" + 12160 "</div>"; 12161 coloring += 12162 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="out-of-range">' + 12163 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12164 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12165 this.options.choropleth.coloring.palette.outOfRange.description + 12166 "</div>" + 12167 "</div>"; 12168 const paletteColors = this.options.choropleth.coloring.palette.colors; 12169 paletteColors.forEach((paletteColor, idx) => { 12170 let paletteColorElementText = ""; 12171 if (paletteColor.description) { 12172 paletteColorElementText = paletteColor.description; 12173 } 12174 else { 12175 if (idx === 0 && !paletteColor.valueFrom && paletteColor.valueFrom !== 0) { 12176 if (legend.layout === "vertical") { 12177 paletteColorElementText = "Less then " + paletteColor.valueTo; 12178 } 12179 else { 12180 paletteColorElementText = "< " + paletteColor.valueTo; 12181 } 12182 } 12183 else if (idx === paletteColors.length - 1 && !paletteColor.valueTo) { 12184 if (legend.layout === "vertical") { 12185 paletteColorElementText = paletteColor.valueFrom + " or more"; 12186 } 12187 else { 12188 paletteColorElementText = paletteColor.valueFrom + " <"; 12189 } 12190 } 12191 else { 12192 paletteColorElementText = 12193 paletteColor.valueFrom + " ≤ " + paletteColor.valueTo; 12194 } 12195 } 12196 coloring += 12197 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="' + 12198 idx + 12199 '">' + 12200 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12201 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12202 paletteColorElementText + 12203 "</div>" + 12204 "</div>"; 12205 }); 12206 } 12207 this.containers.legend = { 12208 title: $$A('<div class="mapsvg-choropleth-legend-title">' + legend.title + "</div>")[0], 12209 text: $$A('<div class="mapsvg-choropleth-legend-text">' + legend.text + "</div>")[0], 12210 coloring: $$A('<div class="mapsvg-choropleth-legend-' + 12211 this.options.choropleth.coloring.mode + 12212 '">' + 12213 coloring + 12214 "</div>")[0], 12215 description: $$A('<div class="mapsvg-choropleth-legend-description">' + 12216 legend.description + 12217 "</div>")[0], 12218 container: $$A("<div />").addClass("mapsvg-choropleth-legend mapsvg-choropleth-legend-" + 12219 legend.layout + 12220 " mapsvg-choropleth-legend-container-" + 12221 legend.container)[0], 12222 }; 12223 $$A(this.containers.legend.container) 12224 .append(this.containers.legend.title) 12225 .append(this.containers.legend.text) 12226 .append(this.containers.legend.coloring) 12227 .append(this.containers.legend.description); 12228 $$A(this.containers.map).append(this.containers.legend.container); 12229 this.setChoroplethLegendCSS(); 12230 this.regionsRepository.events.on("updated", () => { 12231 this.redrawChoropleth(); 12232 }); 12233 this.objectsRepository.events.on("updated", () => { 12234 this.redrawChoropleth(); 12235 }); 12236 } 12237 if (this.options.choropleth.on && this.options.choropleth.coloring.mode === "gradient") { 12238 const colors = this.options.choropleth.coloring.gradient.colors; 12239 if (colors) { 12240 colors.lowRGB = tinycolor(colors.low).toRgb(); 12241 colors.highRGB = tinycolor(colors.high).toRgb(); 12242 colors.diffRGB = { 12243 r: colors.highRGB.r - colors.lowRGB.r, 12244 g: colors.highRGB.g - colors.lowRGB.g, 12245 b: colors.highRGB.b - colors.lowRGB.b, 12246 a: colors.highRGB.a - colors.lowRGB.a, 12247 }; 12248 this.containers.legend && this.setChoroplethLegendCSS(); 12249 } 12250 } 12251 this.redrawChoropleth(); 12252 } 12253 redrawChoropleth() { 12254 this.updateChoroplethMinMax(); 12255 this.redrawBubbles(); 12256 this.regionsRedrawColors(); 12257 } 12258 updateChoroplethMinMax() { 12259 if (this.options.choropleth.on) { 12260 const gradient = this.options.choropleth.coloring.gradient, values = []; 12261 gradient.values.min = 0; 12262 gradient.values.max = null; 12263 if (this.options.choropleth.source === "regions") { 12264 this.regions.forEach((region) => { 12265 const choropleth = region.data && region.data[this.options.choropleth.sourceField]; 12266 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12267 }); 12268 } 12269 else {
12270 this.objectsRepository.objects.forEach((object) => { 12271 const choropleth = object[this.options.choropleth.sourceField]; 12272 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12273 }); 12274 } 12275 if (values.length > 0) { 12276 gradient.values.min = Math.min.apply(null, values); 12277 gradient.values.max = Math.max.apply(null, values); 12278 gradient.values.maxAdjusted = gradient.values.max - gradient.values.min; 12279 } 12280 } 12281 } 12282 setChoroplethLegendCSS() { 12283 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; 12284 $$A(".mapsvg-choropleth-legend").css({ 12285 width: legend.width, 12286 height: legend.height, 12287 }); 12288 if (this.options.choropleth.coloring.mode === "gradient") { 12289 if (legend.layout === "horizontal") { 12290 $$A(".mapsvg-choropleth-legend-horizontal .mapsvg-choropleth-legend-gradient-colors").css({ 12291 background: "linear-gradient(to right," + 12292 gradient.colors.low + 12293 " 1%," + 12294 gradient.colors.high + 12295 " 100%)", 12296 }); 12297 } 12298 else { 12299 $$A(".mapsvg-choropleth-legend-vertical .mapsvg-choropleth-legend-gradient-colors").css({ 12300 background: "linear-gradient(to bottom," + 12301 gradient.colors.low + 12302 " 1%," + 12303 gradient.colors.high + 12304 " 100%)", 12305 }); 12306 } 12307 $$A(".mapsvg-choropleth-legend-gradient-no-data").css({ 12308 "background-color": noData.color, 12309 }); 12310 } 12311 else { 12312 const paletteColors = this.options.choropleth.coloring.palette.colors; 12313 paletteColors.forEach(function (paletteColor, idx) { 12314 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="' + 12315 idx + 12316 '"] .mapsvg-choropleth-legend-palette-color').css({ 12317 "background-color": paletteColor.color, 12318 }); 12319 }); 12320 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="no-data"] .mapsvg-choropleth-legend-palette-color').css({ 12321 "background-color": noData.color, 12322 }); 12323 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="out-of-range"] .mapsvg-choropleth-legend-palette-color').css({ 12324 "background-color": outOfRange.color, 12325 }); 12326 } 12327 } 12328 setCss(css) { 12329 this.options.css = 12330 css || (this.options.css ? this.options.css.replace(/%id%/g, "" + this.id) : ""); 12331 this.liveCss = this.liveCss || $$A("<style></style>").appendTo("head")[0]; 12332 $$A(this.liveCss).html(this.options.css); 12333 } 12334 setFilters(options) { 12335 options = options || this.options.filters; 12336 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12337 options.hide != undefined && (options.hide = MapSVG.parseBoolean(options.hide)); 12338 $$A.extend(true, this.options, { filters: options }); 12339 if (!MapSVG.googleMapsApiLoaded && 12340 this.options.filters.on && 12341 this.filtersSchema.getField("distance")) { 12342 this.loadGoogleMapsAPI(() => { 12343 return 1; 12344 }, () => { 12345 return 1; 12346 }); 12347 } 12348 if (["leftSidebar", "rightSidebar", "header", "footer", "custom", "map"].indexOf(this.options.filters.location) === -1) { 12349 this.options.filters.location = "leftSidebar"; 12350 } 12351 if (this.options.filters.on) { 12352 if (this.formBuilder) { 12353 this.formBuilder.destroy(); 12354 } 12355 if (!this.containers.filters) { 12356 this.containers.filters = $$A('<div class="mapsvg-filters-wrap"></div>')[0]; 12357 } 12358 else { 12359 $$A(this.containers.filters).empty(); 12360 $$A(this.containers.filters).show(); 12361 } 12362 $$A(this.containers.filters).css({ 12363 "background-color": this.options.colors.directorySearch, 12364 }); 12365 if ($$A(this.containers.filtersModal)) { 12366 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 12367 } 12368 if (this.options.filters.location === "custom") { 12369 $$A(this.containers.filters) 12370 .removeClass("mapsvg-filter-container-custom") 12371 .addClass("mapsvg-filter-container-custom"); 12372 if ($$A("#" + this.options.filters.containerId).length) { 12373 $$A("#" + this.options.filters.containerId).append(this.containers.filters); 12374 } 12375 else { 12376 $$A(this.containers.filters).hide(); 12377 console.error("MapSVG: filter container #" + 12378 this.options.filters.containerId + 12379 " does not exists"); 12380 } 12381 } 12382 else { 12383 if (MapSVG.isPhone) { 12384 $$A(this.containers.header).append($$A(this.containers.filters)); 12385 this.setContainers({ header: { on: true } }); 12386 } 12387 else { 12388 const location = MapSVG.isPhone ? "header" : this.options.filters.location; 12389 if (this.options.menu.on && 12390 this.controllers.directory && 12391 this.options.menu.location === this.options.filters.location) { 12392 $$A(this.controllers.directory.containers.view) 12393 .find(".mapsvg-directory-filter-wrap") 12394 .append($$A(this.containers.filters)); 12395 this.controllers.directory.updateTopShift(); 12396 } 12397 else { 12398 $$A(this.containers[location]).append($$A(this.containers.filters)); 12399 this.controllers.directory && this.controllers.directory.updateTopShift(); 12400 } 12401 } 12402 } 12403 this.loadFiltersController(this.containers.filters, false); 12404 this.updateFiltersState(); 12405 } 12406 else { 12407 if ($$A(this.containers.filters)) { 12408 $$A(this.containers.filters).empty(); 12409 $$A(this.containers.filters).hide(); 12410 } 12411 } 12412 if (this.options.menu.on && 12413 this.controllers.directory && 12414 this.options.menu.location === this.options.filters.location) { 12415 this.controllers.directory.updateTopShift(); 12416 } 12417 } 12418 updateFiltersState() { 12419 if (this.options.filters && this.options.filters.on && this.controllers.filters) { 12420 this.controllers.filters.update(this.objectsRepository.query); 12421 this.updateFilterTags(); 12422 } 12423 } 12424 setGlobalDistanceFilter() { 12425 if (this.objectsRepository && 12426 this.objectsRepository.query.filters && 12427 this.objectsRepository.query.filters.distance) { 12428 const dist = this.objectsRepository.query.filters.distance; 12429 MapSVG.distanceSearch = this.objectsRepository.query.filters.distance; 12430 } 12431 else { 12432 MapSVG.distanceSearch = null; 12433 } 12434 } 12435 updateFilterTags() { 12436 $$A(this.containers.filterTags) && $$A(this.containers.filterTags).empty(); 12437 for (const field_name in this.objectsRepository.query.filters) { 12438 let field_value = this.objectsRepository.query.filters[field_name]; 12439 let _field_name = field_name; 12440 const filterField = this.filtersSchema.getField(_field_name); 12441 if (field_name == "regions") { 12442 _field_name = ""; 12443 field_value = field_value.region_ids.map((id) => this.getRegion(id).title); 12444 } 12445 else { 12446 _field_name = filterField && filterField.label; 12447 } 12448 if (field_name !== "distance") { 12449 if (!this.containers.filterTags) { 12450 this.containers.filterTags = $$A('<div class="mapsvg-filter-tags"></div>')[0]; 12451 if ($$A(this.containers.filters)) ; 12452 else { 12453 if (this.options.menu.on && this.controllers.directory) { 12454 $$A(this.controllers.directory.containers.toolbar).append(this.containers.filterTags); 12455 this.controllers.directory.updateTopShift(); 12456 } 12457 else { 12458 $$A(this.containers.map).append(this.containers.filterTags); 12459 if (this.options.zoom.buttons.on) { 12460 if (this.options.layersControl.on) { 12461 if (this.options.layersControl.position == "top-left") { 12462 $$A(this.containers.filterTags).css({ 12463 right: 0, 12464 bottom: 0, 12465 }); 12466 } 12467 else { 12468 $$A(this.containers.filterTags).css({ 12469 bottom: 0, 12470 }); 12471 } 12472 } 12473 else { 12474 if (this.options.zoom.buttons.location == "left") { 12475 $$A(this.containers.filterTags).css({ 12476 right: 0, 12477 }); 12478 } 12479 } 12480 } 12481 } 12482 } 12483 $$A(this.containers.filterTags).on("click", ".mapsvg-filter-delete", (e) => { 12484 const filterField = $$A(e.target).data("filter"); 12485 $$A(e.target).parent().remove(); 12486 this.objectsRepository.query.removeFilter(filterField); 12487 this.deselectAllRegions(); 12488 this.loadDataObjects(); 12489 }); 12490 } 12491 $$A(this.containers.filterTags).append('<div class="mapsvg-filter-tag">' + 12492 (_field_name ? _field_name + ": " : "") + 12493 field_value + 12494 ' <span class="mapsvg-filter-delete" data-filter="' + 12495 field_name + 12496 '">
12496Ã</span></div>'); 12497 } 12498 } 12499 } 12500 setContainers(options) { 12501 const _this = this; 12502 if (!this.containersCreated) { 12503 this.containers.wrapAll = document.createElement("div"); 12504 this.containers.wrapAll.classList.add("mapsvg-wrap-all"); 12505 this.containers.wrapAll.id = "mapsvg-map-" + this.id; 12506 this.containers.wrapAll.setAttribute("data-map-id", this.id ? this.id.toString() : ""); 12507 this.containers.wrap = document.createElement("div"); 12508 this.containers.wrap.classList.add("mapsvg-wrap"); 12509 this.containers.mapContainer = document.createElement("div"); 12510 this.containers.mapContainer.classList.add("mapsvg-map-container"); 12511 this.containers.leftSidebar = document.createElement("div"); 12512 this.containers.leftSidebar.className = 12513 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"; 12514 this.containers.rightSidebar = document.createElement("div"); 12515 this.containers.rightSidebar.className = 12516 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"; 12517 this.containers.header = document.createElement("div"); 12518 this.containers.header.className = "mapsvg-header mapsvg-top-container"; 12519 this.containers.footer = document.createElement("div"); 12520 this.containers.footer.className = "mapsvg-footer mapsvg-top-container"; 12521 _this.containers.wrapAll = $$A('<div class="mapsvg-wrap-all"></div>') 12522 .attr("id", "mapsvg-map-" + this.id) 12523 .attr("data-map-id", this.id)[0]; 12524 _this.containers.wrap = $$A('<div class="mapsvg-wrap"></div>')[0]; 12525 _this.containers.mapContainer = $$A('<div class="mapsvg-map-container"></div>')[0]; 12526 _this.containers.leftSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"></div>')[0]; 12527 _this.containers.rightSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"></div>')[0]; 12528 _this.containers.header = $$A('<div class="mapsvg-header mapsvg-top-container"></div>')[0]; 12529 _this.containers.footer = $$A('<div class="mapsvg-footer mapsvg-top-container"></div>')[0]; 12530 $$A(_this.containers.wrapAll).insertBefore(_this.containers.map); 12531 $$A(_this.containers.wrapAll).append(_this.containers.header); 12532 $$A(_this.containers.wrapAll).append(_this.containers.wrap); 12533 $$A(_this.containers.wrapAll).append(_this.containers.footer); 12534 $$A(_this.containers.mapContainer).append(_this.containers.map); 12535 $$A(_this.containers.wrap).append(_this.containers.leftSidebar); 12536 $$A(_this.containers.wrap).append(_this.containers.mapContainer); 12537 $$A(_this.containers.wrap).append(_this.containers.rightSidebar); 12538 _this.containersCreated = true; 12539 } 12540 options = options || _this.options.containers || {}; 12541 for (const contName in options) { 12542 if (options[contName].on !== undefined) { 12543 options[contName].on = MapSVG.parseBoolean(options[contName].on); 12544 } 12545 if (options[contName].width) { 12546 if (typeof options[contName].width != "string" || 12547 (options[contName].width.indexOf("px") === -1 && 12548 options[contName].width.indexOf("%") === -1 && 12549 options[contName].width !== "auto")) { 12550 options[contName].width = options[contName].width + "px"; 12551 } 12552 $$A(_this.containers[contName]).css({ "flex-basis": options[contName].width }); 12553 } 12554 if (options[contName].height) { 12555 if (typeof options[contName].height != "string" || 12556 (options[contName].height.indexOf("px") === -1 && 12557 options[contName].height.indexOf("%") === -1 && 12558 options[contName].height !== "auto")) { 12559 options[contName].height = options[contName].height + "px"; 12560 } 12561 $$A(_this.containers[contName]).css({ 12562 "flex-basis": options[contName].height, 12563 height: options[contName].height, 12564 }); 12565 } 12566 $$A.extend(true, _this.options, { containers: options }); 12567 let on = _this.options.containers[contName].on; 12568 if (MapSVG.isPhone && 12569 _this.options.menu.hideOnMobile && 12570 _this.options.menu.location === contName && 12571 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12572 on = false;
12573 } 12574 else if (MapSVG.isPhone && 12575 _this.options.menu.location === "custom" && 12576 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12577 on = false; 12578 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12579 } 12580 else if (MapSVG.isPhone && 12581 !_this.options.menu.hideOnMobile && 12582 _this.options.menu.location === contName && 12583 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12584 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12585 $$A(_this.containers.wrapAll).addClass("mapsvg-directory-visible"); 12586 } 12587 $$A(_this.containers[contName]).toggle(on); 12588 } 12589 _this.setDetailsView(); 12590 } 12591 shouldBeScrollable(container) { 12592 const _this = this; 12593 switch (container) { 12594 case "map": 12595 case "leftSidebar": 12596 case "rightSidebar": 12597 return true; 12598 case "custom": 12599 return false; 12600 case "header": 12601 case "footer": 12602 if (_this.options.containers[container].height && 12603 _this.options.containers[container].height !== "auto" && 12604 _this.options.containers[container].height !== "100%") { 12605 return true; 12606 } 12607 else { 12608 return false; 12609 } 12610 default: 12611 return false; 12612 } 12613 } 12614 setDirectory(options) { 12615 return this.setMenu(options); 12616 } 12617 setMenu(options) { 12618 options = options || this.options.menu; 12619 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12620 options.search != undefined && (options.search = MapSVG.parseBoolean(options.search)); 12621 options.showMapOnClick != undefined && 12622 (options.showMapOnClick = MapSVG.parseBoolean(options.showMapOnClick)); 12623 options.searchFallback != undefined && 12624 (options.searchFallback = MapSVG.parseBoolean(options.searchFallback)); 12625 options.customContainer != undefined && 12626 (options.customContainer = MapSVG.parseBoolean(options.customContainer)); 12627 $$A.extend(true, this.options, { menu: options }); 12628 this.controllers = this.controllers || {}; 12629 if (!this.containers.directory) { 12630 this.containers.directory = $$A('<div class="mapsvg-directory"></div>')[0]; 12631 } 12632 $$A(this.containers.directory).toggleClass("flex", this.shouldBeScrollable(this.options.menu.location)); 12633 if (this.options.menu.on) { 12634 if (!this.controllers.directory) { 12635 this.controllers.directory = new DirectoryController({ 12636 container: this.containers.directory, 12637 template: this.options.templates.directory, 12638 mapsvg: this, 12639 repository: this.options.menu.source === "regions" 12640 ? this.regionsRepository 12641 : this.objectsRepository, 12642 scrollable: this.shouldBeScrollable(this.options.menu.location), 12643 events: { 12644 click: (e, regionOrObject, mapsvg) => { 12645 this.events.trigger("click.directoryItem", this, [ 12646 e, 12647 regionOrObject, 12648 mapsvg, 12649 ]); 12650 }, 12651 mouseover: (e, regionOrObject, mapsvg) => { 12652 this.events.trigger("mouseover.directoryItem", this, [ 12653 e, 12654 regionOrObject, 12655 mapsvg, 12656 ]); 12657 }, 12658 mouseout: (e, regionOrObject, mapsvg) => { 12659 this.events.trigger("mouseout.directoryItem", this, [ 12660 e, 12661 regionOrObject, 12662 mapsvg, 12663 ]); 12664 }, 12665 }, 12666 }); 12667 this.controllers.directory._init(); 12668 } 12669 if (options.source) { 12670 this.controllers.directory.repository = 12671 this.options.menu.source === "regions" 12672 ? this.regionsRepository 12673 : this.objectsRepository; 12674 } 12675 if (options.sortBy || options.sortDirection) { 12676 this.controllers.directory.repository.query.update({ 12677 sort: [ 12678 { 12679 field: this.options.menu.sortBy, 12680 order: this.options.menu.sortDirection, 12681 }, 12682 ], 12683 }); 12684 } 12685 if (options.filterout) { 12686 const f = {}; 12687 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 12688 this.controllers.directory.repository.query.setFilterOut(f); 12689 } 12690 if (options.location) { 12691 this.controllers.directory.scrollable = this.shouldBeScrollable(this.options.menu.location); 12692 } 12693 let $container; 12694 if (MapSVG.isPhone && this.options.menu.hideOnMobile) { 12695 $container = $$A(this.containers.leftSidebar); 12696 } 12697 else { 12698 $container = 12699 this.options.menu.location !== "custom" 12700 ? $$A(this.containers[this.options.menu.location]) 12701 : $$A("#" + this.options.menu.containerId); 12702 } 12703 $container.append(this.containers.directory); 12704 if (this.options.colors.directory) { 12705 $$A(this.containers.directory).css({ 12706 "background-color": this.options.colors.directory, 12707 }); 12708 } 12709 this.setFilters(); 12710 this.setTemplates({ directoryItem: this.options.templates.directoryItem }); 12711 if ((this.options.menu.source === "regions" && this.regionsRepository.loaded) || 12712 (this.options.menu.source === "database" && this.objectsRepository.loaded)) { 12713 if (this.editMode && 12714 (options.sortBy || options.sortDirection || options.filterout)) { 12715 this.controllers.directory.repository.reload(); 12716 } 12717 this.loadDirectory(); 12718 } 12719 } 12720 else { 12721 this.controllers.directory && this.controllers.directory.destroy(); 12722 this.controllers.directory = null; 12723 } 12724 } 12725 setDatabase(options) { 12726 options = options || this.options.database; 12727 if (options.pagination) { 12728 if (options.pagination.on != undefined) { 12729 options.pagination.on = MapSVG.parseBoolean(options.pagination.on); 12730 } 12731 if (options.pagination.perpage != undefined) { 12732 options.pagination.perpage = parseInt(options.pagination.perpage); 12733 } 12734 } 12735 $$A.extend(true, this.options, { database: options }); 12736 if (options.pagination) { 12737 if (options.pagination.on !== undefined || options.pagination.perpage) { 12738 const query = new Query({ 12739 perpage: this.options.database.pagination.on 12740 ? this.options.database.pagination.perpage 12741 : 0, 12742 }); 12743 this.objectsRepository.find(query); 12744 } 12745 else { 12746 this.setPagination(); 12747 } 12748 } 12749 } 12750 updateGoogleMapsMaxZoom(geoPoint) { 12751 this.googleMaps.maxZoomService.getMaxZoomAtLatLng(geoPoint, (result) => { 12752 if (result.status === "OK") { 12753 this.googleMaps.currentMaxZoom = result.zoom; 12754 } 12755 }); 12756 } 12757 setGoogleMaps(options) { 12758 options = options || this.options.googleMaps; 12759 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12760 if (!this.googleMaps) { 12761 this.googleMaps = { loaded: false, initialized: false, map: null, overlay: null }; 12762 } 12763 $$A.extend(true, this.options, { googleMaps: options }); 12764 if (this.options.googleMaps.on) { 12765 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12766 if (!MapSVG.googleMapsApiLoaded) { 12767 this.loadGoogleMapsAPI(() => { 12768 this.setGoogleMaps(); 12769 }, () => { 12770 this.setGoogleMaps({ on: false }); 12771 }); 12772 } 12773 else { 12774 if (!this.googleMaps.map) { 12775 this.containers.googleMaps = $$A('<div class="mapsvg-layer mapsvg-layer-gm" id="mapsvg-google-maps-' + 12776 this.id + 12777 '"></div>').prependTo(this.containers.map)[0]; 12778 $$A(this.containers.googleMaps).css({ 12779 position: "absolute", 12780 top: 0, 12781 left: 0, 12782 bottom: 0, 12783 right: 0, 12784 "z-index": "0", 12785 }); 12786 this.googleMaps.map = new google.maps.Map(this.containers.googleMaps, { 12787 mapTypeId: options.type, 12788 fullscreenControl: false, 12789 keyboardShortcuts: false, 12790 mapTypeControl: false, 12791 scaleControl: false, 12792 scrollwheel: false, 12793 streetViewControl: false, 12794 zoomControl: false, 12795 styles: options.styleJSON, 12796 tilt: 0, 12797 }); 12798 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 12799 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 12800 const bounds = new google.maps.LatLngBounds(southWest, northEast);
12801 this.googleMaps.overlay = this.createGoogleMapOverlay(bounds, this.googleMaps.map); 12802 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 12803 this.googleMaps.map.fitBounds(bounds, 0); 12804 } 12805 else { 12806 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 12807 this.googleMaps.map.setCenter(this.options.googleMaps.center); 12808 } 12809 this.googleMaps.initialized = true; 12810 this.googleMaps.maxZoomService = new google.maps.MaxZoomService(); 12811 this.googleMaps.map.addListener("idle", () => { 12812 this.isZooming = false; 12813 }); 12814 google.maps.event.addListenerOnce(this.googleMaps.map, "idle", () => { 12815 setTimeout(() => { 12816 $$A(this.containers.map).addClass("mapsvg-fade-in"); 12817 setTimeout(() => { 12818 $$A(this.containers.map).removeClass("mapsvg-google-map-loading"); 12819 $$A(this.containers.map).removeClass("mapsvg-fade-in"); 12820 if (!this.options.googleMaps.center || 12821 !this.options.googleMaps.zoom) { 12822 this.options.googleMaps.center = this.googleMaps.map 12823 .getCenter() 12824 .toJSON(); 12825 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 12826 } 12827 this.zoomDelta = this.options.googleMaps.zoom - this.zoomLevel; 12828 this.updateGoogleMapsMaxZoom(this.options.googleMaps.center); 12829 this.setInitialViewBox(this.viewBox); 12830 this.toggleSvgLayerOnZoom(); 12831 this.events.trigger("googleMapsLoaded"); 12832 this.afterLoadBlockers--; 12833 this.finalizeMapLoading(); 12834 }, 300); 12835 }, 1); 12836 }); 12837 this.events.on("googleMapsBoundsChanged", (bounds) => { 12838 this.setViewBoxByGoogleMapsOverlay(); 12839 }); 12840 } 12841 else { 12842 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12843 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).show(); 12844 if (options.type) { 12845 this.googleMaps.map.setMapTypeId(options.type); 12846 } 12847 this.setViewBoxByGoogleMapsOverlay(); 12848 } 12849 } 12850 } 12851 else { 12852 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", false); 12853 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).hide(); 12854 this.googleMaps.initialized = false; 12855 } 12856 if (this.converter) { 12857 this.converter.setWorldShift(this.options.googleMaps.on); 12858 } 12859 } 12860 createGoogleMapOverlay(bounds, map) { 12861 class GoogleMapsOverlay extends google.maps.OverlayView { 12862 constructor(bounds, googleMapInstance, mapsvg) { 12863 super(); 12864 this.bounds_ = bounds; 12865 this.map_ = googleMapInstance; 12866 this.mapsvg = mapsvg; 12867 this.setMap(googleMapInstance); 12868 this.prevCoords = { 12869 sw: { x: 0, y: 0 }, 12870 sw2: { x: 0, y: 0 }, 12871 ne: { x: 0, y: 0 }, 12872 ne2: { x: 0, y: 0 }, 12873 }; 12874 } 12875 draw() { 12876 this.mapsvg.events.trigger("googleMapsBoundsChanged", this.map_, [ 12877 this.getPixelBounds(), 12878 this.map_, 12879 ]); 12880 } 12881 onAdd() { 12882 this.element = document.createElement("div"); 12883 this.element.style.borderStyle = "none"; 12884 this.element.style.borderWidth = "0px"; 12885 this.element.style.position = "absolute"; 12886 const panes = this.getPanes(); 12887 panes.overlayLayer.appendChild(this.element); 12888 } 12889 getPixelBounds() { 12890 const overlayProjection = this.getProjection(); 12891 if (!overlayProjection) 12892 return;
12893 const geoSW = this.bounds_.getSouthWest(); 12894 const geoNE = this.bounds_.getNorthEast(); 12895 const coords = { 12896 sw: overlayProjection.fromLatLngToDivPixel(geoSW), 12897 ne: overlayProjection.fromLatLngToDivPixel(geoNE), 12898 sw2: overlayProjection.fromLatLngToContainerPixel(geoSW), 12899 ne2: overlayProjection.fromLatLngToContainerPixel(geoNE), 12900 }; 12901 const ww = overlayProjection.getWorldWidth(); 12902 if (this.prevCoords.sw) { 12903 if (coords.ne.x < coords.sw.x) { 12904 if (Math.abs(this.prevCoords.sw.x - coords.sw.x) > 12905 Math.abs(this.prevCoords.ne.x - coords.ne.x)) { 12906 coords.sw.x = coords.sw.x - ww; 12907 } 12908 else { 12909 coords.ne.x = coords.ne.x + ww; 12910 } 12911 if (Math.abs(this.prevCoords.sw2.x - coords.sw2.x) > 12912 Math.abs(this.prevCoords.ne2.x - coords.ne2.x)) { 12913 coords.sw2.x = coords.sw2.x - ww; 12914 } 12915 else { 12916 coords.ne2.x = coords.ne2.x + ww; 12917 } 12918 } 12919 } 12920 this.prevCoords = coords; 12921 return { sw: coords.sw2, ne: coords.ne2 }; 12922 } 12923 } 12924 return new GoogleMapsOverlay(bounds, map, this); 12925 } 12926 loadGoogleMapsAPI(callback, fail) { 12927 if (window.google !== undefined && google.maps) { 12928 MapSVG.googleMapsApiLoaded = true; 12929 } 12930 if (MapSVG.googleMapsApiLoaded) { 12931 if (typeof callback == "function") { 12932 callback(); 12933 } 12934 return; 12935 } 12936 MapSVG.googleMapsLoadCallbacks = MapSVG.googleMapsLoadCallbacks || []; 12937 if (typeof callback == "function") { 12938 MapSVG.googleMapsLoadCallbacks.push(callback); 12939 } 12940 if (MapSVG.googleMapsApiIsLoading) { 12941 return; 12942 } 12943 MapSVG.googleMapsApiIsLoading = true; 12944 window.gm_authFailure = () => { 12945 if (MapSVG.GoogleMapBadApiKey) { 12946 MapSVG.GoogleMapBadApiKey(); 12947 } 12948 else { 12949 if (this.editMode) { 12950 alert("Google maps API key is incorrect."); 12951 } 12952 else { 12953 console.error("MapSVG: Google maps API key is incorrect."); 12954 } 12955 } 12956 }; 12957 this.googleMapsScript = document.createElement("script"); 12958 this.googleMapsScript.onload = () => { 12959 MapSVG.googleMapsApiLoaded = true; 12960 MapSVG.googleMapsLoadCallbacks.forEach((_callback) => { 12961 if (typeof callback == "function") 12962 _callback(); 12963 }); 12964 }; 12965 const gmLibraries = []; 12966 if (this.options.googleMaps.drawingTools) { 12967 gmLibraries.push("drawing"); 12968 } 12969 if (this.options.googleMaps.geometry) { 12970 gmLibraries.push("geometry"); 12971 } 12972 let libraries = ""; 12973 if (gmLibraries.length > 0) { 12974 libraries = "&libraries=" + gmLibraries.join(","); 12975 } 12976 this.googleMapsScript.src = 12977 "https://maps.googleapis.com/maps/api/js?language=" + 12978 this.options.googleMaps.language + 12979 "&key=" + 12980 this.options.googleMaps.apiKey + 12981 libraries; 12982 document.head.appendChild(this.googleMapsScript); 12983 } 12984 loadDetailsView(obj) { 12985 this.controllers.popover && this.controllers.popover.close(); 12986 if (this.controllers.detailsView) 12987 this.controllers.detailsView.destroy(); 12988 this.controllers.detailsView = new DetailsController({ 12989 autoresize: MapSVG.isPhone && 12990 this.options.detailsView.mobileFullscreen && 12991 this.options.detailsView.location !== "custom" 12992 ? false 12993 : this.options.detailsView.autoresize, 12994 container: this.containers.detailsView, 12995 template: obj instanceof Region 12996 ? this.options.templates.detailsViewRegion 12997 : this.options.templates.detailsView, 12998 mapsvg: this, 12999 data: obj.getData(), 13000 modal: MapSVG.isPhone && 13001 this.options.detailsView.mobileFullscreen && 13002 this.options.detailsView.location !== "custom", 13003 scrollable: (MapSVG.isPhone && 13004 this.options.detailsView.mobileFullscreen && 13005 this.options.detailsView.location !== "custom") || 13006 this.shouldBeScrollable(this.options.detailsView.location), 13007 withToolbar: !(MapSVG.isPhone && 13008 this.options.detailsView.mobileFullscreen && 13009 this.options.detailsView.location !== "custom") && this.shouldBeScrollable(this.options.detailsView.location), 13010 events: { 13011 shown: (detailsController) => { 13012 this.events.trigger("shown.detailsView", this, [this, detailsController]); 13013 $$A(window).trigger("shown.detailsView", [this, detailsController]); 13014 }, 13015 closed: (detailsController) => { 13016 this.deselectAllRegions(); 13017 this.deselectAllMarkers(); 13018 this.controllers && 13019 this.controllers.directory && 13020 this.controllers.directory.deselectItems(); 13021 this.events.trigger("closed.detailsView", [this, detailsController]); 13022 }, 13023 }, 13024 }); 13025 this.controllers.detailsView._init(); 13026 } 13027 loadFiltersModal() { 13028 if (this.options.filters.modalLocation != "custom") { 13029 if (!this.containers.filtersModal) { 13030 this.containers.filtersModal = $$A('<div class="mapsvg-details-container mapsvg-filters-wrap"></div>')[0]; 13031 } 13032 this.setColors(); 13033 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 13034 if (MapSVG.isPhone) { 13035 $$A("body").append($$A(this.containers.filtersModal)); 13036 $$A(this.containers.filtersModal).css({ width: "" }); 13037 } 13038 else { 13039 $$A(this.containers[this.options.filters.modalLocation]).append($$A(this.containers.filtersModal)); 13040 } 13041 } 13042 else { 13043 this.containers.filtersModal = $$A("#" + this.options.filters.containerId)[0]; 13044 $$A(this.containers.filtersModal).css({ width: "" }); 13045 } 13046 this.loadFiltersController(this.containers.filtersModal, true); 13047 } 13048 loadFiltersController(container, modal = false) { 13049 if (!this.filtersShouldBeShown()) { 13050 return; 13051 } 13052 let filtersInDirectory, filtersHide; 13053 if (MapSVG.isPhone) { 13054 filtersInDirectory = true; 13055 filtersHide = this.options.filters.hideOnMobile; 13056 } 13057 else { 13058 filtersInDirectory = 13059 this.options.menu.on && 13060 this.controllers.directory && 13061 this.options.menu.location === this.options.filters.location; 13062 filtersHide = this.options.filters.hide; 13063 } 13064 const scrollable = modal || 13065 (!filtersInDirectory && 13066 ["leftSidebar", "rightSidebar"].indexOf(this.options.filters.location) !== -1); 13067 this.filtersRepository = 13068 this.options.filters.source === "regions" 13069 ? this.regionsRepository 13070 : this.objectsRepository; 13071 if (this.options.filters.searchButton) { 13072 this.changedFields = null; 13073 this.changedSearch = null; 13074 } 13075 else { 13076 this.changedSearch = () => { 13077 this.filtersRepository.query.searchFallback = this.filtersSchema.getFieldByType("search").searchFallback; 13078 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13079 }; 13080 this.changedFields = () => { 13081 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13082 }; 13083 } 13084 this.controllers.filters = new FiltersController({ 13085 container: container, 13086 query: this.filtersRepository.query, 13087 mapsvg: this, 13088 schema: this.filtersSchema, 13089 template: '<div class="mapsvg-filters-container"></div>', 13090 scrollable: scrollable, 13091 modal: modal, 13092 withToolbar: MapSVG.isPhone ? false : modal, 13093 width: $$A(container).hasClass("mapsvg-map-container") 13094 ? this.options.filters.width 13095 : "100%", 13096 hide: this.options.filters.hide, 13097 hideOnMobile: this.options.filters.hideOnMobile, 13098 showButtonText: this.options.filters.showButtonText, 13099 clearButton: this.options.filters.clearButton, 13100 clearButtonText: this.options.filters.clearButtonText, 13101 searchButton: this.options.filters.searchButton, 13102 searchButtonText: this.options.filters.searchButtonText, 13103 padding: this.options.filters.padding, 13104 events: { 13105 cleared: () => { 13106 this.deselectAllRegions(); 13107 this.filtersRepository.reload(); 13108 }, 13109 "changed.fields": this.changedFields, 13110 "changed.search": this.changedSearch, 13111 "click.btn.searchButton": () => { 13112 this.filtersRepository.reload(); 13113 }, 13114 loaded: () => { 13115 this.controllers.directory && this.controllers.directory.updateTopShift(); 13116 this.afterLoadBlockers--; 13117 this.finalizeMapLoading(); 13118 }, 13119 "click.btn.showFilters": () => { 13120 this.loadFiltersModal(); 13121 }, 13122 }, 13123 }); 13124 this.controllers.filters._init(); 13125 } 13126 filtersShouldBeShown() { 13127 return (this.options.filters.on && 13128 this.options.filtersSchema && 13129 this.options.filtersSchema.length > 0); 13130 } 13131 textSearch(text, fallback = false) { 13132 const query = new Query({ 13133 filters: { search: text }, 13134 searchFallback: fallback, 13135 }); 13136 this.filtersRepository.find(query); 13137 } 13138 getRegion(id) { 13139 return this.regions.findById(id); 13140 } 13141 getRegions() { 13142 return this.regions; 13143 } 13144 getMarker(id) { 13145 return this.markers.findById(id); 13146 } 13147 checkId(id) { 13148 if (this.getRegion(id)) 13149 return { canUse: false, error: "This ID is already being used by a Region" }; 13150 else if (this.getMarker(id)) 13151 return { canUse: false, error: "This ID is already being used by another Marker" }; 13152 else 13153 return { canUse: true, error: "" }; 13154 } 13155 regionsRedrawColors() { 13156 this.regions.forEach((region) => { 13157 region.setFill(); 13158 }); 13159 } 13160 redrawBubbles() { 13161 $$A(this.containers.map).removeClass("bubbles-regions-on bubbles-database-on"); 13162 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 13163 $$A(this.containers.map).addClass("bubbles-" + this.options.choropleth.source + "-on"); 13164 } 13165 this.regions.forEach(function (region) { 13166 region.drawBubble(); 13167 }); 13168 const markersBubbleMode = this.options.choropleth.on && 13169 this.options.choropleth.source == "database" && 13170 this.options.choropleth.bubbleMode;
13171 this.markers.forEach(function (marker) { 13172 marker.setBubbleMode(markersBubbleMode); 13173 }); 13174 } 13175 destroy() { 13176 if (this.controllers && this.controllers.directory) { 13177 this.controllers.directory.mobileButtons.remove(); 13178 } 13179 $$A(this.containers.map) 13180 .empty() 13181 .insertBefore($$A(this.containers.wrapAll)) 13182 .attr("style", "") 13183 .removeClass("mapsvg mapsvg-responsive"); 13184 this.controllers.popover && this.controllers.popover.close(); 13185 if (this.controllers.detailsView) 13186 this.controllers.detailsView.destroy(); 13187 $$A(this.containers.wrapAll).remove(); 13188 } 13189 getData() { 13190 return { 13191 id: this.id, 13192 title: this.options.title, 13193 options: this.getOptions(false, false), 13194 }; 13195 } 13196 mayBeFitMarkers() { 13197 if (!this.lastTimeFitWas) { 13198 this.lastTimeFitWas = Date.now() - 99999; 13199 } 13200 this.fitDelta = Date.now() - this.lastTimeFitWas; 13201 if (this.fitDelta > 1000 && 13202 !this.firstDataLoad && 13203 !this.fitOnDataLoadDone && 13204 this.options.fitMarkers) { 13205 this.fitMarkers(); 13206 this.fitOnDataLoadDone = true; 13207 } 13208 if (this.firstDataLoad && 13209 (this.options.fitMarkersOnStart || 13210 (this.options.fitMarkers && this.options.database.loadOnStart === false))) { 13211 this.firstDataLoad = false; 13212 if (this.options.googleMaps.on && !this.googleMaps.map) { 13213 this.events.on("googleMapsLoaded", () => { 13214 this.fitMarkers(); 13215 }); 13216 } 13217 else { 13218 this.fitMarkers(); 13219 } 13220 } 13221 this.lastTimeFitWas = Date.now(); 13222 } 13223 fitMarkers() { 13224 const dbObjects = this.objectsRepository.getLoaded(); 13225 if (!dbObjects || dbObjects.length === 0) { 13226 return; 13227 } 13228 if (this.options.googleMaps.on && typeof google !== "undefined") { 13229 const lats = []; 13230 const lngs = []; 13231 if (dbObjects.length > 1) { 13232 dbObjects.forEach((object) => { 13233 if (object.location && object.location.geoPoint) { 13234 lats.push(object.location.geoPoint.lat); 13235 lngs.push(object.location.geoPoint.lng); 13236 } 13237 }); 13238 const minlat = Math.min.apply(null, lats), maxlat = Math.max.apply(null, lats); 13239 const minlng = Math.min.apply(null, lngs), maxlng = Math.max.apply(null, lngs); 13240 const bbox = new google.maps.LatLngBounds({ lat: minlat, lng: minlng }, { lat: maxlat, lng: maxlng }); 13241 this.googleMaps.map.fitBounds(bbox, 0); 13242 } 13243 else { 13244 if (dbObjects[0].location && 13245 dbObjects[0].location.geoPoint.lat && 13246 dbObjects[0].location.geoPoint.lng) { 13247 const coords = { 13248 lat: dbObjects[0].location.geoPoint.lat, 13249 lng: dbObjects[0].location.geoPoint.lng, 13250 }; 13251 if (this.googleMaps.map) { 13252 this.googleMaps.map.setCenter(coords); 13253 this.googleMaps.map.setZoom(this.options.fitSingleMarkerZoom); 13254 } 13255 } 13256 } 13257 } 13258 else { 13259 if (this.options.clustering.on) { 13260 const arr = []; 13261 this.markersClusters.forEach((c) => { 13262 arr.push(c); 13263 }); 13264 this.markers.forEach((m) => { 13265 arr.push(m); 13266 }); 13267 this.zoomTo(arr); 13268 return; 13269 } 13270 else { 13271 this.zoomTo(this.markers); 13272 return; 13273 } 13274 } 13275 } 13276 setFitSingleMarkerZoom(zoom) { 13277 this.options.fitSingleMarkerZoom = parseInt(zoom); 13278 } 13279 showUserLocation(callback) { 13280 this.getUserLocation((geoPoint) => { 13281 this.userLocation = null; 13282 this.userLocation = new Location({ 13283 geoPoint: geoPoint, 13284 img: MapSVG.urls.root + "/markers/user-location.svg", 13285 }); 13286 this.userLocationMarker && this.userLocationMarker.delete(); 13287 this.userLocationMarker = new Marker({ 13288 location: this.userLocation, 13289 mapsvg: this, 13290 width: 15, 13291 height: 15, 13292 }); 13293 $$A(this.userLocationMarker.element).addClass("mapsvg-user-location"); 13294 this.userLocationMarker.centered = true; 13295 this.getLayer("markers").append(this.userLocationMarker.element); 13296 this.userLocationMarker.adjustScreenPosition(); 13297 callback && callback(this.userLocation); 13298 }); 13299 } 13300 getUserLocation(callback) { 13301 if (navigator.geolocation) { 13302 navigator.geolocation.getCurrentPosition(function (position) { 13303 const pos = new GeoPoint(position.coords.latitude, position.coords.longitude); 13304 callback && callback(pos); 13305 }); 13306 } 13307 else { 13308 return false;
13309 } 13310 } 13311 getScale() { 13312 const scale2 = this.containers.map.clientWidth / this.viewBox.width; 13313 return scale2 || 1; 13314 } 13315 getViewBox() { 13316 return this.viewBox; 13317 } 13318 viewBoxSetBySize(width, height) { 13319 this.setSize(width, height); 13320 this._viewBox.update(this.viewBoxGetBySize(width, height)); 13321 this.setViewBox(this._viewBox); 13322 $$A(window).trigger("resize"); 13323 this.setSize(width, height); 13324 this.setZoomLevels(); 13325 return this.viewBox; 13326 } 13327 viewBoxGetBySize(width, height) { 13328 const new_ratio = width / height; 13329 const old_ratio = this.svgDefault.viewBox.width / this.svgDefault.viewBox.height; 13330 const vb = this.svgDefault.viewBox.clone(); 13331 if (new_ratio != old_ratio) { 13332 if (new_ratio > old_ratio) { 13333 vb.width = this.svgDefault.viewBox.height * new_ratio; 13334 vb.x = this.svgDefault.viewBox.x - (vb.width - this.svgDefault.viewBox.width) / 2; 13335 } 13336 else { 13337 vb.height = this.svgDefault.viewBox.width / new_ratio; 13338 vb.y = this.svgDefault.viewBox.y - (vb.height - this.svgDefault.viewBox.height) / 2; 13339 } 13340 } 13341 return vb; 13342 }
13343 viewBoxReset(toInitial) { 13344 if (this.options.googleMaps.on && this.googleMaps.map) { 13345 if (!toInitial) { 13346 this.options.googleMaps.center = null; 13347 this.options.googleMaps.zoom = null; 13348 } 13349 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 13350 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 13351 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 13352 const bounds = new google.maps.LatLngBounds(southWest, northEast); 13353 this.googleMaps.map.fitBounds(bounds, 0); 13354 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 13355 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 13356 } 13357 else { 13358 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 13359 this.googleMaps.map.setCenter(this.options.googleMaps.center); 13360 } 13361 } 13362 else { 13363 if (toInitial) { 13364 const v = this._viewBox || this.svgDefault.viewBox; 13365 this.zoomLevel = 0; 13366 this._scale = 1; 13367 this.setViewBox(v); 13368 } 13369 else { 13370 this.setViewBox(); 13371 } 13372 } 13373 return this.viewBox; 13374 } 13375 getGeoViewBox() { 13376 const v = this.viewBox; 13377 const p1 = new SVGPoint(v.x, v.y); 13378 const p2 = new SVGPoint(v.x + v.width, v.y); 13379 const p3 = new SVGPoint(v.x, v.y); 13380 const p4 = new SVGPoint(v.x, v.y + v.height); 13381 const leftLon = this.converter.convertSVGToGeo(p1).lng; 13382 const rightLon = this.converter.convertSVGToGeo(p2).lng; 13383 const topLat = this.converter.convertSVGToGeo(p3).lat; 13384 const bottomLat = this.converter.convertSVGToGeo(p4).lat; 13385 return [leftLon, topLat, rightLon, bottomLat]; 13386 } 13387 setStrokes() { 13388 $$A(this.containers.svg) 13389 .find("path, polygon, circle, ellipse, rect, line, polyline") 13390 .each((index, elem) => { 13391 const width = MapObject.getComputedStyle("stroke-width", elem); 13392 if (width) { 13393 $$A(elem).attr("data-stroke-width", width.replace("px", "")); 13394 } 13395 }); 13396 } 13397 adjustStrokes() { 13398 $$A(this.containers.svg) 13399 .find("path, polygon, circle, ellipse, rect, line, polyline") 13400 .each((index, elem) => { 13401 const width = elem.getAttribute("data-stroke-width"); 13402 if (width) { 13403 $$A(elem).css("stroke-width", Number(width) / this.scale); 13404 } 13405 }); 13406 } 13407 zoomIn(center) { 13408 if (this.canZoom) { 13409 this.isZooming = true; 13410 this.canZoom = false;
13411 setTimeout(() => { 13412 this.isZooming = false; 13413 this.canZoom = true; 13414 }, 700); 13415 this.zoom(1, center); 13416 } 13417 } 13418 zoomOut(center) { 13419 if (this.canZoom) { 13420 this.isZooming = true; 13421 this.canZoom = false; 13422 setTimeout(() => { 13423 this.isZooming = false; 13424 this.canZoom = true; 13425 }, 700); 13426 this.zoom(-1, center); 13427 } 13428 } 13429 zoomTo(mapObjects, zoomToLevel) { 13430 if (mapObjects instanceof Marker || mapObjects instanceof MarkerCluster) { 13431 return this.zoomToMarkerOrCluster(mapObjects, zoomToLevel); 13432 } 13433 else { 13434 const convertedObjects = !Array.isArray(mapObjects) ? [mapObjects] : mapObjects; 13435 const bbox = this.getGroupBBox(convertedObjects); 13436 return this.fitViewBox(bbox, zoomToLevel); 13437 } 13438 } 13439 zoomToMarkerOrCluster(mapObject, zoomToLevel) { 13440 this.zoomLevel = zoomToLevel || 1; 13441 const foundZoomLevel = this.zoomLevels.get(this.zoomLevel); 13442 if (!foundZoomLevel) { 13443 return false; 13444 } 13445 const vb = foundZoomLevel.viewBox; 13446 if (this.canZoom) { 13447 this.isZooming = true; 13448 this.canZoom = false;
13449 setTimeout(() => { 13450 this.isZooming = false; 13451 this.canZoom = true; 13452 }, 700); 13453 const vbNew = new ViewBox(mapObject.svgPoint.x - vb.width / 2, mapObject.svgPoint.y - vb.height / 2, vb.width, vb.height); 13454 this.setViewBox(vbNew); 13455 this._scale = foundZoomLevel._scale; 13456 return true; 13457 } 13458 return false; 13459 } 13460 getGroupBBox(mapObjects) { 13461 let _bbox; 13462 const xmax = []; 13463 const ymax = []; 13464 const xmin = []; 13465 const ymin = []; 13466 for (let i = 0; i < mapObjects.length; i++) { 13467 _bbox = mapObjects[i].getBBox(); 13468 xmin.push(_bbox.x); 13469 ymin.push(_bbox.y); 13470 const _w = _bbox.x + _bbox.width; 13471 const _h = _bbox.y + _bbox.height; 13472 xmax.push(_w); 13473 ymax.push(_h); 13474 } 13475 const _xmin = Math.min(...xmin); 13476 const _ymin = Math.min(...ymin); 13477 const width = Math.max(...xmax) - _xmin; 13478 const height = Math.max(...ymax) - _ymin; 13479 let padding = 10; 13480 const point1 = new ScreenPoint(padding, 0); 13481 const point2 = new ScreenPoint(0, 0); 13482 padding = 13483 this.converter.convertPixelToSVG(point1).x - this.converter.convertPixelToSVG(point2).x; 13484 return new ViewBox(_xmin - padding, _ymin - padding, width + padding * 2, height + padding * 2); 13485 } 13486 fitViewBox(fitViewBox, forceZoomLevel) { 13487 let viewBoxPrev; 13488 let foundZoomLevelNumber = 0; 13489 let foundZoomLevel; 13490 let newViewBox;
13491 this.zoomLevels.forEach((zoomLevel) => { 13492 if (viewBoxPrev && viewBoxPrev.x !== undefined) { 13493 if (fitViewBox.fitsInViewBox(viewBoxPrev) && 13494 zoomLevel.viewBox.fitsInViewBox(fitViewBox, true)) { 13495 foundZoomLevelNumber = forceZoomLevel ? forceZoomLevel : zoomLevel.zoomLevel; 13496 foundZoomLevel = this.zoomLevels.get(foundZoomLevelNumber); 13497 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); 13498 } 13499 } 13500 viewBoxPrev = zoomLevel && zoomLevel.viewBox; 13501 }); 13502 if (foundZoomLevel) { 13503 if (this.canZoom) { 13504 this.isZooming = true; 13505 this.canZoom = false; 13506 setTimeout(() => { 13507 this.isZooming = false; 13508 this.canZoom = true; 13509 }, 700); 13510 this.zoomLevel = foundZoomLevelNumber; 13511 this._scale = foundZoomLevel._scale; 13512 this.setViewBox(newViewBox); 13513 return true; 13514 } 13515 } 13516 else { 13517 return false; 13518 } 13519 } 13520 zoomToRegion(region, zoomToLevel) { 13521 this.fitViewBox(region.getBBox(), zoomToLevel); 13522 return true; 13523 } 13524 centerOn(region, yShift) { 13525 if (this.options.googleMaps.on) { 13526 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13527 $$A(this.containers.map).addClass("scrolling"); 13528 const latLng = region.getCenterLatLng(yShift); 13529 this.googleMaps.map.panTo(latLng); 13530 setTimeout(() => { 13531 $$A(this.containers.map).removeClass("scrolling"); 13532 }, 100); 13533 } 13534 else { 13535 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13536 const bbox = region.getBBox(); 13537 const vb = this.viewBox; 13538 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); 13539 this.setViewBox(newViewBox); 13540 } 13541 } 13542 zoom(delta, center) { 13543 let newViewBox = new ViewBox(0, 0, 0, 0); 13544 const d = delta > 0 ? 1 : -1; 13545 if (!this.zoomLevels.get(this.zoomLevel + d)) 13546 return;
13547 const newZoomLevel = this.zoomLevel + d; 13548 const zoomIn = d > 0; 13549 const zoomOut = d < 0; 13550 const zoomRange = this.getZoomRange(); 13551 const isInZoomRange = this.zoomLevel >= zoomRange.min && this.zoomLevel <= zoomRange.max; 13552 const goingOutOfZoomRange = isInZoomRange && (newZoomLevel > zoomRange.max || newZoomLevel < zoomRange.min); 13553 const outOfRangeAndMovingAway = !isInZoomRange && 13554 ((zoomIn && newZoomLevel > zoomRange.max) || (zoomOut && newZoomLevel < zoomRange.min)); 13555 if (goingOutOfZoomRange || outOfRangeAndMovingAway) { 13556 return; 13557 } 13558 this.zoomLevel = newZoomLevel; 13559 const z = this.zoomLevels.get(this.zoomLevel); 13560 this._scale = z._scale; 13561 newViewBox = z.viewBox; 13562 let shift = []; 13563 if (center) { 13564 const koef = zoomIn ? 0.5 : -1; 13565 newViewBox.x = this.viewBox.x + (center.x - this.viewBox.x) * koef; 13566 newViewBox.y = this.viewBox.y + (center.y - this.viewBox.y) * koef; 13567 } 13568 else { 13569 shift = [ 13570 (this.viewBox.width - newViewBox.width) / 2, 13571 (this.viewBox.height - newViewBox.height) / 2, 13572 ]; 13573 newViewBox.x = this.viewBox.x + shift[0]; 13574 newViewBox.y = this.viewBox.y + shift[1]; 13575 } 13576 this.shiftViewBoxToScrollBoundaries(newViewBox); 13577 this.setViewBox(newViewBox); 13578 } 13579 toggleSvgLayerOnZoom() { 13580 if (this.options.googleMaps.on && 13581 this.googleMaps.map && 13582 this.options.zoom.hideSvg && 13583 this.googleMaps.map.getZoom() >= this.options.zoom.hideSvgZoomLevel) { 13584 if (!$$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13585 $$A(this.containers.svg).animate({ opacity: 0 }, 400, "linear", () => { 13586 $$A(this.containers.svg).addClass("mapsvg-invisible"); 13587 }); 13588 } 13589 } 13590 else { 13591 if ($$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13592 $$A(this.containers.svg).animate({ opacity: 1 }, 400, "linear", () => { 13593 $$A(this.containers.svg).removeClass("mapsvg-invisible"); 13594 }); 13595 } 13596 } 13597 } 13598 shiftViewBoxToScrollBoundaries(newViewBox) { 13599 if (this.options.scroll.limit) { 13600 if (newViewBox.x < this.svgDefault.viewBox.x) 13601 newViewBox.x = this.svgDefault.viewBox.x; 13602 else if (newViewBox.x + newViewBox.width > 13603 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13604 newViewBox.x = 13605 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - newViewBox.width; 13606 if (newViewBox.y < this.svgDefault.viewBox.y) 13607 newViewBox.y = this.svgDefault.viewBox.y; 13608 else if (newViewBox.y + newViewBox.height > 13609 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13610 newViewBox.y = 13611 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height - newViewBox.height; 13612 } 13613 return newViewBox; 13614 } 13615 markerDelete(marker) { 13616 if (this.editingMarker && this.editingMarker.id == marker.id) { 13617 this.unsetEditingMarker(); 13618 } 13619 if (this.markers.findById(marker.id)) { 13620 this.markers.delete(marker.id); 13621 } 13622 marker.delete(); 13623 marker = null; 13624 if (this.markers.length === 0) 13625 this.options.markerLastID = 0; 13626 } 13627 markersClusterAdd(markersCluster) { 13628 this.layers.markers.append(markersCluster.elem); 13629 this.markersClusters.push(markersCluster); 13630 markersCluster.adjustScreenPosition(); 13631 } 13632 markerAdd(marker) { 13633 $$A(marker.element).hide(); 13634 marker.adjustScreenPosition(); 13635 this.layers.markers.append(marker.element); 13636 this.markers.push(marker); 13637 marker.mapped = true; 13638 setTimeout(function () { 13639 $$A(marker.element).show(); 13640 }, 100); 13641 } 13642 markerRemove(marker) { 13643 if (this.editingMarker && this.editingMarker.id == marker.id) { 13644 this.editingMarker = null; 13645 delete this.editingMarker; 13646 } 13647 if (this.markers.findById(marker.id)) { 13648 this.markers.findById(marker.id).element.remove(); 13649 this.markers.delete(marker.id); 13650 marker = null; 13651 } 13652 if (this.markers.length === 0) 13653 this.options.markerLastID = 0; 13654 } 13655 markerId() { 13656 this.options.markerLastID = this.options.markerLastID + 1; 13657 const id = "marker_" + this.options.markerLastID; 13658 if (this.getMarker(id)) 13659 return this.markerId(); 13660 else 13661 return id; 13662 } 13663 movingItemsAdjustScreenPosition() { 13664 this.markersAdjustScreenPosition(); 13665 this.popoverAdjustScreenPosition(); 13666 this.bubblesRegionsAdjustScreenPosition(); 13667 this.labelsRegionsAdjustScreenPosition(); 13668 } 13669 movingItemsMoveScreenPositionBy(deltaX, deltaY) { 13670 this.markersMoveScreenPositionBy(deltaX, deltaY); 13671 this.popoverMoveScreenPositionBy(deltaX, deltaY); 13672 this.bubblesRegionsMoveScreenPositionBy(deltaX, deltaY); 13673 this.labelsRegionsMoveScreenPositionBy(deltaX, deltaY); 13674 } 13675 labelsRegionsAdjustScreenPosition() { 13676 if ($$A(this.containers.map).is(":visible")) { 13677 this.regions.forEach(function (region) { 13678 region.adjustLabelScreenPosition(); 13679 }); 13680 } 13681 } 13682 bubblesRegionsAdjustScreenPosition() { 13683 if ($$A(this.containers.map).is(":visible")) { 13684 this.regions.forEach(function (region) { 13685 region.adjustBubbleScreenPosition(); 13686 }); 13687 } 13688 } 13689 labelsRegionsMoveScreenPositionBy(deltaX, deltaY) { 13690 if ($$A(this.containers.map).is(":visible")) { 13691 this.regions.forEach(function (region) { 13692 region.moveLabelScreenPositionBy(deltaX, deltaY); 13693 }); 13694 } 13695 } 13696 bubblesRegionsMoveScreenPositionBy(deltaX, deltaY) { 13697 if ($$A(this.containers.map).is(":visible")) { 13698 this.regions.forEach((region) => { 13699 region.moveBubbleScreenPositionBy(deltaX, deltaY); 13700 }); 13701 } 13702 } 13703 markersAdjustScreenPosition() {
13704 this.markers.forEach((marker) => { 13705 marker.adjustScreenPosition(); 13706 }); 13707 this.markersClusters.forEach((cluster) => { 13708 cluster.adjustScreenPosition(); 13709 }); 13710 if (this.userLocationMarker) { 13711 this.userLocationMarker.adjustScreenPosition(); 13712 } 13713 } 13714 markersMoveScreenPositionBy(deltaX, deltaY) { 13715 this.markers.forEach((marker) => { 13716 marker.moveSrceenPositionBy(deltaX, deltaY); 13717 }); 13718 this.markersClusters.forEach((cluster) => { 13719 cluster.moveSrceenPositionBy(deltaX, deltaY); 13720 }); 13721 if (this.userLocationMarker) { 13722 this.userLocationMarker.moveSrceenPositionBy(deltaX, deltaY); 13723 } 13724 } 13725 setEditingMarker(marker) { 13726 this.editingMarker = marker; 13727 if (!this.editingMarker.mapped) { 13728 this.editingMarker.needToRemove = true; 13729 this.markerAdd(this.editingMarker); 13730 } 13731 } 13732 unsetEditingMarker() { 13733 if (this.editingMarker && this.editingMarker.needToRemove) { 13734 this.markerRemove(this.editingMarker); 13735 } 13736 this.editingMarker = null; 13737 } 13738 getEditingMarker() { 13739 return this.editingMarker; 13740 } 13741 scrollStart(e, mapsvg) { 13742 if ($$A(e.target).hasClass("mapsvg-btn-map") || 13743 $$A(e.target).closest(".mapsvg-choropleth").length) 13744 return; 13745 if (this.editMarkers.on && $$A(e.target).hasClass("mapsvg-marker")) 13746 return; 13747 e.preventDefault(); 13748 $$A(this.containers.map).addClass("no-transitions"); 13749 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13750 ? e.originalEvent.touches[0] 13751 : e; 13752 this.scrollStarted = true; 13753 this.scroll = { 13754 tx: this.scroll.tx || 0, 13755 ty: this.scroll.ty || 0, 13756 vxi: this.viewBox.x, 13757 vyi: this.viewBox.y, 13758 x: ce.clientX, 13759 y: ce.clientY, 13760 dx: 0, 13761 dy: 0, 13762 vx: 0, 13763 vy: 0, 13764 gx: ce.clientX, 13765 gy: ce.clientY, 13766 touchScrollStart: 0, 13767 }; 13768 if (e.type.indexOf("mouse") === 0) { 13769 $$A(document).on("mousemove.scroll.mapsvg", (e) => { 13770 this.scrollMove(e); 13771 }); 13772 if (this.options.scroll.spacebar) { 13773 $$A(document).on("keyup.scroll.mapsvg", (e) => { 13774 if (e.keyCode == 32) { 13775 this.scrollEnd(e, mapsvg); 13776 } 13777 }); 13778 } 13779 else { 13780 $$A(document).on("mouseup.scroll.mapsvg", (e) => { 13781 this.scrollEnd(e, mapsvg); 13782 }); 13783 } 13784 } 13785 } 13786 scrollMove(e) { 13787 e.preventDefault(); 13788 if (!this.isScrolling) { 13789 this.isScrolling = true; 13790 $$A(this.containers.map).addClass("scrolling"); 13791 } 13792 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13793 ? e.originalEvent.touches[0] 13794 : e; 13795 this.panBy(this.scroll.gx - ce.clientX, this.scroll.gy - ce.clientY); 13796 this.scroll.gx = ce.clientX; 13797 this.scroll.gy = ce.clientY; 13798 this.scroll.dx = this.scroll.x - ce.clientX; 13799 this.scroll.dy = this.scroll.y - ce.clientY; 13800 let vx = this.scroll.vxi + this.scroll.dx / this.scale; 13801 let vy = this.scroll.vyi + this.scroll.dy / this.scale; 13802 if (this.options.scroll.limit) { 13803 if (vx < this.svgDefault.viewBox.x) 13804 vx = this.svgDefault.viewBox.x; 13805 else if (this.viewBox.width + vx > 13806 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13807 vx = this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - this.viewBox.width; 13808 if (vy < this.svgDefault.viewBox.y) 13809 vy = this.svgDefault.viewBox.y; 13810 else if (this.viewBox.height + vy > 13811 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13812 vy = 13813 this.svgDefault.viewBox.y + 13814 this.svgDefault.viewBox.height - 13815 this.viewBox.height; 13816 } 13817 this.scroll.vx = vx; 13818 this.scroll.vy = vy; 13819 } 13820 scrollEnd(e, mapsvg, noClick) { 13821 setTimeout(() => { 13822 this.enableAnimation(); 13823 this.scrollStarted = false;
13824 this.isScrolling = false; 13825 }, 100); 13826 if (this.googleMaps && this.googleMaps.overlay) { 13827 this.googleMaps.overlay.draw(); 13828 } 13829 $$A(this.containers.map).removeClass("scrolling"); 13830 $$A(document).off("keyup.scroll.mapsvg"); 13831 $$A(document).off("mousemove.scroll.mapsvg"); 13832 $$A(document).off("mouseup.scroll.mapsvg"); 13833 if (noClick !== true && Math.abs(this.scroll.dx) < 5 && Math.abs(this.scroll.dy) < 5) { 13834 if (this.editMarkers.on) 13835 this.clickAddsMarker && this.markerAddClickHandler(e); 13836 else if (this.objectClickedBeforeScroll) 13837 if (this.objectClickedBeforeScroll instanceof Marker) { 13838 this.markerClickHandler(e, this.objectClickedBeforeScroll); 13839 } 13840 else if (this.objectClickedBeforeScroll instanceof Region) { 13841 this.regionClickHandler(e, this.objectClickedBeforeScroll); 13842 } 13843 else if (this.objectClickedBeforeScroll instanceof MarkerCluster) { 13844 this.markerClusterClickHandler(e, this.objectClickedBeforeScroll); 13845 } 13846 } 13847 this.viewBox.x = this.scroll.vx || this.viewBox.x; 13848 this.viewBox.y = this.scroll.vy || this.viewBox.y; 13849 } 13850 setViewBoxByGoogleMapsOverlay() { 13851 const bounds = this.googleMaps.overlay.getPixelBounds(); 13852 const scale = (bounds.ne.x - bounds.sw.x) / this.svgDefault.viewBox.width; 13853 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); 13854 this.setViewBox(vb, false); 13855 } 13856 panBy(x, y) { 13857 let tx = this.scroll.tx - x; 13858 let ty = this.scroll.ty - y; 13859 const scrolled = { x: true, y: true }; 13860 if (this.options.scroll.limit) { 13861 const svg = $$A(this.containers.svg)[0].getBoundingClientRect(); 13862 const bounds = $$A(this.containers.map)[0].getBoundingClientRect(); 13863 if ((svg.left - x > bounds.left && x < 0) || (svg.right - x < bounds.right && x > 0)) { 13864 tx = this.scroll.tx; 13865 scrolled.x = false; 13866 } 13867 if ((svg.top - y > bounds.top && y < 0) || (svg.bottom - y < bounds.bottom && y > 0)) { 13868 ty = this.scroll.ty; 13869 scrolled.y = false; 13870 } 13871 } 13872 $$A(this.containers.scrollpane).css({ 13873 transform: "translate(" + tx + "px," + ty + "px)", 13874 }); 13875 this.scroll.tx = tx; 13876 this.scroll.ty = ty; 13877 if (scrolled.x || scrolled.y) { 13878 const moveX = scrolled.x ? x : 0; 13879 const moveY = scrolled.y ? y : 0; 13880 this.movingItemsMoveScreenPositionBy(moveX, moveY); 13881 if (this.googleMaps.map) { 13882 let point = this.googleMaps.map.getCenter(); 13883 const projection = this.googleMaps.overlay.getProjection(); 13884 const pixelpoint = projection.fromLatLngToDivPixel(point); 13885 pixelpoint.x += moveX; 13886 pixelpoint.y += moveY; 13887 point = projection.fromDivPixelToLatLng(pixelpoint); 13888 this.googleMaps.map.setCenter(point); 13889 } 13890 } 13891 return scrolled; 13892 } 13893 setObjectClickedBeforeScroll(object) { 13894 this.objectClickedBeforeScroll = object; 13895 } 13896 touchStart(_e, mapsvg) { 13897 _e.preventDefault(); 13898 if (this.scrollStarted) { 13899 this.scrollEnd(_e, mapsvg, true); 13900 } 13901 const e = _e.originalEvent; 13902 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13903 this.touchZoomStart = true; 13904 this.scaleDistStart = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY); 13905 } 13906 else if (e.touches && e.touches.length == 1) { 13907 this.scrollStart(_e, mapsvg); 13908 } 13909 $$A(document) 13910 .on("touchmove.scroll.mapsvg", (e) => { 13911 e.preventDefault(); 13912 this.touchMove(e, this); 13913 }) 13914 .on("touchend.scroll.mapsvg", (e) => { 13915 e.preventDefault(); 13916 this.touchEnd(e, this); 13917 }); 13918 } 13919 touchMove(_e, mapsvg) { 13920 _e.preventDefault(); 13921 const e = _e.originalEvent; 13922 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13923 if (!MapSVG.ios) { 13924 e.scale = 13925 Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY) / this.scaleDistStart; 13926 } 13927 if (e.scale != 1 && this.canZoom) { 13928 const d = e.scale > 1 ? 1 : -1; 13929 const cx = e.touches[0].pageX >= e.touches[1].pageX 13930 ? e.touches[0].pageX - 13931 (e.touches[0].pageX - e.touches[1].pageX) / 2 - 13932 $$A(this.containers.map).offset().left 13933 : e.touches[1].pageX - 13934 (e.touches[1].pageX - e.touches[0].pageX) / 2 - 13935 $$A(this.containers.map).offset().left; 13936 const cy = e.touches[0].pageY >= e.touches[1].pageY 13937 ? e.touches[0].pageY - 13938 (e.touches[0].pageY - e.touches[1].pageY) - 13939 $$A(this.containers.map).offset().top 13940 : e.touches[1].pageY - 13941 (e.touches[1].pageY - e.touches[0].pageY) - 13942 $$A(this.containers.map).offset().top; 13943 const center = this.converter.convertPixelToSVG(new ScreenPoint(cx, cy)); 13944 if (d > 0) 13945 this.zoomIn(center); 13946 else 13947 this.zoomOut(center); 13948 } 13949 } 13950 else if (e.touches && e.touches.length == 1) { 13951 this.scrollMove(_e); 13952 } 13953 } 13954 touchEnd(_e, mapsvg) { 13955 _e.preventDefault(); 13956 const e = _e.originalEvent; 13957 if (this.touchZoomStart) { 13958 this.touchZoomStart = false;
13959 } 13960 else if (this.scrollStarted) { 13961 this.scrollEnd(_e, mapsvg); 13962 } 13963 $$A(document).off("touchmove.scroll.mapsvg"); 13964 $$A(document).off("touchend.scroll.mapsvg"); 13965 } 13966 getSelected() { 13967 return this.selected_id; 13968 } 13969 selectRegion(id, skipDirectorySelection) { 13970 let region; 13971 if (typeof id == "string") { 13972 region = this.getRegion(id); 13973 } 13974 else { 13975 region = id; 13976 } 13977 if (!region) 13978 return; 13979 let ids; 13980 if (this.options.multiSelect && !this.editRegions.on) { 13981 if (region.selected) { 13982 this.deselectRegion(region); 13983 if (!skipDirectorySelection && this.options.menu.on) { 13984 if (this.options.menu.source == "database") { 13985 if (region.objects && region.objects.length) { 13986 ids = region.objects.map((obj) => { 13987 return obj.id.toString(); 13988 }); 13989 } 13990 } 13991 else { 13992 ids = [region.id]; 13993 } 13994 this.controllers.directory.deselectItems(); 13995 } 13996 return; 13997 } 13998 } 13999 else if (this.selected_id.length > 0) { 14000 this.deselectAllRegions(); 14001 if (!skipDirectorySelection && this.options.menu.on) { 14002 if (this.options.menu.source == "database") { 14003 if (region.objects && region.objects.length) { 14004 ids = region.objects.map((obj) => { 14005 return obj.id.toString(); 14006 }); 14007 } 14008 } 14009 else { 14010 ids = [region.id]; 14011 } 14012 this.controllers.directory.deselectItems(); 14013 } 14014 } 14015 this.selected_id.push(region.id); 14016 region.select(); 14017 const skip = this.options.actions.region.click.filterDirectory; 14018 if (!skip && 14019 !skipDirectorySelection && 14020 this.options.menu.on && 14021 this.controllers && 14022 this.controllers.directory) { 14023 if (this.options.menu.source == "database") { 14024 if (region.objects && region.objects.length) { 14025 ids = region.objects.map((obj) => { 14026 return obj.id.toString(); 14027 }); 14028 } 14029 else { 14030 ids = [region.id]; 14031 } 14032 } 14033 else { 14034 ids = [region.id]; 14035 } 14036 this.controllers.directory.selectItems(ids); 14037 } 14038 if (this.options.actions.region.click.addIdToUrl && 14039 !this.options.actions.region.click.showAnotherMap) { 14040 window.location.hash = "/m/" + region.id; 14041 } 14042 } 14043 deselectAllRegions() { 14044 $$A.each(this.selected_id, (index, id) => { 14045 this.deselectRegion(this.getRegion(id)); 14046 }); 14047 } 14048 deselectRegion(region) { 14049 if (!region) 14050 region = this.getRegion(this.selected_id[0]); 14051 if (region) { 14052 region.deselect(); 14053 const i = $$A.inArray(region.id, this.selected_id); 14054 this.selected_id.splice(i, 1); 14055 } 14056 if (this.options.actions.region.click.addIdToUrl) { 14057 if (window.location.hash.indexOf(region.id) !== -1) { 14058 history.replaceState(null, null, " "); 14059 } 14060 } 14061 } 14062 highlightRegions(regions) { 14063 regions.forEach((region) => { 14064 if (region && !region.selected && !region.disabled) { 14065 this.highlightedRegions.push(region); 14066 region.highlight(); 14067 } 14068 }); 14069 } 14070 unhighlightRegions() { 14071 this.highlightedRegions.forEach((region) => { 14072 if (region && !region.selected && !region.disabled) 14073 region.unhighlight(); 14074 }); 14075 this.highlightedRegions = []; 14076 } 14077 selectMarker(marker) { 14078 if (!(marker instanceof Marker)) 14079 return; 14080 this.deselectAllMarkers(); 14081 marker.select(); 14082 this.selected_marker = marker; 14083 $$A(this.layers.markers).addClass("mapsvg-with-marker-active"); 14084 if (this.options.menu.on && this.options.menu.source == "database") { 14085 this.controllers.directory.deselectItems(); 14086 this.controllers.directory.selectItems(marker.object.id); 14087 } 14088 } 14089 deselectAllMarkers() { 14090 this.selected_marker && this.selected_marker.deselect(); 14091 $$A(this.layers.markers).removeClass("mapsvg-with-marker-active"); 14092 } 14093 deselectMarker(marker) { 14094 if (marker) { 14095 marker.deselect(); 14096 } 14097 } 14098 highlightMarker(marker) { 14099 $$A(this.layers.markers).addClass("mapsvg-with-marker-hover"); 14100 marker.highlight(); 14101 this.highlighted_marker = marker; 14102 } 14103 unhighlightMarker() { 14104 $$A(this.layers.markers).removeClass("mapsvg-with-marker-hover"); 14105 this.highlighted_marker && this.highlighted_marker.unhighlight(); 14106 } 14107 convertMouseToSVG(e) { 14108 const mc = MapSVG.mouseCoords(e); 14109 const x = mc.x - $$A(this.containers.map).offset().left; 14110 const y = mc.y - $$A(this.containers.map).offset().top; 14111 const screenPoint = new ScreenPoint(x, y); 14112 return this.converter.convertPixelToSVG(screenPoint); 14113 } 14114 pickChoroplethColor(choroplethValue) { 14115 const w = (choroplethValue - this.options.choropleth.coloring.gradient.values.min) / 14116 this.options.choropleth.coloring.gradient.values.maxAdjusted; 14117 const rgba = { 14118 r: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.r * w + 14119 this.options.choropleth.coloring.gradient.colors.lowRGB.r), 14120 g: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.g * w + 14121 this.options.choropleth.coloring.gradient.colors.lowRGB.g), 14122 b: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.b * w + 14123 this.options.choropleth.coloring.gradient.colors.lowRGB.b), 14124 a: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.a * w + 14125 this.options.choropleth.coloring.gradient.colors.lowRGB.a), 14126 }; 14127 return rgba; 14128 } 14129 isRegionDisabled(id, svgfill) { 14130 if (this.options.regions[id] && (this.options.regions[id].disabled || svgfill == "none")) { 14131 return true; 14132 } 14133 else if ((this.options.regions[id] == undefined || 14134 MapSVG.parseBoolean(this.options.regions[id].disabled)) && 14135 (this.options.disableAll || svgfill == "none" || id == "labels" || id == "Labels")) { 14136 return true; 14137 } 14138 else { 14139 return false;
14140 } 14141 } 14142 loadMap(id, container) { 14143 if (!(container instanceof HTMLElement)) { 14144 console.error("Can't load a new map: container was not provided."); 14145 return; 14146 } 14147 const previousMapsIds = [...this.options.previousMapsIds]; 14148 const currentMapId = this.id; 14149 if (previousMapsIds[previousMapsIds.length - 1] !== id) { 14150 previousMapsIds.push(currentMapId); 14151 } 14152 else { 14153 previousMapsIds.pop(); 14154 } 14155 let showPreviousMapButton; 14156 if (this.options.actions.region.click.showAnotherMapContainerId !== "undefined") { 14157 showPreviousMapButton = false; 14158 } 14159 else { 14160 showPreviousMapButton = this.options.controls.previousMap; 14161 } 14162 const mapsRepo = new MapsRepository(); 14163 mapsRepo.findById(id).done((map) => { 14164 this.destroy(); 14165 const newMap = new MapSVGMap(container.getAttribute("id"), map); 14166 newMap.events.on("afterLoad", function () { 14167 this.options.previousMapsIds = previousMapsIds; 14168 this.options.controls.previousMap = showPreviousMapButton; 14169 this.setControls(this.options.controls); 14170 }); 14171 }); 14172 } 14173 loadPreviousMap() { 14174 const previousMapId = this.options.previousMapsIds[this.options.previousMapsIds.length - 1]; 14175 const container = document.getElementById(this.containerId); 14176 this.loadMap(previousMapId, container); 14177 } 14178 markerClusterClickHandler(e, markerCluster) { 14179 this.objectClickedBeforeScroll = null; 14180 if (this.eventsPreventList["click"]) 14181 return; 14182 this.zoomTo(markerCluster.markers); 14183 return; 14184 } 14185 regionClickHandler(e, region) { 14186 this.objectClickedBeforeScroll = null; 14187 if (this.eventsPreventList["click"]) 14188 return; 14189 this.selectRegion(region.id); 14190 if (this.editRegions.on) { 14191 this.regionEditHandler.call(region); 14192 return; 14193 } 14194 const actions = this.options.actions; 14195 if (actions.region.click.zoom) { 14196 this.zoomTo(region, parseInt(actions.region.click.zoomToLevel)); 14197 } 14198 if (actions.region.click.filterDirectory) { 14199 const query = new Query({ 14200 filters: { 14201 regions: { 14202 table_name: this.regionsRepository.getSchema().name, 14203 region_ids: [region.id], 14204 }, 14205 }, 14206 }); 14207 this.objectsRepository.find(query).done(() => { 14208 if (this.controllers.popover) { 14209 this.controllers.popover.redraw(region.forTemplate()); 14210 } 14211 if (this.controllers.detailsView) { 14212 this.controllers.detailsView.redraw(region.forTemplate()); 14213 } 14214 }); 14215 this.updateFiltersState(); 14216 }
14217 if (actions.region.click.showDetails) { 14218 this.loadDetailsView(region); 14219 } 14220 if (actions.region.click.showPopover) { 14221 if (actions.region.click.zoom) { 14222 setTimeout(() => { 14223 this.showPopover(region); 14224 }, 400); 14225 } 14226 else { 14227 this.showPopover(region); 14228 } 14229 } 14230 else if (e && e.type.indexOf("touch") !== -1 && actions.region.touch.showPopover) { 14231 if (actions.region.click.zoom) { 14232 setTimeout(() => { 14233 this.showPopover(region); 14234 }, 400); 14235 } 14236 else { 14237 this.showPopover(region); 14238 } 14239 } 14240 if (actions.region.click.goToLink) { 14241 const linkParts = actions.region.click.linkField.split("."); 14242 let url; 14243 if (linkParts.length > 1) { 14244 const obj = linkParts.shift(); 14245 const attr = "." + linkParts.join("."); 14246 if (obj == "Region") { 14247 if (region.data) { 14248 try { 14249 url = eval("region.data" + attr); 14250 } 14251 catch (err) { 14252 console.log("No such field as region.data" + attr); 14253 } 14254 } 14255 } 14256 else { 14257 if (region.objects && region.objects[0]) { 14258 try { 14259 url = eval("region.objects[0]" + attr); 14260 } 14261 catch (err) { 14262 console.log("No such field as region.objects[0]" + attr); 14263 } 14264 } 14265 } 14266 if (url && !this.disableLinks) { 14267 if (this.editMode) { 14268 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14269 return; 14270 } 14271 if (actions.region.click.newTab) { 14272 const win = window.open(url, "_blank"); 14273 win.focus(); 14274 } 14275 else { 14276 window.location.href = url; 14277 } 14278 } 14279 } 14280 } 14281 if (actions.region.click.showAnotherMap) { 14282 if (this.editMode) { 14283 alert('"Show another map" action is disabled in the preview'); 14284 return; 14285 } 14286 const linkParts = actions.region.click.showAnotherMapField.split("."); 14287 if (linkParts.length > 1) { 14288 const obj = linkParts.shift(); 14289 const attr = "." + linkParts.join("."); 14290 let map_id; 14291 if (obj == "Region") { 14292 if (region.data) 14293 map_id = eval("region.data" + attr); 14294 } 14295 else { 14296 if (region.objects && region.objects[0]) 14297 map_id = eval("region.objects[0]" + attr); 14298 } 14299 if (map_id) { 14300 const container = actions.region.click.showAnotherMapContainerId 14301 ? $$A("#" + actions.region.click.showAnotherMapContainerId)[0] 14302 : $$A(this.containers.wrapAll)[0]; 14303 this.loadMap(map_id, container); 14304 } 14305 } 14306 } 14307 this.events.trigger("click.region", region, [e, region, this]); 14308 } 14309 markerClickHandler(e, marker) { 14310 this.objectClickedBeforeScroll = null; 14311 if (this.eventsPreventList["click"]) 14312 return; 14313 const actions = this.options.actions; 14314 this.selectMarker(marker); 14315 const passingObject = marker.object; 14316 if (actions.marker.click.zoom) { 14317 this.zoomTo(marker, parseInt(actions.marker.click.zoomToLevel)); 14318 } 14319 if (actions.marker.click.filterDirectory) { 14320 const query = new Query({ filters: { id: marker.object.id } }); 14321 this.objectsRepository.find(query); 14322 this.updateFiltersState(); 14323 }
14324 if (actions.marker.click.showDetails) 14325 this.loadDetailsView(passingObject); 14326 if (actions.marker.click.showPopover) { 14327 if (actions.marker.click.zoom) { 14328 setTimeout(() => { 14329 this.showPopover(passingObject); 14330 }, 500); 14331 } 14332 else { 14333 this.showPopover(passingObject); 14334 } 14335 } 14336 else if (e && e.type.indexOf("touch") !== -1 && actions.marker.touch.showPopover) { 14337 if (actions.marker.click.zoom) { 14338 setTimeout(() => { 14339 this.showPopover(passingObject); 14340 }, 500); 14341 } 14342 else { 14343 this.showPopover(passingObject); 14344 } 14345 } 14346 if (actions.marker.click.goToLink) { 14347 const linkParts = actions.marker.click.linkField.split("."); 14348 let url; 14349 if (linkParts.length > 1) { 14350 const obj = linkParts.shift(); 14351 const attr = "." + linkParts.join("."); 14352 try { 14353 url = eval("passingObject" + attr); 14354 } 14355 catch (err) { 14356 console.log("MapSVG: No such field as passingObject" + attr); 14357 } 14358 if (url && !this.disableLinks) 14359 if (this.editMode) { 14360 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14361 return; 14362 } 14363 if (actions.marker.click.newTab) { 14364 const win = window.open(url, "_blank"); 14365 win.focus(); 14366 } 14367 else { 14368 window.location.href = url; 14369 } 14370 } 14371 } 14372 this.events.trigger("click.marker", marker, [e, marker, this]); 14373 } 14374 fileExists(url) { 14375 if (url.substr(0, 4) == "data") 14376 return true; 14377 const http = new XMLHttpRequest(); 14378 http.open("HEAD", url, false); 14379 http.send(); 14380 return http.status != 404; 14381 } 14382 hideMarkers() { 14383 this.markers.forEach(function (marker) { 14384 marker.hide(); 14385 }); 14386 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14387 } 14388 hideMarkersExceptOne(id) { 14389 this.markers.forEach(function (marker) { 14390 if (typeof id === "undefined" || (marker.object && id != marker.object.id)) { 14391 marker.hide(); 14392 } 14393 }); 14394 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14395 } 14396 showMarkers() { 14397 this.markers.forEach(function (m) { 14398 m.show(); 14399 }); 14400 this.deselectAllMarkers(); 14401 $$A(this.containers.wrap).removeClass("mapsvg-edit-marker-mode"); 14402 } 14403 markerAddClickHandler(e) { 14404 if ($$A(e.target).hasClass("mapsvg-marker")) 14405 return; 14406 const svgPoint = this.getSvgPointAtClick(e); 14407 const geoPoint = this.isGeo() ? this.converter.convertSVGToGeo(svgPoint) : null; 14408 if (!$$A.isNumeric(svgPoint.x) || !$$A.isNumeric(svgPoint.y)) 14409 return; 14410 if (this.editingMarker) { 14411 if (geoPoint) { 14412 this.editingMarker.location.setGeoPoint(geoPoint); 14413 } 14414 else { 14415 this.editingMarker.location.setSvgPoint(svgPoint); 14416 } 14417 return; 14418 } 14419 const location = new Location({ 14420 svgPoint: svgPoint, 14421 geoPoint: geoPoint, 14422 img: this.options.defaultMarkerImage, 14423 }); 14424 const marker = new Marker({ 14425 location: location, 14426 mapsvg: this, 14427 }); 14428 this.markerAdd(marker); 14429 this.markerEditHandler && this.markerEditHandler.call(location, location); 14430 } 14431 getSvgPointAtClick(e) { 14432 const mc = MapSVG.mouseCoords(e); 14433 const x = mc.x - $$A(this.containers.map).offset().left; 14434 const y = mc.y - $$A(this.containers.map).offset().top; 14435 const screenPoint = new ScreenPoint(x, y); 14436 return this.converter.convertPixelToSVG(screenPoint); 14437 } 14438 setDefaultMarkerImage(src) { 14439 this.options.defaultMarkerImage = src; 14440 } 14441 setMarkerImagesDependency() { 14442 this.locationField = this.objectsRepository.schema.getFieldByType("location"); 14443 if (this.locationField && 14444 this.locationField.markersByFieldEnabled && 14445 this.locationField.markerField && 14446 Object.values(this.locationField.markersByField).length > 0) { 14447 this.setMarkersByField = true; 14448 } 14449 else { 14450 this.setMarkersByField = false;
14451 } 14452 } 14453 getMarkerImage(fieldValueOrObject, location) { 14454 let fieldValue; 14455 if (this.setMarkersByField) { 14456 if (typeof fieldValueOrObject === "object") { 14457 fieldValue = fieldValueOrObject[this.locationField.markerField]; 14458 if (this.locationField.markerField === "regions") { 14459 fieldValue = fieldValue[0] && fieldValue[0].id; 14460 } 14461 else if (typeof fieldValue === "object" && fieldValue.length) { 14462 fieldValue = fieldValue[0].value; 14463 } 14464 } 14465 else { 14466 fieldValue = fieldValueOrObject; 14467 } 14468 if (this.locationField.markersByField[fieldValue]) { 14469 return this.locationField.markersByField[fieldValue]; 14470 } 14471 } 14472 return location && location.imagePath 14473 ? location.imagePath 14474 : this.options.defaultMarkerImage 14475 ? this.options.defaultMarkerImage 14476 : MapSVG.urls.root + "markers/_pin_default.png"; 14477 } 14478 setMarkersEditMode(on, clickAddsMarker) { 14479 this.editMarkers.on = MapSVG.parseBoolean(on); 14480 this.clickAddsMarker = this.editMarkers.on; 14481 this.setEventHandlers(); 14482 } 14483 setRegionsEditMode(on) { 14484 this.editRegions.on = MapSVG.parseBoolean(on); 14485 this.deselectAllRegions(); 14486 this.setEventHandlers(); 14487 } 14488 setEditMode(on) { 14489 this.editMode = on; 14490 } 14491 setDataEditMode(on) { 14492 this.editData.on = MapSVG.parseBoolean(on); 14493 this.deselectAllRegions(); 14494 this.setEventHandlers(); 14495 } 14496 download() { 14497 window.location.href = window.location.origin + this.options.source; 14498 } 14499 popoverAdjustScreenPosition() { 14500 if (this.controllers.popover instanceof PopoverController) { 14501 this.controllers.popover.adjustScreenPosition(); 14502 } 14503 } 14504 popoverMoveScreenPositionBy(deltaX, deltaY) { 14505 if (this.controllers.popover instanceof PopoverController) { 14506 this.controllers.popover.moveSrceenPositionBy(deltaX, deltaY); 14507 } 14508 } 14509 showPopover(object) { 14510 const mapObject = object instanceof Region 14511 ? object 14512 : object.location && object.location.marker 14513 ? object.location.marker 14514 : null; 14515 if (!mapObject) 14516 return; 14517 let point; 14518 if (mapObject instanceof Marker) { 14519 point = mapObject.svgPoint; 14520 } 14521 else { 14522 point = mapObject.getCenterSVG(); 14523 } 14524 this.controllers.popover && this.controllers.popover.destroy(); 14525 this.controllers.popover = new PopoverController({ 14526 container: this.containers.popover, 14527 point: point, 14528 yShift: mapObject instanceof Marker ? mapObject.height : 0, 14529 template: object instanceof Region 14530 ? this.options.templates.popoverRegion 14531 : this.options.templates.popoverMarker, 14532 mapsvg: this, 14533 data: object.getData(), 14534 mapObject: mapObject, 14535 scrollable: true, 14536 withToolbar: !(MapSVG.isPhone && this.options.popovers.mobileFullscreen), 14537 events: { 14538 shown: (popover) => { 14539 if (this.options.popovers.centerOn) { 14540 const shift = popover.containers.main.offsetHeight / 2; 14541 if (this.options.popovers.centerOn && 14542 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14543 this.centerOn(mapObject, shift); 14544 } 14545 } 14546 this.popoverShowingFor = mapObject; 14547 this.events.trigger("shown.popover", this, [this, popover]); 14548 $$A(window).trigger("shown.popover", [this, popover]); 14549 }, 14550 closed: (popover) => { 14551 this.options.popovers.resetViewboxOnClose && this.viewBoxReset(true); 14552 this.popoverShowingFor = null; 14553 this.events.trigger("closed.popover", this, [this, popover]); 14554 }, 14555 resize: (popover) => { 14556 if (this.options.popovers.centerOn) { 14557 const shift = popover.containers.main.offsetHeight / 2; 14558 if (this.options.popovers.centerOn && 14559 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14560 this.centerOn(mapObject, shift); 14561 } 14562 } 14563 }, 14564 }, 14565 }); 14566 this.controllers.popover._init(); 14567 } 14568 hidePopover() { 14569 this.controllers.popover && this.controllers.popover.close(); 14570 } 14571 popoverOffHandler(e) { 14572 if (this.isScrolling || 14573 $$A(e.target).closest(".mapsvg-popover").length || 14574 $$A(e.target).hasClass("mapsvg-btn-map")) 14575 return; 14576 this.controllers.popover && this.controllers.popover.close(); 14577 } 14578 mouseOverHandler(e, object) { 14579 if (this.eventsPreventList["mouseover"]) { 14580 return; 14581 } 14582 if (object instanceof Marker) { 14583 if (this.options.actions.marker.mouseover.showTooltip) { 14584 this.showTooltip(object); 14585 } 14586 } 14587 if (object instanceof Region) { 14588 if (this.options.actions.region.mouseover.showTooltip) { 14589 this.showTooltip(object); 14590 } 14591 } 14592 let ids; 14593 if (this.options.menu.on) { 14594 if (this.options.menu.source == "database") { 14595 if (object instanceof Region && object.objects.length) { 14596 ids = object.objects.map((obj) => { 14597 return obj.id; 14598 }); 14599 } 14600 if (object instanceof Marker) { 14601 ids = object.object ? [object.object.id] : []; 14602 } 14603 } 14604 else { 14605 if (object instanceof Region) { 14606 ids = [object.id]; 14607 } 14608 if (this instanceof Marker && 14609 object.object.regions && 14610 object.object.regions.length) { 14611 ids = object.object.regions.map((obj) => { 14612 return obj.id; 14613 }); 14614 } 14615 } 14616 this.controllers.directory.highlightItems(ids); 14617 } 14618 if (object instanceof Region) { 14619 if (!object.selected) 14620 object.highlight(); 14621 this.events.trigger("mouseover.region", object, [e, this]); 14622 } 14623 else { 14624 this.highlightMarker(object); 14625 this.events.trigger("mouseover.marker", object, [e, this]); 14626 } 14627 } 14628 showTooltip(object) { 14629 let name, _object; 14630 if (object instanceof Region) { 14631 name = "tooltipRegion"; 14632 _object = object; 14633 } 14634 else if (object instanceof Marker) { 14635 name = "tooltipMarker"; 14636 _object = object.object; 14637 } 14638 else { 14639 name = "tooltipMarker"; 14640 _object = object; 14641 } 14642 if (_object != null && this.popoverShowingFor !== object) { 14643 this.controllers.tooltip.setMainTemplate(this.options.templates[name]); 14644 this.controllers.tooltip.redraw(_object.getData()); 14645 this.controllers.tooltip.show(); 14646 } 14647 } 14648 mouseOutHandler(e, object) { 14649 if (this.eventsPreventList["mouseout"]) { 14650 return; 14651 } 14652 if (this.controllers.tooltip) 14653 this.controllers.tooltip.hide(); 14654 if (object instanceof Region) { 14655 if (!object.selected) 14656 object.unhighlight(); 14657 this.events.trigger("mouseout.region", object, [e, this]); 14658 } 14659 else { 14660 this.unhighlightMarker(); 14661 this.events.trigger("mouseout.marker", object, [e, this]); 14662 } 14663 let ids; 14664 if (this.options.menu.on) { 14665 if (this.options.menu.source == "database") { 14666 if (object instanceof Marker) { 14667 const marker = object; 14668 ids = marker.object ? [marker.object.id] : []; 14669 } 14670 } 14671 this.controllers.directory.unhighlightItems(); 14672 } 14673 } 14674 eventsPrevent(event) { 14675 this.eventsPreventList[event] = true; 14676 } 14677 eventsRestore(event) { 14678 if (event) { 14679 this.eventsPreventList[event] = false;
14680 } 14681 else { 14682 this.eventsPreventList = {}; 14683 } 14684 } 14685 setEventHandlers() { 14686 const _this = this; 14687 $$A(_this.containers.map).off(".common.mapsvg"); 14688 $$A(_this.containers.scrollpane).off(".common.mapsvg"); 14689 $$A(document).off(".scroll.mapsvg"); 14690 $$A(document).off(".scrollInit.mapsvg"); 14691 if (_this.editMarkers.on) { 14692 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", ".mapsvg-marker", function (e) { 14693 e.originalEvent.preventDefault(); 14694 const marker = _this.getMarker($$A(this).attr("id")); 14695 const startCoords = MapSVG.mouseCoords(e); 14696 marker.drag(startCoords, _this.scale); 14697 }); 14698 } 14699 if (!_this.editMarkers.on) { 14700 $$A(_this.containers.map) 14701 .on("mouseover.common.mapsvg", ".mapsvg-region", function (e) { 14702 const id = $$A(this).attr("id"); 14703 _this.mouseOverHandler.call(_this, e, _this.getRegion(id)); 14704 }) 14705 .on("mouseleave.common.mapsvg", ".mapsvg-region", function (e) { 14706 const id = $$A(this).attr("id"); 14707 _this.mouseOutHandler.call(_this, e, _this.getRegion(id)); 14708 }); 14709 } 14710 if (!_this.editRegions.on) { 14711 $$A(_this.containers.map) 14712 .on("mouseover.common.mapsvg", ".mapsvg-marker", function (e) { 14713 const id = $$A(this).attr("id"); 14714 _this.mouseOverHandler.call(_this, e, _this.getMarker(id)); 14715 }) 14716 .on("mouseleave.common.mapsvg", ".mapsvg-marker", function (e) { 14717 const id = $$A(this).attr("id"); 14718 _this.mouseOutHandler.call(_this, e, _this.getMarker(id)); 14719 }); 14720 } 14721 if (_this.options.scroll.spacebar) { 14722 $$A(document).on("keydown.scroll.mapsvg", function (e) { 14723 if (!(document.activeElement.tagName === "INPUT" && 14724 $$A(document.activeElement).attr("type") === "text") && 14725 !_this.isScrolling && 14726 e.keyCode == 32) { 14727 e.preventDefault(); 14728 $$A(_this.containers.map).addClass("mapsvg-scrollable"); 14729 $$A(document) 14730 .on("mousemove.scrollInit.mapsvg", function (e) { 14731 _this.isScrolling = true; 14732 $$A(document).off("mousemove.scrollInit.mapsvg"); 14733 _this.scrollStart(e, _this); 14734 }) 14735 .on("keyup.scroll.mapsvg", function (e) { 14736 if (e.keyCode == 32) { 14737 $$A(document).off("mousemove.scrollInit.mapsvg"); 14738 $$A(_this.containers.map).removeClass("mapsvg-scrollable"); 14739 } 14740 }); 14741 } 14742 }); 14743 } 14744 else if (!_this.options.scroll.on) { 14745 if (!_this.editMarkers.on) { 14746 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-region", function (e) { 14747 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14748 }); 14749 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-marker", function (e) { 14750 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14751 }); 14752 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-region", function (e) { 14753 if (e.cancelable) { 14754 e.preventDefault(); 14755 } 14756 if (!_this.scroll.touchScrollStart || 14757 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14758 _this.regionClickHandler(e, _this.getRegion($$A(this).attr("id"))); 14759 } 14760 }); 14761 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker", function (e) { 14762 if (e.cancelable) { 14763 e.preventDefault(); 14764 } 14765 if (!_this.scroll.touchScrollStart || 14766 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14767 _this.markerClickHandler.call(_this, e, _this.getMarker($$A(this).attr("id"))); 14768 } 14769 }); 14770 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker-cluster", function (e) { 14771 if (e.cancelable) { 14772 e.preventDefault(); 14773 } 14774 if (!_this.scroll.touchScrollStart || 14775 _this.scroll.touchScrollStart == $$A(window).scrollTop()) { 14776 const cluster = $$A(this).data("cluster"); 14777 _this.zoomTo(cluster.markers); 14778 } 14779 }); 14780 } 14781 else { 14782 if (_this.clickAddsMarker) 14783 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", function (e) { 14784 if (e.cancelable) { 14785 e.preventDefault(); 14786 } 14787 _this.markerAddClickHandler(e); 14788 }); 14789 } 14790 } 14791 else { 14792 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", function (e) { 14793 if ($$A(e.target).hasClass("mapsvg-popover") || 14794 $$A(e.target).closest(".mapsvg-popover").length) { 14795 if ($$A(e.target).hasClass("mapsvg-popover-close")) { 14796 if (e.type == "touchstart") { 14797 if (e.cancelable) { 14798 e.preventDefault(); 14799 } 14800 } 14801 } 14802 return; 14803 } 14804 if (e.type == "touchstart") { 14805 if (e.cancelable) { 14806 e.preventDefault(); 14807 } 14808 } 14809 let obj; 14810 if (e.target && 14811 $$A(e.target).attr("class") && 14812 $$A(e.target).attr("class").indexOf("mapsvg-region") != -1) { 14813 obj = _this.getRegion($$A(e.target).attr("id")); 14814 _this.setObjectClickedBeforeScroll(obj); 14815 } 14816 else if (e.target && 14817 $$A(e.target).attr("class") && 14818 $$A(e.target).attr("class").indexOf("mapsvg-marker") != -1 && 14819 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster")
14819=== -1) { 14820 if (_this.editMarkers.on) { 14821 return; 14822 } 14823 obj = _this.getMarker($$A(e.target).attr("id")); 14824 _this.setObjectClickedBeforeScroll(obj); 14825 } 14826 else if (e.target && 14827 $$A(e.target).attr("class") && 14828 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster") != -1) { 14829 if (_this.editMarkers.on) { 14830 return; 14831 } 14832 obj = $$A(e.target).data("cluster"); 14833 _this.setObjectClickedBeforeScroll(obj); 14834 } 14835 if (e.type == "mousedown") { 14836 _this.scrollStart(e, _this); 14837 } 14838 else { 14839 _this.touchStart(e, _this); 14840 } 14841 }); 14842 } 14843 $$A(_this.containers.map).on("mouseleave.common.mapsvg", ".mapsvg-choropleth-gradient-wrap", (e) => { 14844 this.controllers.tooltip.hide(); 14845 }); 14846 } 14847 setLabelsRegions(options) { 14848 options = options || this.options.labelsRegions; 14849 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14850 $$A.extend(true, this.options, { labelsRegions: options }); 14851 if (this.options.labelsRegions.on) { 14852 this.regions.forEach((region) => { 14853 if (!region.label) { 14854 region.label = jQuery('<div class="mapsvg-region-label" />')[0]; 14855 $$A(this.layers.labels).append(region.label); 14856 } 14857 try { 14858 $$A(region.label).html(this.templates.labelRegion(region.forTemplate())); 14859 } 14860 catch (err) { 14861 console.error('MapSVG: Error in the "Region Label" template'); 14862 } 14863 }); 14864 this.labelsRegionsAdjustScreenPosition(); 14865 } 14866 else { 14867 this.regions.forEach((region) => { 14868 if (region.label) { 14869 $$A(region.label).remove(); 14870 region.label = null; 14871 delete region.label; 14872 } 14873 }); 14874 } 14875 } 14876 setLabelsMarkers(options) { 14877 options = options || this.options.labelsMarkers; 14878 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14879 $$A.extend(true, this.options, { labelsMarkers: options }); 14880 if (this.options.labelsMarkers.on) { 14881 this.markers.forEach((marker) => { 14882 try { 14883 marker.setLabel(this.templates.labelMarker(marker.object)); 14884 } 14885 catch (err) { 14886 console.error('MapSVG: Error in the "Marker Label" template'); 14887 } 14888 }); 14889 } 14890 else { 14891 this.markers.forEach((marker) => { 14892 marker.setLabel(""); 14893 }); 14894 } 14895 } 14896 addLayer(name) { 14897 this.layers[name] = $$A('<div class="mapsvg-layer mapsvg-layer-' + name + '"></div>')[0]; 14898 this.containers.layers.appendChild(this.layers[name]); 14899 return this.layers[name]; 14900 } 14901 getLayer(name) { 14902 return this.layers[name]; 14903 } 14904 getDb() { 14905 return this.objectsRepository; 14906 } 14907 getDbRegions() { 14908 return this.regionsRepository; 14909 } 14910 regionAdd(svgObject) { 14911 const region = new Region(svgObject, this); 14912 region.setStatus(1); 14913 this.regions.push(region); 14914 this.regions.sort(function (a, b) { 14915 return a.id == b.id ? 0 : +(a.id > b.id) || -1; 14916 }); 14917 return region; 14918 } 14919 regionDelete(id) { 14920 if (this.regions.findById(id)) { 14921 this.regions.findById(id).elem.remove(); 14922 this.regions.delete(id); 14923 } 14924 else if ($$A("#" + id).length) { 14925 $$A("#" + id).remove(); 14926 } 14927 } 14928 reloadRegions() { 14929 this.regions.clear(); 14930 $$A(this.containers.svg).find(".mapsvg-region").removeClass("mapsvg-region"); 14931 $$A(this.containers.svg) 14932 .find(".mapsvg-region-disabled") 14933 .removeClass("mapsvg-region-disabled"); 14934 $$A(this.containers.svg) 14935 .find("path, polygon, circle, ellipse, rect") 14936 .each((index, element) => { 14937 const elem = element; 14938 if ($$A(elem).closest("defs").length) 14939 return; 14940 if (elem.getAttribute("data-stroke-width")) { 14941 elem.style["stroke-width"] = elem.getAttribute("data-stroke-width"); 14942 } 14943 if (elem.getAttribute("id")) { 14944 if (!this.options.regionPrefix || 14945 (this.options.regionPrefix && 14946 elem.getAttribute("id").indexOf(this.options.regionPrefix) === 0)) { 14947 const region = new Region(elem, this); 14948 this.regions.push(region); 14949 } 14950 } 14951 }); 14952 } 14953 reloadRegionsFull() { 14954 const statuses = this.regionsRepository.getSchema().getFieldByType("status"); 14955 this.regions.forEach((region) => { 14956 const _region = this.regionsRepository.getLoaded().findById(region.id); 14957 if (_region) { 14958 region.setData(_region); 14959 if (statuses && _region.status !== undefined && _region.status !== null) { 14960 region.setStatus(_region.status); 14961 } 14962 } 14963 else { 14964 if (this.options.filters.filteredRegionsStatus || 14965 this.options.filters.filteredRegionsStatus === 0 || 14966 (this.options.menu.source === "regions" && 14967 this.options.menu.filterout && 14968 this.options.menu.filterout.field === "status" && 14969 this.options.menu.filterout.val) || 14970 this.options.menu.filterout.val === 0) { 14971 const status = this.options.filters.filteredRegionsStatus || 14972 this.options.filters.filteredRegionsStatus === 0 14973 ? this.options.filters.filteredRegionsStatus 14974 : this.options.menu.filterout.val; 14975 region.setStatus(status); 14976 } 14977 } 14978 }); 14979 this.loadDirectory(); 14980 this.setChoropleth(); 14981 this.setLayersControl(); 14982 this.setGroups(); 14983 if (this.options.labelsRegions.on) { 14984 this.setLabelsRegions(); 14985 } 14986 } 14987 fixMarkersWorldScreen() { 14988 if (this.googleMaps.map) 14989 setTimeout(() => { 14990 const markers = { left: 0, right: 0, leftOut: 0, rightOut: 0 }; 14991 if (this.markers.length > 1) {
14992 this.markers.forEach((m) => { 14993 if ($$A(m.element).offset().left < 14994 $$A(this.containers.map).offset().left + 14995 this.containers.map.clientWidth / 2) { 14996 markers.left++; 14997 if ($$A(m.element).offset().left < $$A(this.containers.map).offset().left) { 14998 markers.leftOut++; 14999 } 15000 } 15001 else { 15002 markers.right++; 15003 if ($$A(m.element).offset().left > 15004 $$A(this.containers.map).offset().left + 15005 this.containers.map.clientWidth) { 15006 markers.rightOut++; 15007 } 15008 } 15009 }); 15010 if ((markers.left === 0 && markers.rightOut) || 15011 (markers.right === 0 && markers.leftOut)) { 15012 const k = markers.left === 0 ? 1 : -1; 15013 const ww = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 15014 360 *
15015 this.getScale(); 15016 this.googleMaps.map.panBy(k * ww, 0); 15017 } 15018 } 15019 }, 600); 15020 } 15021 updateOutdatedOptions(options) { 15022 if (options.menu && (options.menu.position || options.menu.customContainer)) { 15023 if (options.menu.customContainer) { 15024 options.menu.location = "custom"; 15025 } 15026 else { 15027 options.menu.position = options.menu.position === "left" ? "left" : "right"; 15028 options.menu.location = 15029 options.menu.position === "left" ? "leftSidebar" : "rightSidebar"; 15030 if (!options.containers || !options.containers[options.menu.location]) { 15031 options.containers = options.containers || {}; 15032 options.containers[options.menu.location] = { on: false, width: "200px" }; 15033 } 15034 options.containers[options.menu.location].width = options.menu.width; 15035 if (MapSVG.parseBoolean(options.menu.on)) { 15036 options.containers[options.menu.location].on = true; 15037 } 15038 } 15039 delete options.menu.position; 15040 delete options.menu.width; 15041 delete options.menu.customContainer; 15042 } 15043 if (options.detailsView && 15044 (options.detailsView.location === "mapContainer" || 15045 options.detailsView.location === "near" || 15046 options.detailsView.location === "top")) { 15047 options.detailsView.location = "map"; 15048 } 15049 if (!options.controls) { 15050 options.controls = {}; 15051 options.controls.zoom = 15052 options.zoom && 15053 options.zoom.on && 15054 (!options.zoom.buttons || options.zoom.buttons.location !== "hide"); 15055 options.controls.location = 15056 options.zoom && options.zoom.buttons && options.zoom.buttons.location !== "hide" 15057 ? options.zoom.buttons.location 15058 : "right"; 15059 } 15060 if (options.colors && !options.colors.markers) { 15061 options.colors.markers = { 15062 base: { opacity: 100, saturation: 100 }, 15063 hovered: { opacity: 100, saturation: 100 }, 15064 unhovered: { opacity: 100, saturation: 100 }, 15065 active: { opacity: 100, saturation: 100 }, 15066 inactive: { opacity: 100, saturation: 100 }, 15067 }; 15068 } 15069 if (options.tooltipsMode) { 15070 options.tooltips.mode = options.tooltipsMode; 15071 delete options.tooltipsMode; 15072 } 15073 if (options.popover) { 15074 options.popovers = options.popover; 15075 delete options.popover; 15076 } 15077 } 15078 init() { 15079 MapSVG.addInstance(this); 15080 if (this.options.source === "") { 15081 throw new Error("MapSVG: please provide SVG file source."); 15082 } 15083 this.disableAnimation(); 15084 this.setEvents(this.options.events); 15085 this.events.trigger("beforeLoad"); 15086 if (this.options.googleMaps.on || 15087 (this.options.filters.on && 15088 this.options.filtersSchema.find((f) => f.type === "distance"))) { 15089 this.loadGoogleMapsAPI(() => { 15090 return 1; 15091 }, () => { 15092 return 1; 15093 }); 15094 } 15095 this.containers.map.classList.add("mapsvg"); 15096 this.setCss(); 15097 if (this.options.colors && this.options.colors.background) { 15098 this.containers.map.style.background = this.options.colors.background; 15099 } 15100 this.setContainers(this.options.containers); 15101 this.setColors(); 15102 this.addLoadingMessage(); 15103 this.addLayer("markers"); 15104 this.addLayer("labels"); 15105 this.addLayer("bubbles"); 15106 this.addLayer("popovers"); 15107 this.addLayer("scrollpane"); 15108 this.loadExtensions(); 15109 $$A.ajax({ url: this.options.source + "?v=" + this.svgFileLastChanged }) 15110 .fail((resp) => { 15111 this.svgLoadingFailed(resp); 15112 }) 15113 .done((xmlData) => { 15114 this.renderSvgData(xmlData); 15115 }); 15116 return this; 15117 } 15118 getContainer(name) { 15119 return this.containers[name]; 15120 } 15121 renderSvgData(xmlData) { 15122 const svgTag = $$A(xmlData).find("svg"); 15123 this.containers.svg = svgTag[0]; 15124 if (svgTag.attr("width") && svgTag.attr("height")) { 15125 this.svgDefault.width = parseFloat(svgTag.attr("width").replace(/px/g, "")); 15126 this.svgDefault.height = parseFloat(svgTag.attr("height").replace(/px/g, "")); 15127 this.svgDefault.viewBox = svgTag.attr("viewBox") 15128 ? new ViewBox(svgTag.attr("viewBox").split(" ")) 15129 : new ViewBox(0, 0, this.svgDefault.width, this.svgDefault.height); 15130 } 15131 else if (svgTag.attr("viewBox")) { 15132 this.svgDefault.viewBox = new ViewBox(svgTag.attr("viewBox").split(" ")); 15133 this.svgDefault.width = this.svgDefault.viewBox.width; 15134 this.svgDefault.height = this.svgDefault.viewBox.height; 15135 } 15136 else { 15137 const msg = "MapSVG: width/height and viewBox are missing in the SVG file. Can't parse the file because of that."; 15138 if (this.editMode) { 15139 alert(msg); 15140 } 15141 else { 15142 console.error(msg); 15143 } 15144 return false;
15145 } 15146 this.geoViewBox = this.getGeoViewBoxFromSvgTag(this.containers.svg); 15147 if (this.options.viewBox && this.options.viewBox.length == 4) { 15148 this._viewBox = new ViewBox(this.options.viewBox); 15149 } 15150 else { 15151 this._viewBox = new ViewBox(this.svgDefault.viewBox); 15152 } 15153 svgTag.attr("preserveAspectRatio", "xMidYMid meet"); 15154 svgTag.removeAttr("width"); 15155 svgTag.removeAttr("height"); 15156 $$A(this.containers.scrollpane).append(svgTag); 15157 this.setStrokes(); 15158 this.reloadRegions(); 15159 this.setSize(this.options.width, this.options.height, this.options.responsive); 15160 if (this.options.disableAll) { 15161 this.setDisableAll(true); 15162 } 15163 this.setViewBox(this._viewBox); 15164 this.converter = new Converter(this.containers.map, this.svgDefault.viewBox, this.viewBox); 15165 if (this.geoViewBox) { 15166 this.converter.setGeoViewBox(this.geoViewBox); 15167 } 15168 this.setResponsive(this.options.responsive); 15169 this.setScroll(this.options.scroll, true); 15170 this.setZoom(this.options.zoom); 15171 this.setControls(this.options.controls); 15172 this.setGoogleMaps(); 15173 this.setTooltips(this.options.tooltips); 15174 this.setPopovers(this.options.popovers); 15175 if (this.options.cursor) 15176 this.setCursor(this.options.cursor); 15177 this.setTemplates(this.options.templates); 15178 this.loadExtensions(); 15179 this.filtersSchema = new Schema({ fields: this.options.filtersSchema }); 15180 this.objectsRepository.events.on("load", () => { 15181 this.showLoadingMessage(); 15182 }); 15183 this.objectsRepository.events.on("loaded", () => { 15184 this.setGlobalDistanceFilter(); 15185 this.fitOnDataLoadDone = false; 15186 this.addLocations(); 15187 this.fixMarkersWorldScreen(); 15188 this.attachDataToRegions(); 15189 this.loadDirectory(); 15190 if (this.options.labelsMarkers.on) { 15191 this.setLabelsMarkers(); 15192 } 15193 if (this.options.templates.labelRegion.indexOf("{{objects") !== -1) { 15194 this.setLabelsRegions(); 15195 } 15196 if (this.options.filters.on && 15197 this.options.filters.source === "database" && 15198 this.controllers.filters && 15199 this.controllers.filters.hideFilters) { 15200 this.controllers.filters.setFiltersCounter(); 15201 } 15202 this.hideLoadingMessage(); 15203 this.events.trigger("databaseLoaded"); 15204 this.updateFiltersState(); 15205 this.setChoropleth(); 15206 }); 15207 this.objectsRepository.events.on("schemaChanged", () => { 15208 this.objectsRepository.reload(); 15209 }); 15210 this.objectsRepository.events.on("updated", (obj) => { 15211 this.attachDataToRegions(obj); 15212 this.reloadRegionsFull(); 15213 }); 15214 this.objectsRepository.events.on("created", (obj) => { 15215 this.attachDataToRegions(obj); 15216 this.reloadRegionsFull(); 15217 }); 15218 this.objectsRepository.events.on("deleted", (id) => { 15219 this.attachDataToRegions(); 15220 this.reloadRegionsFull(); 15221 }); 15222 this.regionsRepository.events.on("load", () => { 15223 this.showLoadingMessage(); 15224 }); 15225 this.regionsRepository.events.on("loaded", () => { 15226 this.hideLoadingMessage(); 15227 this.reloadRegionsFull(); 15228 if (this.options.filters.on && 15229 this.options.filters.source === "regions" && 15230 this.controllers.filters && 15231 this.controllers.filters.hideFilters) { 15232 this.controllers.filters.setFiltersCounter(); 15233 } 15234 this.events.trigger("regionsLoaded"); 15235 }); 15236 this.regionsRepository.events.on("updated", (regionData) => { 15237 this.reloadRegionsFull(); 15238 }); 15239 this.regionsRepository.events.on("created", (regionData) => { 15240 this.reloadRegionsFull(); 15241 }); 15242 this.regionsRepository.events.on("deleted", (regionData) => { 15243 this.reloadRegionsFull(); 15244 }); 15245 this.setMenu(); 15246 this.setFilters(); 15247 if (this.options.menu.filterout.field) { 15248 const f = {}; 15249 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 15250 if (this.options.menu.source == "regions") ; 15251 else { 15252 this.objectsRepository.query.setFilterOut(f); 15253 } 15254 } 15255 this.setEventHandlers(); 15256 this.afterLoadBlockers--; 15257 if (!this.id) { 15258 this.finalizeMapLoading(); 15259 return; 15260 } 15261 if (!this.options.data_regions) { 15262 this.regionsRepository.find().done((data) => { 15263 this.afterLoadBlockers--; 15264 this.finalizeMapLoading(); 15265 }); 15266 } 15267 else {
15268 this.regionsRepository.loadDataFromResponse(this.options.data_regions); 15269 this.afterLoadBlockers--; 15270 } 15271 if (!this.options.data_objects) { 15272 if (this.options.database.loadOnStart || this.editMode) { 15273 this.objectsRepository.find().done((data) => { 15274 this.afterLoadBlockers--; 15275 this.finalizeMapLoading(); 15276 }); 15277 } 15278 else { 15279 this.afterLoadBlockers--; 15280 this.finalizeMapLoading(); 15281 } 15282 } 15283 else { 15284 if (this.editMode || this.options.database.loadOnStart) { 15285 this.objectsRepository.loadDataFromResponse(this.options.data_objects); 15286 this.afterLoadBlockers--; 15287 } 15288 else { 15289 this.afterLoadBlockers--; 15290 } 15291 delete this.options.data_regions; 15292 delete this.options.data_objects; 15293 this.finalizeMapLoading(); 15294 } 15295 } 15296 getGeoViewBoxFromSvgTag(svgTag) { 15297 const geo = $$A(svgTag).attr("mapsvg:geoViewBox") || $$A(svgTag).attr("mapsvg:geoviewbox"); 15298 if (geo) { 15299 const geoParts = geo.split(" ").map((p) => parseFloat(p)); 15300 if (geoParts.length == 4) { 15301 this.mapIsGeo = true; 15302 this.geoCoordinates = true; 15303 const sw = new GeoPoint(geoParts[3], geoParts[0]); 15304 const ne = new GeoPoint(geoParts[1], geoParts[2]); 15305 return new GeoViewBox(sw, ne); 15306 } 15307 } 15308 else { 15309 return null; 15310 } 15311 } 15312 svgLoadingFailed(resp) { 15313 if (resp.status == 404) { 15314 let msg = "MapSVG: file not found - " + 15315 this.options.source + 15316 "\n\nIf you moved MapSVG from another server please read the following docs page: https://mapsvg.com/docs/installation/moving"; 15317 if (this.editMode) { 15318 msg += 15319 "\n\nIf you know the correct path for the SVG file, please write it and press OK:"; 15320 const oldSvgPath = this.options.source; 15321 const userSvgPath = prompt(msg, oldSvgPath); 15322 if (userSvgPath !== null) { 15323 $$A.ajax({ url: userSvgPath + "?v=" + this.svgFileLastChanged }) 15324 .fail(function () { 15325 location.reload(); 15326 }) 15327 .done((xmlData) => { 15328 this.options.source = userSvgPath; 15329 this.renderSvgData(xmlData); 15330 const mapsRepo = new MapsRepository(); 15331 mapsRepo.update(this); 15332 }); 15333 } 15334 else { 15335 location.reload(); 15336 } 15337 } 15338 else { 15339 console.error(msg); 15340 } 15341 } 15342 else { 15343 const msg = "MapSVG: can't load SVG file for unknown reason. Please contact support: https://mapsvg.ticksy.com"; 15344 if (this.editMode) { 15345 alert(msg); 15346 } 15347 else { 15348 console.error(msg); 15349 } 15350 } 15351 } 15352 addLoadingMessage() { 15353 this.containers.loading = document.createElement("div"); 15354 this.containers.loading.className = "mapsvg-loading"; 15355 const loadingTextBlock = document.createElement("div"); 15356 loadingTextBlock.className = "mapsvg-loading-text"; 15357 loadingTextBlock.innerHTML = this.options.loadingText; 15358 const spinner = document.createElement("div"); 15359 spinner.className = "spinner-border spinner-border-sm"; 15360 this.containers.loading.appendChild(spinner); 15361 this.containers.loading.appendChild(loadingTextBlock); 15362 this.containers.map.appendChild(this.containers.loading); 15363 if (this.options.googleMaps.on) { 15364 $$A(this.containers.map).addClass("mapsvg-google-map-loading"); 15365 } 15366 } 15367 hideLoadingMessage() { 15368 $$A(this.containers.loading).hide(); 15369 } 15370 showLoadingMessage() { 15371 $$A(this.containers.loading).show(); 15372 } 15373 disableAnimation() { 15374 this.containers.map.classList.add("no-transitions"); 15375 } 15376 enableAnimation() { 15377 $$A(this.containers.map).removeClass("no-transitions"); 15378 } 15379 loadExtensions() { 15380 if (this.options.extension && 15381 $$A().mapSvg.extensions && 15382 $$A().mapSvg.extensions[_this.options.extension]) { 15383 const ext = $$A().mapSvg.extensions[_this.options.extension]; 15384 ext && ext.common(this); 15385 } 15386 } 15387 finalizeMapLoading() { 15388 if (this.afterLoadBlockers > 0 || this.loaded) { 15389 return; 15390 } 15391 this.selectRegionByIdFromUrl(); 15392 setTimeout(() => { 15393 this.movingItemsAdjustScreenPosition(); 15394 this.adjustStrokes(); 15395 setTimeout(() => { 15396 this.hideLoadingMessage(); 15397 $$A(this.containers.loading).find(".mapsvg-loading-text").hide(); 15398 this.enableAnimation(); 15399 }, 200); 15400 }, 100); 15401 this.loaded = true; 15402 this.events.trigger("afterLoad"); 15403 } 15404 selectRegionByIdFromUrl() { 15405 const match = RegExp("[?&]mapsvg_select=([^&]*)").exec(window.location.search); 15406 if (match) { 15407 const select = decodeURIComponent(match[1].replace(/\+/g, " ")); 15408 this.selectRegion(select); 15409 } 15410 if (window.location.hash) { 15411 const query = window.location.hash.replace("#/m/", ""); 15412 const region = this.getRegion(query); 15413 if (region && this.options.actions.map.afterLoad.selectRegion) { 15414 this.regionClickHandler(null, region); 15415 } 15416 } 15417 } 15418 createForm(options) { 15419 return new FormBuilder(options); 15420 } 15421 getApiUrl(path) { 15422 const server = new Server(); 15423 return server.getUrl(path); 15424 } 15425 getConverter() { 15426 return this.converter; 15427 } 15428 setChoropleth(options) { 15429 const _this = this; 15430 options = options || _this.options.choropleth; 15431 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 15432 $$A.extend(true, _this.options, { choropleth: options }); 15433 let needsRedraw = false;
15434 if (!_this.$gauge) { 15435 _this.$gauge = {}; 15436 _this.$gauge.gradient = $$A("<td> </td>").addClass("mapsvg-gauge-gradient"); 15437 _this.setGaugeGradientCSS(); 15438 _this.$gauge.container = $$A("<div />").addClass("mapsvg-gauge").hide(); 15439 _this.$gauge.table = $$A("<table />"); 15440 const tr = $$A("<tr />"); 15441 _this.$gauge.labelLow = $$A("<td>" + _this.options.choropleth.labels.low + "</td>"); 15442 _this.$gauge.labelHigh = $$A("<td>" + _this.options.choropleth.labels.high + "</td>"); 15443 tr.append(_this.$gauge.labelLow); 15444 tr.append(_this.$gauge.gradient); 15445 tr.append(_this.$gauge.labelHigh); 15446 _this.$gauge.table.append(tr); 15447 _this.$gauge.container.append(_this.$gauge.table); 15448 $$A(_this.containers.map).append(_this.$gauge.container); 15449 } 15450 if (!_this.options.choropleth.on && _this.$gauge.container.is(":visible")) { 15451 _this.$gauge.container.hide(); 15452 needsRedraw = true; 15453 } 15454 else if (_this.options.choropleth.on && !_this.$gauge.container.is(":visible")) { 15455 _this.$gauge.container.show(); 15456 needsRedraw = true; 15457 _this.regionsRepository.events.on("change", function () { 15458 _this.redrawGauge(); 15459 }); 15460 } 15461 if (options.colors) { 15462 _this.options.choropleth.colors.lowRGB = tinycolor(_this.options.choropleth.colors.low).toRgb(); 15463 _this.options.choropleth.colors.highRGB = tinycolor(_this.options.choropleth.colors.high).toRgb(); 15464 _this.options.choropleth.colors.diffRGB = { 15465 r: _this.options.choropleth.colors.highRGB.r - 15466 _this.options.choropleth.colors.lowRGB.r, 15467 g: _this.options.choropleth.colors.highRGB.g - 15468 _this.options.choropleth.colors.lowRGB.g, 15469 b: _this.options.choropleth.colors.highRGB.b - 15470 _this.options.choropleth.colors.lowRGB.b, 15471 a: _this.options.choropleth.colors.highRGB.a - 15472 _this.options.choropleth.colors.lowRGB.a, 15473 }; 15474 needsRedraw = true; 15475 _this.$gauge && _this.setGaugeGradientCSS(); 15476 } 15477 if (options.labels) { 15478 _this.$gauge.labelLow.html(_this.options.choropleth.labels.low); 15479 _this.$gauge.labelHigh.html(_this.options.choropleth.labels.high); 15480 } 15481 needsRedraw && _this.redrawGauge(); 15482 } 15483 redrawGauge() { 15484 const _this = this; 15485 _this.updateGaugeMinMax(); 15486 _this.regionsRedrawColors(); 15487 } 15488 updateGaugeMinMax() { 15489 const _this = this; 15490 _this.options.choropleth.min = 0; 15491 _this.options.choropleth.max = false; 15492 const values = []; 15493 _this.regions.forEach(function (r) { 15494 const gauge = r.data && r.data[_this.options.regionChoroplethField]; 15495 gauge != undefined && values.push(gauge); 15496 }); 15497 if (values.length > 0) { 15498 _this.options.choropleth.min = values.length == 1 ? 0 : Math.min.apply(null, values); 15499 _this.options.choropleth.max = Math.max.apply(null, values); 15500 _this.options.choropleth.maxAdjusted = 15501 _this.options.choropleth.max - _this.options.choropleth.min; 15502 } 15503 } 15504 setGaugeGradientCSS() { 15505 const _this = this; 15506 _this.$gauge.gradient.css({ 15507 background: "linear-gradient(to right," + 15508 _this.options.choropleth.colors.low + 15509 " 1%," + 15510 _this.options.choropleth.colors.high + 15511 " 100%)", 15512 filter: 'progid:DXImageTransform.Microsoft.gradient( startColorstr="' + 15513 _this.options.choropleth.colors.low + 15514 '", endColorstr="' + 15515 _this.options.choropleth.colors.high + 15516 '",GradientType=1 )', 15517 }); 15518 } 15519 get $map() { 15520 return $$A(this.getContainer("map")); 15521 } 15522 get $svg() { 15523 return $$A(this.getContainer("svg")); 15524 } 15525 get $popover() { 15526 return $$A(this.getContainer("popover")); 15527 } 15528 get $details() { 15529 return $$A(this.getContainer("detailsView")); 15530 } 15531 get $directory() { 15532 return $$A(this.getContainer("directory")); 15533 } 15534 get database() { 15535 return this.objectsRepository; 15536 } 15537 get regionsDatabase() { 15538 return this.regionsRepository; 15539 } 15540 } 15541 15542 exports.MapSVGMap = MapSVGMap; 15543 exports.arrayIndexed = ArrayIndexed; 15544 exports.customObject = CustomObject; 15545 exports.formBuilder = FormBuilder; 15546 exports.geoPoint = GeoPoint; 15547 exports.globals = MapSVG; 15548 exports.location = Location; 15549 exports.map = MapSVGMap; 15550 exports.mapsRepository = MapsRepository; 15551 exports.mapsV2Repository = MapsV2Repository; 15552 exports.marker = Marker; 15553 exports.query = Query; 15554 exports.repository = Repository; 15555 exports.schema = Schema; 15556 exports.schemaRepository = SchemaRepository; 15557 exports.screenPoint = ScreenPoint; 15558 exports.server = Server; 15559 exports.svgPoint = SVGPoint; 15560 15561 Object.defineProperty(exports, '__esModule', { value: true }); 15562 15563}))); 15564//# 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.