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 MapSVG.browser.safari = 140 MapSVG.userAgent.indexOf("safari") > -1 && MapSVG.userAgent.indexOf("chrome") === -1; 141 142 /** 143 * Contains device information 144 * @type {object} 145 * @static 146 * @property 147 */ 148 var ua = window.navigator.userAgent; 149 MapSVG.device = {}; 150 MapSVG.device.ios = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i); 151 MapSVG.device.android = !!ua.match(/Android/i); 152 153 if (!String.prototype.trim) { 154 String.prototype.trim = function () { 155 return this.replace(/^\s+|\s+$/g, ""); 156 }; 157 } 158 159 /** 160 * Converts mouse event object to x/y coordinates 161 * @param e 162 * @returns {{x: *, y: *}} 163 */ 164 MapSVG.mouseCoords = function (e) { 165 if (e.clientX) { 166 return { x: e.clientX + $(document).scrollLeft(), y: e.clientY + $(document).scrollTop() }; 167 } 168 if (e.pageX) { 169 return { x: e.pageX, y: e.pageY }; 170 } else if (MapSVG.touchDevice) { 171 e = e.originalEvent || e; 172 return e.touches && e.touches[0] 173 ? { x: e.touches[0].pageX, y: e.touches[0].pageY } 174 : { x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY }; 175 } 176 }; 177 178 /** 179 * Adds new instance of the map 180 * @param {MapSVG.Map} mapsvg 181 */ 182 MapSVG.addInstance = function (mapsvg) {
183 MapSVG.instances.push(mapsvg); 184 }; 185 186 MapSVG.get = function (index) { 187 return MapSVG.instances[index]; 188 }; 189 190 MapSVG.getById = function (id) { 191 var instance = MapSVG.instances.filter(function (i) { 192 return i.id == id; 193 }); 194 if (instance.length > 0) { 195 return instance[0]; 196 } 197 }; 198 199 MapSVG.getByContainerId = function (id) { 200 var instance = MapSVG.instances.filter(function (i) { 201 return i.$map.attr("id") == id; 202 }); 203 if (instance.length > 0) { 204 return instance[0]; 205 } 206 }; 207 208 MapSVG.extend = function (sub, base) { 209 sub.prototype = Object.create(base.prototype); 210 sub.prototype.constructor = sub; 211 }; 212 213 MapSVG.ucfirst = function (string) { 214 return string.charAt(0).toUpperCase() + string.slice(1); 215 }; 216 MapSVG.parseBoolean = function (string) { 217 switch (String(string).toLowerCase()) { 218 case "on": 219 case "true": 220 case "1": 221 case "yes": 222 case "y": 223 return true; 224 case "off": 225 case "false": 226 case "0": 227 case "no": 228 case "n": 229 return false; 230 default: 231 return undefined; 232 } 233 }; 234 MapSVG.isNumber = function (n) { 235 return !isNaN(parseFloat(n)) && isFinite(n); 236 }; 237 238 MapSVG.safeURL = function (url) { 239 if (url.indexOf("http://") == 0 || url.indexOf("https://") == 0) 240 url = "//" + url.split("://").pop(); 241 return url.replace(/^.*\/\/[^\/]+/, ""); 242 }; 243 244 MapSVG.convertToText = function (obj) { 245 //create an array that will later be joined into a string. 246 var string = []; 247 248 //is object 249 // Both arrays and objects seem to return "object" 250 // when typeof(obj) is applied to them. So instead 251 // I am checking to see if they have the property 252 // join, which normal objects don't have but 253 // arrays do. 254 if (obj === null) { 255 return null; 256 } 257 if (obj === undefined) { 258 return '""'; 259 } else if (typeof obj == "object" && obj.join == undefined) { 260 var prop; 261 for (prop in obj) { 262 if (obj.hasOwnProperty(prop)) { 263 var key = '"' + prop.replace(/\"/g, '\\"') + '"'; //prop.search(/[^a-zA-Z]+/) === -1 ? prop : ... 264 string.push(key + ": " + MapSVG.convertToText(obj[prop])); 265 } 266 } 267 return "{" + string.join(",") + "}"; 268 269 //is array 270 } else if (typeof obj == "object" && !(obj.join == undefined)) { 271 var prop; 272 for (prop in obj) { 273 string.push(MapSVG.convertToText(obj[prop])); 274 } 275 return "[" + string.join(",") + "]"; 276 277 //is function 278 } else if (typeof obj == "function") { 279 return obj.toString().replace("function anonymous", "function"); 280 // string.push(obj.toString().replace('function anonymous','function')); 281 282 //all other values can be done with JSON.stringify 283 } else { 284 return JSON.stringify(obj); 285 // var s = JSON.stringify(obj); 286 // string.push(s); 287 } 288 }; 289 290 // Create Element.remove() function if not exists 291 if (!("remove" in Element.prototype)) { 292 Element.prototype.remove = function () { 293 if (this.parentNode) { 294 this.parentNode.removeChild(this); 295 } 296 }; 297 } 298 299 Math.hypot = 300 Math.hypot || 301 function () { 302 var y = 0; 303 var length = arguments.length; 304 305 for (var i = 0; i < length; i++) { 306 if (arguments[i] === Infinity || arguments[i] === -Infinity) { 307 return Infinity; 308 } 309 y += arguments[i] * arguments[i]; 310 } 311 return Math.sqrt(y); 312 }; 313 SVGElement.prototype.getTransformToElement = 314 SVGElement.prototype.getTransformToElement || 315 function (toElement) { 316 let value; 317 try { 318 value = toElement.getScreenCTM().inverse().multiply(this.getScreenCTM()); 319 } catch (e) { 320 return; 321 } 322 return value; 323 }; 324 325 Map.prototype.toArray = function () { 326 return Array.from(this, ([name, value]) => value); 327 }; 328 329 MapSVG.ResizeSensor = class ResizeSensor { 330 constructor(element, callback) { 331 var _this = this; 332 _this.element = element; 333 _this.callback = callback; 334 var style = getComputedStyle(element); 335 var zIndex = parseInt(style.zIndex); 336 if (isNaN(zIndex)) { 337 zIndex = 0; 338 } 339 zIndex--; 340 _this.expand = document.createElement("div"); 341 _this.expand.style.position = "absolute";
342 _this.expand.style.left = "0px"; 343 _this.expand.style.top = "0px"; 344 _this.expand.style.right = "0px"; 345 _this.expand.style.bottom = "0px"; 346 _this.expand.style.overflow = "hidden"; 347 _this.expand.style.zIndex = zIndex.toString(); 348 _this.expand.style.visibility = "hidden"; 349 var expandChild = document.createElement("div"); 350 expandChild.style.position = "absolute"; 351 expandChild.style.left = "0px"; 352 expandChild.style.top = "0px"; 353 expandChild.style.width = "10000000px"; 354 expandChild.style.height = "10000000px"; 355 _this.expand.appendChild(expandChild); 356 _this.shrink = document.createElement("div"); 357 _this.shrink.style.position = "absolute"; 358 _this.shrink.style.left = "0px"; 359 _this.shrink.style.top = "0px"; 360 _this.shrink.style.right = "0px"; 361 _this.shrink.style.bottom = "0px"; 362 _this.shrink.style.overflow = "hidden"; 363 _this.shrink.style.zIndex = zIndex.toString(); 364 _this.shrink.style.visibility = "hidden"; 365 var shrinkChild = document.createElement("div"); 366 shrinkChild.style.position = "absolute"; 367 shrinkChild.style.left = "0px"; 368 shrinkChild.style.top = "0px"; 369 shrinkChild.style.width = "200%"; 370 shrinkChild.style.height = "200%"; 371 _this.shrink.appendChild(shrinkChild); 372 _this.element.appendChild(_this.expand); 373 _this.element.appendChild(_this.shrink); 374 var size = element.getBoundingClientRect(); 375 _this.currentWidth = size.width; 376 _this.currentHeight = size.height; 377 _this.setScroll(); 378 _this.expand.addEventListener("scroll", function () { 379 _this.onScroll(); 380 }); 381 _this.shrink.addEventListener("scroll", function () { 382 _this.onScroll(); 383 }); 384 } 385 onScroll() { 386 var _this = this; 387 var size = _this.element.getBoundingClientRect(); 388 var newWidth = size.width; 389 var newHeight = size.height; 390 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 391 _this.currentWidth = newWidth; 392 _this.currentHeight = newHeight; 393 _this.callback(); 394 } 395 this.setScroll(); 396 } 397 setScroll() { 398 this.expand.scrollLeft = 10000000; 399 this.expand.scrollTop = 10000000; 400 this.shrink.scrollLeft = 10000000; 401 this.shrink.scrollTop = 10000000; 402 } 403 destroy() { 404 this.expand.remove(); 405 this.shrink.remove(); 406 } 407 }; 408 409 MapSVG.nonce = function () { 410 return mapsvg_runtime_vars.nonce; 411 }; 412 413 /** 414 * Adds # hash at the beginning of HEX color value 415 * @param {String} color 416 * @returns {String} 417 * @private 418 */ 419 MapSVG.fixColorHash = (color) => { 420 const hexColorNoHash = new RegExp(/^([0-9a-f]{3}|[0-9a-f]{6})$/i); 421 if (color && color.match(hexColorNoHash) !== null) { 422 color = "#" + color; 423 } 424 return color; 425 }; 426 427 /** 428 * Delays method execution. 429 * For example, it can be used in search input fields to prevent sending 430 * an ajax request on each key press. 431 * @param {Function} method 432 * @param {number} delay 433 * @param {object} scope 434 * @param {array} params 435 * @private 436 */ 437 MapSVG.throttle = (method, delay, scope, params) => { 438 clearTimeout(method._tId); 439 method._tId = setTimeout(function () { 440 method.apply(scope, params); 441 }, delay); 442 }; 443 MapSVG.geocode = (query, callback) => { 444 if (!window.google) { 445 console.error("MapSVG: can't do Geocoding - Google Maps API is not loaded."); 446 jQuery.growl.error({ 447 title: "Error", 448 message: "Google Maps API files are not loaded", 449 }); 450 return false;
451 } 452 // if (!MapSVG.options.google_api_key) { 453 // jQuery.growl.error({ 454 // title: "Error", 455 // message: "Google Maps API key is not provided", 456 // }); 457 // return false; 458 // } 459 if (!MapSVG.geocoder) { 460 MapSVG.geocoder = new google.maps.Geocoder(); 461 } 462 463 MapSVG.throttle(MapSVG.geocoder.geocode, 500, MapSVG.geocoder, [ 464 query, 465 function (results, status) { 466 if (status === "OK") { 467 callback(results); 468 } else { 469 jQuery.growl.error({ 470 title: "Error: " + status, 471 message: 472 "There is some problem with Google API keys. See browser's console for more details", 473 }); 474 } 475 }, 476 ]); 477 }; 478 479 MapSVG.handleFailedRequest = (response) => { 480 var message = ""; 481 482 if (response.status === 403) { 483 if (response.responseText.indexOf("Wordfence") !== -1) { 484 message += 485 "The request has been blocked by Wordfence. " + 486 'Switch Wordfence to "Learning mode", and save the map settings again. ' + 487 "If the settings are saved successfully, you can switch Wordfence back to normal mode."; 488 } else { 489 message += 490 "The request has been blocked by your server. " + 491 "Do you have mod_sec Apache's module enabled? If that's the case you need to change its settings."; 492 } 493 } else { 494 if (response && response.responseText) { 495 try { 496 var _response = JSON.parse(response.responseText); 497 if (_response && _response.data && _response.data.error) { 498 message = _response.data.error; 499 } 500 } catch (e) { 501 } 502 } 503 } 504 505 $.growl.error({ 506 title: "Error: " + response.status + " " + response.statusText, 507 message: message, 508 duration: 30000, 509 }); 510 }; 511 512 if (!Object.values) { 513 Object.values = function (object) { 514 return Object.keys(object).map(function (k) { 515 return object[k]; 516 }); 517 }; 518 } 519 520 window.MapSVG = MapSVG; 521 522 const defRegionTemplate = "<div>\n" + 523 " <p>This is the demo content of the <strong>Region %templateType%</strong>.</p>\n" + 524 ' <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' + 525 ' <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' + 526 "</div>\n" + 527 "<hr />\n\n" + 528 "<!-- Region fields are available in this template -->\n" + 529 "<h5>{{#if title}} {{title}} {{else}} {{id}} {{/if}}</h5>\n" + 530 "<p>Status: {{status_text}}</p>\n\n" + 531 "<!-- Show all linked Database Objects: -->\n" + 532 "{{#each objects}}\n\n" + 533 " <!-- DB Object are available inside of this block -->\n\n" + 534 " <h5>{{title}}</h5>\n" + 535 " <!-- When you need to render a field as HTML, use 3 curly braces instead of 2:-->\n" + 536 " <p>{{{description}}}</p>\n" + 537 " <p><em>{{location.address.formatted}}</em></p>\n\n" + 538 " <!-- Show all images: -->\n" + 539 " {{#each images}}\n" + 540 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 541 " <!-- are available in this block -->\n" + 542 ' <img src="{{thumbnail}}" />\n' + 543 " {{/each}}\n\n" + 544 "{{/each}}"; 545 const defDBTemplate = "<div>\n" + 546 " <p>This is the demo content of the <strong>DB Object %templateType%</strong>.</p>\n" + 547 ' <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' + 548 ' <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' + 549 "</div>\n" + 550 "<hr />\n\n" + 551 "<!-- DB Object fields are available in this template. -->\n" + 552 "<h5>{{title}}</h5>\n" + 553 "<!-- When you need to render a fields as HTML, use 3 curly braces instead of 2:-->\n" + 554 "<p>{{{description}}}</p>\n" + 555 "<p><em>{{location.address.formatted}}</em></p>\n\n" + 556 "<!-- Show all images: -->\n" + 557 "{{#each images}}\n" + 558 ' <!-- Image fields "thumbnail", "medium", "full" -->\n' + 559 " <!-- are available in this block -->\n" + 560 ' <img src="{{thumbnail}}" />\n' + 561 "{{/each}}\n\n" + 562 "<!-- Show all linked Regions, comma-separated: -->\n" + 563 "<p> Regions: \n" + 564 " {{#each regions}}\n" + 565 " <!-- Region fields are available in this block -->\n" + 566 " {{#if title}}\n" + 567 " {{title}}\n" + 568 " {{else}}\n" + 569 " {{id}}\n" + 570 " {{/if}}{{#unless @last}}, {{/unless}}\n" + 571 " {{/each}}\n" + 572 "</p>"; 573 const dirItemItemTemplate = "<!-- If Directory Source = Database: DB Object fields are available in this template -->\n" + 574 "<!-- If Directory Source = Regions: Region fields are available in this template -->\n" + 575 "{{title}}"; 576 const DefaultOptions = { 577 source: "", 578 markerLastID: 0, 579 regionLastID: 0, 580 dataLastID: 1, 581 disableAll: false, 582 width: null, 583 height: null, 584 lockAspectRatio: false, 585 padding: { top: 0, left: 0, right: 0, bottom: 0 }, 586 maxWidth: null, 587 maxHeight: null, 588 minWidth: null, 589 minHeight: null, 590 loadingText: "Loading map...", 591 colorsIgnore: false, 592 colors: { 593 baseDefault: "#000000", 594 background: "#eeeeee", 595 selected: 40, 596 hover: 20, 597 directory: "#fafafa", 598 detailsView: "", 599 status: {},
600 clusters: "", 601 clustersBorders: "", 602 clustersText: "", 603 clustersHover: "", 604 clustersHoverBorders: "", 605 clustersHoverText: "", 606 markers: { 607 base: { opacity: 100, saturation: 100 }, 608 hovered: { opacity: 100, saturation: 100 }, 609 unhovered: { opacity: 40, saturation: 100 }, 610 active: { opacity: 100, saturation: 100 }, 611 inactive: { opacity: 40, saturation: 100 }, 612 }, 613 }, 614 regions: {}, 615 clustering: { on: false }, 616 viewBox: [], 617 cursor: "default", 618 manualRegions: false, 619 onClick: null, 620 mouseOver: null, 621 mouseOut: null, 622 menuOnClick: null, 623 beforeLoad: null, 624 afterLoad: null, 625 zoom: { 626 on: true, 627 limit: [0, 22], 628 delta: 2, 629 buttons: { on: true, location: "right" }, 630 mousewheel: true, 631 fingers: true, 632 hideSvg: false, 633 hideSvgZoomLevel: 7, 634 }, 635 scroll: { on: true, limit: false, background: false, spacebar: false }, 636 responsive: true, 637 tooltips: { on: false, position: "bottom-right", template: "", maxWidth: "", minWidth: 100 }, 638 popovers: { 639 on: false, 640 position: "top", 641 template: "", 642 centerOn: true, 643 width: 300, 644 maxWidth: 50, 645 maxHeight: 50, 646 }, 647 multiSelect: false, 648 regionStatuses: { 649 "1": { label: "Enabled", value: "1", color: "", disabled: false }, 650 "0": { label: "Disabled", value: "0", color: "", disabled: true }, 651 }, 652 events: { 653 afterLoad: "function(){\n" + 654 " // var mapsvg = this;\n" + 655 " // var regions = mapsvg.regions;\n" + 656 " // var dbObjects = mapsvg.database.getLoaded();\n" + 657 "}", 658 beforeLoad: "function(){\n" + 659 " // var mapsvg = this;\n" + 660 " // var settings = mapsvg.options;\n" + 661 " // console.log(settings);\n" + 662 "}", 663 databaseLoaded: "function (){\n" + 664 " // var mapsvg = this;\n" + 665 " // var dbObjects = mapsvg.database.getLoaded();\n" + 666 "}", 667 "click.region": "function (e, mapsvg){\n" + 668 " // var region = this;\n" + 669 " // console.log(region);\n" + 670 "}", 671 "mouseover.region": "function (e, mapsvg){\n" + 672 " // var region = this;\n" + 673 " // console.log(region);\n" + 674 "}", 675 "mouseout.region": "function (e, mapsvg){\n" + 676 " // var region = this;\n" + 677 " // console.log(region);\n" + 678 "}", 679 "click.marker": "function (e, mapsvg){\n" + 680 " // var marker = this;\n" + 681 " // console.log(marker);\n" + 682 "}", 683 "mouseover.marker": "function (e, mapsvg){\n" + 684 " // var marker = this;\n" + 685 " // console.log(marker);\n" + 686 "}", 687 "mouseout.marker": "function (e, mapsvg){\n" + 688 " // var marker = this;\n" + 689 " // console.log(marker);\n" + 690 "}", 691 "click.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 692 "mouseover.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 693 "mouseout.directoryItem": "function (e, regionOrObject, mapsvg){\n" + " // var itemjQueryObject = this;\n" + "}", 694 "shown.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 695 "closed.popover": "function (mapsvg){\n" + " // var popoverjQueryObject = this;\n" + "}", 696 "closed.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 697 "shown.detailsView": "function (mapsvg){\n" + " // var detailsjQueryObject = this;\n" + "}", 698 }, 699 css: "#mapsvg-map-%id% .mapsvg-tooltip {\n\n}\n" + 700 "#mapsvg-map-%id% .mapsvg-popover {\n\n}\n" + 701 "#mapsvg-map-%id% .mapsvg-details-container {\n\n}\n" + 702 "#mapsvg-map-%id% .mapsvg-directory-item {\n\n}\n" + 703 "#mapsvg-map-%id% .mapsvg-region-label {\n" + 704 " /* background-color: rgba(255,255,255,.6); */\n" + 705 " font-size: 11px;\n" + 706 " padding: 3px 5px;\n" + 707 " border-radius: 4px;\n" + 708 "}\n" + 709 "#mapsvg-map-%id% .mapsvg-marker-label {\n" + 710 " padding: 3px 5px;\n" + 711 " /*\n" + 712 " border-radius: 4px;\n" + 713 " background-color: white;\n" + 714 " margin-top: -4px;\n" + 715 " */\n}\n" + 716 "#mapsvg-map-%id% .mapsvg-filters-wrap {\n\n}\n" + 717 "\n\n\n\n\n\n", 718 templates: { 719 popoverRegion: defRegionTemplate 720 .replace(/%templateType%/g, "Popover") 721 .replace(/%templateTypeSnake%/g, "popover"), 722 popoverMarker: defDBTemplate 723 .replace(/%templateType%/g, "Popover") 724 .replace(/%templateTypeSnake%/g, "popover"), 725 tooltipRegion: "<!-- Region fields are available in this template -->\n{{id}} - {{title}}", 726 tooltipMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 727 directoryItem: dirItemItemTemplate, 728 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>', 729 detailsView: defDBTemplate 730 .replace(/%templateType%/g, "Details View") 731 .replace(/%templateTypeSnake%/g, "detailsView"), 732 detailsViewRegion: defRegionTemplate 733 .replace(/%templateType%/g, "Details View") 734 .replace(/%templateTypeSnake%/g, "detailsView"), 735 labelMarker: "<!-- DB Object fields are available in this template -->\n{{title}}", 736 labelRegion: "<!-- Region fields are available in this template -->\n{{title}}", 737 labelLocation: "You are here!", 738 }, 739 choropleth: { 740 on: false, 741 source: "regions", 742 sourceFieldSelect: { 743 on: false, 744 variants: [], 745 }, 746 bubbleMode: false, 747 bubbleSize: { 748 min: 20, 749 max: 40, 750 }, 751 labels: { low: "low", high: "high" }, 752 colors: { lowRGB: null, highRGB: null, low: "#550000", high: "#ee0000", noData: "#333333" }, 753 min: 0, 754 max: 0, 755 coloring: { 756 mode: "gradient", 757 noData: { 758 color: "#999999", 759 description: "No data", 760 }, 761 gradient: { 762 colors: { 763 lowRGB: null, 764 highRGB: null, 765 diffRGB: null, 766 low: "#550000", 767 high: "#ee0000", 768 }, 769 labels: { 770 low: "low", 771 high: "high", 772 }, 773 values: { 774 min: null, 775 max: null, 776 maxAdjusted: null, 777 }, 778 }, 779 palette: { 780 outOfRange: { 781 color: "#ececec", 782 description: "Out of range", 783 }, 784 colors: [ 785 { 786 color: "#550000", 787 valueFrom: 0, 788 valueTo: 50, 789 description: "", 790 }, 791 ], 792 }, 793 legend: { 794 on: true, 795 layout: "vertical", 796 container: "bottom-left", 797 title: "Choropleth map", 798 text: "", 799 description: "", 800 width: "20%", 801 height: "20%", 802 }, 803 }, 804 }, 805 filters: { 806 on: true, 807 source: "database", 808 location: "header", 809 modalLocation: "map", 810 width: "100%", 811 hide: false, 812 showButtonText: "Filters", 813 clearButtonText: "Clear all",
814 clearButton: false, 815 searchButton: false, 816 searchButtonText: "Search", 817 padding: "", 818 }, 819 menu: { 820 on: false, 821 hideOnMobile: true, 822 location: "leftSidebar", 823 locationMobile: "leftSidebar", 824 search: false, 825 containerId: "", 826 searchPlaceholder: "Search...", 827 searchFallback: false, 828 source: "database", 829 showFirst: "map", 830 showMapOnClick: true, 831 minHeight: "400", 832 sortBy: "id", 833 sortDirection: "desc", 834 categories: { 835 on: false, 836 groupBy: "", 837 hideEmpty: true, 838 collapse: true, 839 collapseOther: true, 840 }, 841 clickActions: { 842 region: "default", 843 marker: "default", 844 directoryItem: { 845 triggerClick: true, 846 showPopover: false, 847 showDetails: true, 848 }, 849 }, 850 detailsViewLocation: "overDirectory", 851 noResultsText: "No results found", 852 filterout: { field: "", cond: "=", val: "" }, 853 }, 854 database: { 855 pagination: { 856 on: true, 857 perpage: 30, 858 next: "Next", 859 prev: "Prev.", 860 showIn: "both", 861 }, 862 loadOnStart: true, 863 table: "", 864 }, 865 actions: { 866 map: { 867 afterLoad: { 868 selectRegion: false, 869 }, 870 }, 871 region: { 872 mouseover: { 873 showTooltip: false, 874 }, 875 click: { 876 addIdToUrl: false, 877 showDetails: true, 878 showDetailsFor: "region", 879 filterDirectory: false, 880 loadObjects: false, 881 showPopover: false, 882 showPopoverFor: "region", 883 goToLink: false, 884 linkField: "Region.link", 885 }, 886 touch: { 887 showPopover: false, 888 }, 889 }, 890 marker: { 891 mouseover: { 892 showTooltip: false, 893 }, 894 click: { 895 showDetails: true, 896 showPopover: false, 897 goToLink: false, 898 linkField: "Object.link", 899 }, 900 touch: { 901 showPopover: false, 902 }, 903 }, 904 directoryItem: { 905 click: { 906 showDetails: true, 907 showPopover: false, 908 goToLink: false, 909 selectRegion: true, 910 fireRegionOnClick: true, 911 linkField: "Object.link", 912 }, 913 hover: { 914 centerOnMarker: false, 915 }, 916 }, 917 }, 918 detailsView: { 919 location: "map", 920 containerId: "", 921 width: "100%", 922 mobileFullscreen: true, 923 }, 924 mobileView: { 925 labelMap: "Map", 926 labelList: "List", 927 labelClose: "Close", 928 }, 929 googleMaps: { 930 on: false, 931 apiKey: "", 932 loaded: false, 933 center: "auto", 934 type: "roadmap", 935 minZoom: 1, 936 style: "default", 937 styleJSON: [], 938 language: "en", 939 }, 940 groups: [], 941 floors: [], 942 layersControl: { 943 on: false, 944 position: "top-left", 945 label: "Show on map", 946 expanded: true, 947 maxHeight: "100%", 948 }, 949 floorsControl: { 950 on: false, 951 position: "top-left", 952 label: "Floors", 953 expanded: false, 954 maxHeight: "100%", 955 }, 956 containers: { 957 leftSidebar: { on: false, width: "250px" }, 958 rightSidebar: { on: false, width: "250px" }, 959 header: { on: true, height: "auto" }, 960 footer: { on: false, height: "auto" }, 961 }, 962 labelsMarkers: { on: false }, 963 labelsRegions: { on: false }, 964 svgFileVersion: 1, 965 fitMarkers: false, 966 fitMarkersOnStart: false, 967 fitSingleMarkerZoom: 20, 968 controls: { 969 location: "right", 970 zoom: true, 971 zoomReset: false, 972 userLocation: false, 973 previousMap: false, 974 }, 975 previousMapsIds: [], 976 }; 977 978 // TinyColor v1.4.1 979 // https://github.com/bgrins/TinyColor 980 // Brian Grinstead, MIT License 981 982 //(function(Math) { 983 984 var trimLeft = /^\s+/, 985 trimRight = /\s+$/, 986 tinyCounter = 0, 987 mathRound = Math.round, 988 mathMin = Math.min, 989 mathMax = Math.max, 990 mathRandom = Math.random; 991 992 function tinycolor(color, opts) { 993 color = color ? color : ""; 994 opts = opts || {}; 995 996 // If input is already a tinycolor, return itself 997 if (color instanceof tinycolor) { 998 return color; 999 } 1000 // If we are called as a function, call using new instead 1001 if (!(this instanceof tinycolor)) { 1002 return new tinycolor(color, opts); 1003 } 1004 1005 var rgb = inputToRGB(color); 1006 (this._originalInput = color), 1007 (this._r = rgb.r), 1008 (this._g = rgb.g), 1009 (this._b = rgb.b), 1010 (this._a = rgb.a), 1011 (this._roundA = mathRound(100 * this._a) / 100), 1012 (this._format = opts.format || rgb.format); 1013 this._gradientType = opts.gradientType; 1014 1015 // Don't let the range of [0,255] come back in [0,1]. 1016 // Potentially lose a little bit of precision here, but will fix issues where 1017 // .5 gets interpreted as half of the total, instead of half of 1 1018 // If it was supposed to be 128, this was already taken care of b
vendor: 11,167 bytes, lines 1018-1336
1018y `inputToRgb` 1019 if (this._r < 1) { 1020 this._r = mathRound(this._r); 1021 } 1022 if (this._g < 1) { 1023 this._g = mathRound(this._g); 1024 } 1025 if (this._b < 1) { 1026 this._b = mathRound(this._b); 1027 } 1028 1029 this._ok = rgb.ok; 1030 this._tc_id = tinyCounter++; 1031 } 1032 1033 tinycolor.prototype = { 1034 isDark: function () { 1035 return this.getBrightness() < 128; 1036 }, 1037 isLight: function () { 1038 return !this.isDark(); 1039 }, 1040 isValid: function () { 1041 return this._ok; 1042 }, 1043 getOriginalInput: function () { 1044 return this._originalInput; 1045 }, 1046 getFormat: function () { 1047 return this._format; 1048 }, 1049 getAlpha: function () { 1050 return this._a; 1051 }, 1052 getBrightness: function () { 1053 //http://www.w3.org/TR/AERT#color-contrast 1054 var rgb = this.toRgb(); 1055 return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; 1056 }, 1057 getLuminance: function () { 1058 //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef 1059 var rgb = this.toRgb(); 1060 var RsRGB, GsRGB, BsRGB, R, G, B; 1061 RsRGB = rgb.r / 255; 1062 GsRGB = rgb.g / 255; 1063 BsRGB = rgb.b / 255; 1064 1065 if (RsRGB <= 0.03928) { 1066 R = RsRGB / 12.92; 1067 } else { 1068 R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); 1069 } 1070 if (GsRGB <= 0.03928) { 1071 G = GsRGB / 12.92; 1072 } else { 1073 G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); 1074 } 1075 if (BsRGB <= 0.03928) { 1076 B = BsRGB / 12.92; 1077 } else { 1078 B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); 1079 } 1080 return 0.2126 * R + 0.7152 * G + 0.0722 * B; 1081 }, 1082 setAlpha: function (value) { 1083 this._a = boundAlpha(value); 1084 this._roundA = mathRound(100 * this._a) / 100; 1085 return this; 1086 }, 1087 toHsv: function () { 1088 var hsv = rgbToHsv(this._r, this._g, this._b); 1089 return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; 1090 }, 1091 toHsvString: function () { 1092 var hsv = rgbToHsv(this._r, this._g, this._b); 1093 var h = mathRound(hsv.h * 360), 1094 s = mathRound(hsv.s * 100), 1095 v = mathRound(hsv.v * 100); 1096 return this._a == 1 1097 ? "hsv(" + h + ", " + s + "%, " + v + "%)" 1098 : "hsva(" + h + ", " + s + "%, " + v + "%, " + this._roundA + ")"; 1099 }, 1100 toHsl: function () { 1101 var hsl = rgbToHsl(this._r, this._g, this._b); 1102 return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; 1103 }, 1104 toHslString: function () { 1105 var hsl = rgbToHsl(this._r, this._g, this._b); 1106 var h = mathRound(hsl.h * 360), 1107 s = mathRound(hsl.s * 100), 1108 l = mathRound(hsl.l * 100); 1109 return this._a == 1 1110 ? "hsl(" + h + ", " + s + "%, " + l + "%)" 1111 : "hsla(" + h + ", " + s + "%, " + l + "%, " + this._roundA + ")"; 1112 }, 1113 toHex: function (allow3Char) { 1114 return rgbToHex(this._r, this._g, this._b, allow3Char); 1115 }, 1116 toHexString: function (allow3Char) { 1117 return "#" + this.toHex(allow3Char); 1118 }, 1119 toHex8: function (allow4Char) { 1120 return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char); 1121 }, 1122 toHex8String: function (allow4Char) { 1123 return "#" + this.toHex8(allow4Char); 1124 }, 1125 toRgb: function () { 1126 return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a }; 1127 }, 1128 toRgbString: function () { 1129 return this._a == 1 1130 ? "rgb(" + 1131 mathRound(this._r) + 1132 ", " + 1133 mathRound(this._g) + 1134 ", " + 1135 mathRound(this._b) + 1136 ")" 1137 : "rgba(" + 1138 mathRound(this._r) + 1139 ", " + 1140 mathRound(this._g) + 1141 ", " + 1142 mathRound(this._b) + 1143 ", " + 1144 this._roundA + 1145 ")"; 1146 }, 1147 toPercentageRgb: function () { 1148 return { 1149 r: mathRound(bound01(this._r, 255) * 100) + "%", 1150 g: mathRound(bound01(this._g, 255) * 100) + "%", 1151 b: mathRound(bound01(this._b, 255) * 100) + "%", 1152 a: this._a, 1153 }; 1154 }, 1155 toPercentageRgbString: function () { 1156 return this._a == 1 1157 ? "rgb(" + 1158 mathRound(bound01(this._r, 255) * 100) + 1159 "%, " + 1160 mathRound(bound01(this._g, 255) * 100) + 1161 "%, " + 1162 mathRound(bound01(this._b, 255) * 100) + 1163 "%)" 1164 : "rgba(" + 1165 mathRound(bound01(this._r, 255) * 100) + 1166 "%, " + 1167 mathRound(bound01(this._g, 255) * 100) + 1168 "%, " + 1169 mathRound(bound01(this._b, 255) * 100) + 1170 "%, " + 1171 this._roundA + 1172 ")"; 1173 }, 1174 toName: function () { 1175 if (this._a === 0) { 1176 return "transparent"; 1177 } 1178 1179 if (this._a < 1) { 1180 return false; 1181 } 1182 1183 return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; 1184 }, 1185 toFilter: function (secondColor) { 1186 var hex8String = "#" + rgbaToArgbHex(this._r, this._g, this._b, this._a); 1187 var secondHex8String = hex8String; 1188 var gradientType = this._gradientType ? "GradientType = 1, " : ""; 1189 1190 if (secondColor) { 1191 var s = tinycolor(secondColor); 1192 secondHex8String = "#" + rgbaToArgbHex(s._r, s._g, s._b, s._a); 1193 } 1194 1195 return ( 1196 "progid:DXImageTransform.Microsoft.gradient(" + 1197 gradientType + 1198 "startColorstr=" + 1199 hex8String + 1200 ",endColorstr=" + 1201 secondHex8String + 1202 ")" 1203 ); 1204 }, 1205 toString: function (format) { 1206 var formatSet = !!format; 1207 format = format || this._format; 1208 1209 var formattedString = false; 1210 var hasAlpha = this._a < 1 && this._a >= 0; 1211 var needsAlphaFormat = 1212 !formatSet && 1213 hasAlpha && 1214 (format === "hex" || 1215 format === "hex6" || 1216 format === "hex3" || 1217 format === "hex4" || 1218 format === "hex8" || 1219 format === "name"); 1220 1221 if (needsAlphaFormat) { 1222 // Special case for "transparent", all other non-alpha formats 1223 // will return rgba when there is transparency. 1224 if (format === "name" && this._a === 0) { 1225 return this.toName(); 1226 } 1227 return this.toRgbString(); 1228 } 1229 if (format === "rgb") { 1230 formattedString = this.toRgbString(); 1231 } 1232 if (format === "prgb") { 1233 formattedString = this.toPercentageRgbString(); 1234 } 1235 if (format === "hex" || format === "hex6") { 1236 formattedString = this.toHexString(); 1237 } 1238 if (format === "hex3") { 1239 formattedString = this.toHexString(true); 1240 } 1241 if (format === "hex4") { 1242 formattedString = this.toHex8String(true); 1243 } 1244 if (format === "hex8") { 1245 formattedString = this.toHex8String(); 1246 } 1247 if (format === "name") { 1248 formattedString = this.toName(); 1249 } 1250 if (format === "hsl") { 1251 formattedString = this.toHslString(); 1252 } 1253 if (format === "hsv") { 1254 formattedString = this.toHsvString(); 1255 } 1256 1257 return formattedString || this.toHexString(); 1258 }, 1259 clone: function () { 1260 return tinycolor(this.toString()); 1261 }, 1262 1263 _applyModification: function (fn, args) { 1264 var color = fn.apply(null, [this].concat([].slice.call(args))); 1265 this._r = color._r; 1266 this._g = color._g; 1267 this._b = color._b; 1268 this.setAlpha(color._a); 1269 return this; 1270 }, 1271 lighten: function () { 1272 return this._applyModification(lighten, arguments); 1273 }, 1274 brighten: function () { 1275 return this._applyModification(brighten, arguments); 1276 }, 1277 darken: function () { 1278 return this._applyModification(darken, arguments); 1279 }, 1280 desaturate: function () { 1281 return this._applyModification(desaturate, arguments); 1282 }, 1283 saturate: function () { 1284 return this._applyModification(saturate, arguments); 1285 }, 1286 greyscale: function () { 1287 return this._applyModification(greyscale, arguments); 1288 }, 1289 spin: function () { 1290 return this._applyModification(spin, arguments); 1291 }, 1292 1293 _applyCombination: function (fn, args) { 1294 return fn.apply(null, [this].concat([].slice.call(args))); 1295 }, 1296 analogous: function () { 1297 return this._applyCombination(analogous, arguments); 1298 }, 1299 complement: function () { 1300 return this._applyCombination(complement, arguments); 1301 }, 1302 monochromatic: function () { 1303 return this._applyCombination(monochromatic, arguments); 1304 }, 1305 splitcomplement: function () { 1306 return this._applyCombination(splitcomplement, arguments); 1307 }, 1308 triad: function () { 1309 return this._applyCombination(triad, arguments); 1310 }, 1311 tetrad: function () { 1312 return this._applyCombination(tetrad, arguments); 1313 }, 1314 }; 1315 1316 // If input is an object, force 1 into "1.0" to handle ratios properly 1317 // String input requires "1.0" as input, so 1 will be treated as 1 1318 tinycolor.fromRatio = function (color, opts) { 1319 if (typeof color == "object") { 1320 var newColor = {}; 1321 for (var i in color) { 1322 if (color.hasOwnProperty(i)) { 1323 if (i === "a") { 1324 newColor[i] = color[i]; 1325 } else { 1326 newColor[i] = convertToPercentage(color[i]); 1327 } 1328 } 1329 } 1330 color = newColor; 1331 } 1332 1333 return tinycolor(color, opts); 1334 }; 1335 1336 // Given a string or object, convert that input to RGB
vendor: 8,705 bytes, lines 1337-1617
1337 // Possible string inputs: 1338 // 1339 // "red" 1340 // "#f00" or "f00" 1341 // "#ff0000" or "ff0000" 1342 // "#ff000000" or "ff000000" 1343 // "rgb 255 0 0" or "rgb (255, 0, 0)" 1344 // "rgb 1.0 0 0" or "rgb (1, 0, 0)" 1345 // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" 1346 // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" 1347 // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" 1348 // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" 1349 // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" 1350 // 1351 function inputToRGB(color) { 1352 var rgb = { r: 0, g: 0, b: 0 }; 1353 var a = 1; 1354 var s = null; 1355 var v = null; 1356 var l = null; 1357 var ok = false; 1358 var format = false; 1359 1360 if (typeof color == "string") { 1361 color = stringInputToObject(color); 1362 } 1363 1364 if (typeof color == "object") { 1365 if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) { 1366 rgb = rgbToRgb(color.r, color.g, color.b); 1367 ok = true; 1368 format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; 1369 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) { 1370 s = convertToPercentage(color.s); 1371 v = convertToPercentage(color.v); 1372 rgb = hsvToRgb(color.h, s, v); 1373 ok = true; 1374 format = "hsv"; 1375 } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) { 1376 s = convertToPercentage(color.s); 1377 l = convertToPercentage(color.l); 1378 rgb = hslToRgb(color.h, s, l); 1379 ok = true; 1380 format = "hsl"; 1381 } 1382 1383 if (color.hasOwnProperty("a")) { 1384 a = color.a; 1385 } 1386 } 1387 1388 a = boundAlpha(a); 1389 1390 return { 1391 ok: ok, 1392 format: color.format || format, 1393 r: mathMin(255, mathMax(rgb.r, 0)), 1394 g: mathMin(255, mathMax(rgb.g, 0)), 1395 b: mathMin(255, mathMax(rgb.b, 0)), 1396 a: a, 1397 }; 1398 } 1399 1400 // Conversion Functions 1401 // -------------------- 1402 1403 // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: 1404 // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript> 1405 1406 // `rgbToRgb` 1407 // Handle bounds / percentage checking to conform to CSS color spec 1408 // <http://www.w3.org/TR/css3-color/> 1409 // *Assumes:* r, g, b in [0, 255] or [0, 1] 1410 // *Returns:* { r, g, b } in [0, 255] 1411 function rgbToRgb(r, g, b) { 1412 return { 1413 r: bound01(r, 255) * 255, 1414 g: bound01(g, 255) * 255, 1415 b: bound01(b, 255) * 255, 1416 }; 1417 } 1418 1419 // `rgbToHsl` 1420 // Converts an RGB color value to HSL. 1421 // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] 1422 // *Returns:* { h, s, l } in [0,1] 1423 function rgbToHsl(r, g, b) { 1424 r = bound01(r, 255); 1425 g = bound01(g, 255); 1426 b = bound01(b, 255); 1427 1428 var max = mathMax(r, g, b), 1429 min = mathMin(r, g, b); 1430 var h, 1431 s, 1432 l = (max + min) / 2; 1433 1434 if (max == min) { 1435 h = s = 0; // achromatic 1436 } else { 1437 var d = max - min; 1438 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 1439 switch (max) { 1440 case r: 1441 h = (g - b) / d + (g < b ? 6 : 0); 1442 break; 1443 case g: 1444 h = (b - r) / d + 2; 1445 break; 1446 case b: 1447 h = (r - g) / d + 4; 1448 break; 1449 } 1450 1451 h /= 6; 1452 } 1453 1454 return { h: h, s: s, l: l }; 1455 } 1456 1457 // `hslToRgb` 1458 // Converts an HSL color value to RGB. 1459 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] 1460 // *Returns:* { r, g, b } in the set [0, 255] 1461 function hslToRgb(h, s, l) { 1462 var r, g, b; 1463 1464 h = bound01(h, 360); 1465 s = bound01(s, 100); 1466 l = bound01(l, 100); 1467 1468 function hue2rgb(p, q, t) { 1469 if (t < 0) t += 1; 1470 if (t > 1) t -= 1; 1471 if (t < 1 / 6) return p + (q - p) * 6 * t; 1472 if (t < 1 / 2) return q; 1473 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; 1474 return p; 1475 } 1476 1477 if (s === 0) { 1478 r = g = b = l; // achromatic 1479 } else { 1480 var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 1481 var p = 2 * l - q; 1482 r = hue2rgb(p, q, h + 1 / 3); 1483 g = hue2rgb(p, q, h); 1484 b = hue2rgb(p, q, h - 1 / 3); 1485 } 1486 1487 return { r: r * 255, g: g * 255, b: b * 255 }; 1488 } 1489 1490 // `rgbToHsv` 1491 // Converts an RGB color value to HSV 1492 // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] 1493 // *Returns:* { h, s, v } in [0,1] 1494 function rgbToHsv(r, g, b) { 1495 r = bound01(r, 255); 1496 g = bound01(g, 255); 1497 b = bound01(b, 255); 1498 1499 var max = mathMax(r, g, b), 1500 min = mathMin(r, g, b); 1501 var h, 1502 s, 1503 v = max; 1504 1505 var d = max - min; 1506 s = max === 0 ? 0 : d / max; 1507 1508 if (max == min) { 1509 h = 0; // achromatic 1510 } else { 1511 switch (max) { 1512 case r: 1513 h = (g - b) / d + (g < b ? 6 : 0); 1514 break; 1515 case g: 1516 h = (b - r) / d + 2; 1517 break; 1518 case b: 1519 h = (r - g) / d + 4; 1520 break; 1521 } 1522 h /= 6; 1523 } 1524 return { h: h, s: s, v: v }; 1525 } 1526 1527 // `hsvToRgb` 1528 // Converts an HSV color value to RGB. 1529 // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] 1530 // *Returns:* { r, g, b } in the set [0, 255] 1531 function hsvToRgb(h, s, v) { 1532 h = bound01(h, 360) * 6; 1533 s = bound01(s, 100); 1534 v = bound01(v, 100); 1535 1536 var i = Math.floor(h), 1537 f = h - i, 1538 p = v * (1 - s), 1539 q = v * (1 - f * s), 1540 t = v * (1 - (1 - f) * s), 1541 mod = i % 6, 1542 r = [v, q, p, p, t, v][mod], 1543 g = [t, v, v, q, p, p][mod], 1544 b = [p, p, t, v, v, q][mod]; 1545 1546 return { r: r * 255, g: g * 255, b: b * 255 }; 1547 } 1548 1549 // `rgbToHex` 1550 // Converts an RGB color to hex 1551 // Assumes r, g, and b are contained in the set [0, 255] 1552 // Returns a 3 or 6 character hex 1553 function rgbToHex(r, g, b, allow3Char) { 1554 var hex = [ 1555 pad2(mathRound(r).toString(16)), 1556 pad2(mathRound(g).toString(16)), 1557 pad2(mathRound(b).toString(16)), 1558 ]; 1559 1560 // Return a 3 character hex if possible 1561 if ( 1562 allow3Char && 1563 hex[0].charAt(0) == hex[0].charAt(1) && 1564 hex[1].charAt(0) == hex[1].charAt(1) && 1565 hex[2].charAt(0) == hex[2].charAt(1) 1566 ) { 1567 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); 1568 } 1569 1570 return hex.join(""); 1571 } 1572 1573 // `rgbaToHex` 1574 // Converts an RGBA color plus alpha transparency to hex 1575 // Assumes r, g, b are contained in the set [0, 255] and 1576 // a in [0, 1]. Returns a 4 or 8 character rgba hex 1577 function rgbaToHex(r, g, b, a, allow4Char) { 1578 var hex = [ 1579 pad2(mathRound(r).toString(16)), 1580 pad2(mathRound(g).toString(16)), 1581 pad2(mathRound(b).toString(16)), 1582 pad2(convertDecimalToHex(a)), 1583 ]; 1584 1585 // Return a 4 character hex if possible 1586 if ( 1587 allow4Char && 1588 hex[0].charAt(0) == hex[0].charAt(1) && 1589 hex[1].charAt(0) == hex[1].charAt(1) && 1590 hex[2].charAt(0) == hex[2].charAt(1) && 1591 hex[3].charAt(0) == hex[3].charAt(1) 1592 ) { 1593 return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0); 1594 } 1595 1596 return hex.join(""); 1597 } 1598 1599 // `rgbaToArgbHex` 1600 // Converts an RGBA color to an ARGB Hex8 string 1601 // Rarely used, but required for "toFilter()" 1602 function rgbaToArgbHex(r, g, b, a) { 1603 var hex = [ 1604 pad2(convertDecimalToHex(a)), 1605 pad2(mathRound(r).toString(16)), 1606 pad2(mathRound(g).toString(16)), 1607 pad2(mathRound(b).toString(16)), 1608 ]; 1609 1610 return hex.join(""); 1611 } 1612 1613 // `equals` 1614 // Can be called with any tinycolor input 1615 tinycolor.equals = function (color1, color2) { 1616 if (!color1 || !color2) { 1617 return false;
vendor: 4,315 bytes, lines 1618-1755
1618 } 1619 return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); 1620 }; 1621 1622 tinycolor.random = function () { 1623 return tinycolor.fromRatio({ 1624 r: mathRandom(), 1625 g: mathRandom(), 1626 b: mathRandom(), 1627 }); 1628 }; 1629 1630 // Modification Functions 1631 // ---------------------- 1632 // Thanks to less.js for some of the basics here 1633 // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js> 1634 1635 function desaturate(color, amount) { 1636 amount = amount === 0 ? 0 : amount || 10; 1637 var hsl = tinycolor(color).toHsl(); 1638 hsl.s -= amount / 100; 1639 hsl.s = clamp01(hsl.s); 1640 return tinycolor(hsl); 1641 } 1642 1643 function saturate(color, amount) { 1644 amount = amount === 0 ? 0 : amount || 10; 1645 var hsl = tinycolor(color).toHsl(); 1646 hsl.s += amount / 100; 1647 hsl.s = clamp01(hsl.s); 1648 return tinycolor(hsl); 1649 } 1650 1651 function greyscale(color) { 1652 return tinycolor(color).desaturate(100); 1653 } 1654 1655 function lighten(color, amount) { 1656 amount = amount === 0 ? 0 : amount || 10; 1657 var hsl = tinycolor(color).toHsl(); 1658 hsl.l += amount / 100; 1659 hsl.l = clamp01(hsl.l); 1660 return tinycolor(hsl); 1661 } 1662 1663 function brighten(color, amount) { 1664 amount = amount === 0 ? 0 : amount || 10; 1665 var rgb = tinycolor(color).toRgb(); 1666 rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * -(amount / 100)))); 1667 rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * -(amount / 100)))); 1668 rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * -(amount / 100)))); 1669 return tinycolor(rgb); 1670 } 1671 1672 function darken(color, amount) { 1673 amount = amount === 0 ? 0 : amount || 10; 1674 var hsl = tinycolor(color).toHsl(); 1675 hsl.l -= amount / 100; 1676 hsl.l = clamp01(hsl.l); 1677 return tinycolor(hsl); 1678 } 1679 1680 // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. 1681 // Values outside of this range will be wrapped into this range. 1682 function spin(color, amount) { 1683 var hsl = tinycolor(color).toHsl(); 1684 var hue = (hsl.h + amount) % 360; 1685 hsl.h = hue < 0 ? 360 + hue : hue; 1686 return tinycolor(hsl); 1687 } 1688 1689 // Combination Functions 1690 // --------------------- 1691 // Thanks to jQuery xColor for some of the ideas behind these 1692 // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js> 1693 1694 function complement(color) { 1695 var hsl = tinycolor(color).toHsl(); 1696 hsl.h = (hsl.h + 180) % 360; 1697 return tinycolor(hsl); 1698 } 1699 1700 function triad(color) { 1701 var hsl = tinycolor(color).toHsl(); 1702 var h = hsl.h; 1703 return [ 1704 tinycolor(color), 1705 tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), 1706 tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }), 1707 ]; 1708 } 1709 1710 function tetrad(color) { 1711 var hsl = tinycolor(color).toHsl(); 1712 var h = hsl.h; 1713 return [ 1714 tinycolor(color), 1715 tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), 1716 tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), 1717 tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }), 1718 ]; 1719 } 1720 1721 function splitcomplement(color) { 1722 var hsl = tinycolor(color).toHsl(); 1723 var h = hsl.h; 1724 return [ 1725 tinycolor(color), 1726 tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }), 1727 tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l }), 1728 ]; 1729 } 1730 1731 function analogous(color, results, slices) { 1732 results = results || 6; 1733 slices = slices || 30; 1734 1735 var hsl = tinycolor(color).toHsl(); 1736 var part = 360 / slices; 1737 var ret = [tinycolor(color)]; 1738 1739 for (hsl.h = (hsl.h - ((part * results) >> 1) + 720) % 360; --results; ) { 1740 hsl.h = (hsl.h + part) % 360; 1741 ret.push(tinycolor(hsl)); 1742 } 1743 return ret; 1744 } 1745 1746 function monochromatic(color, results) { 1747 results = results || 6; 1748 var hsv = tinycolor(color).toHsv(); 1749 var h = hsv.h, 1750 s = hsv.s, 1751 v = hsv.v; 1752 var ret = []; 1753 var modification = 1 / results; 1754 1755 while (results--) {
vendor: 4,157 bytes, lines 1756-1864
1756 ret.push(tinycolor({ h: h, s: s, v: v })); 1757 v = (v + modification) % 1; 1758 } 1759 1760 return ret; 1761 } 1762 1763 // Utility Functions 1764 // --------------------- 1765 1766 tinycolor.mix = function (color1, color2, amount) { 1767 amount = amount === 0 ? 0 : amount || 50; 1768 1769 var rgb1 = tinycolor(color1).toRgb(); 1770 var rgb2 = tinycolor(color2).toRgb(); 1771 1772 var p = amount / 100; 1773 1774 var rgba = { 1775 r: (rgb2.r - rgb1.r) * p + rgb1.r, 1776 g: (rgb2.g - rgb1.g) * p + rgb1.g, 1777 b: (rgb2.b - rgb1.b) * p + rgb1.b, 1778 a: (rgb2.a - rgb1.a) * p + rgb1.a, 1779 }; 1780 1781 return tinycolor(rgba); 1782 }; 1783 1784 // Readability Functions 1785 // --------------------- 1786 // <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2) 1787 1788 // `contrast` 1789 // Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) 1790 tinycolor.readability = function (color1, color2) { 1791 var c1 = tinycolor(color1); 1792 var c2 = tinycolor(color2); 1793 return ( 1794 (Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / 1795 (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05) 1796 ); 1797 }; 1798 1799 // `isReadable` 1800 // Ensure that foreground and background color combinations meet WCAG2 guidelines. 1801 // The third argument is an optional Object. 1802 // the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA'; 1803 // the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'. 1804 // If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}. 1805 1806 // *Example* 1807 // tinycolor.isReadable("#000", "#111") => false 1808 // tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false 1809 tinycolor.isReadable = function (color1, color2, wcag2) { 1810 var readability = tinycolor.readability(color1, color2); 1811 var wcag2Parms, out; 1812 1813 out = false; 1814 1815 wcag2Parms = validateWCAG2Parms(wcag2); 1816 switch (wcag2Parms.level + wcag2Parms.size) { 1817 case "AAsmall": 1818 case "AAAlarge": 1819 out = readability >= 4.5; 1820 break; 1821 case "AAlarge": 1822 out = readability >= 3; 1823 break; 1824 case "AAAsmall": 1825 out = readability >= 7; 1826 break; 1827 } 1828 return out; 1829 }; 1830 1831 // `mostReadable` 1832 // Given a base color and a list of possible foreground or background 1833 // colors for that base, returns the most readable color. 1834 // Optionally returns Black or White if the most readable color is unreadable. 1835 // *Example* 1836 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" 1837 // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" 1838 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" 1839 // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" 1840 tinycolor.mostReadable = function (baseColor, colorList, args) { 1841 var bestColor = null; 1842 var bestScore = 0; 1843 var readability; 1844 var includeFallbackColors, level, size; 1845 args = args || {}; 1846 includeFallbackColors = args.includeFallbackColors; 1847 level = args.level; 1848 size = args.size; 1849 1850 for (var i = 0; i < colorList.length; i++) { 1851 readability = tinycolor.readability(baseColor, colorList[i]); 1852 if (readability > bestScore) { 1853 bestScore = readability; 1854 bestColor = tinycolor(colorList[i]); 1855 } 1856 } 1857 1858 if ( 1859 tinycolor.isReadable(baseColor, bestColor, { level: level, size: size }) || 1860 !includeFallbackColors 1861 ) { 1862 return bestColor; 1863 } else { 1864 args.includeFallbackColors = false;
vendor: 12,185 bytes, lines 1865-2238
1865 return tinycolor.mostReadable(baseColor, ["#fff", "#000"], args); 1866 } 1867 }; 1868 1869 // Big List of Colors 1870 // ------------------ 1871 // <http://www.w3.org/TR/css3-color/#svg-color> 1872 var names = (tinycolor.names = { 1873 aliceblue: "f0f8ff", 1874 antiquewhite: "faebd7", 1875 aqua: "0ff", 1876 aquamarine: "7fffd4", 1877 azure: "f0ffff", 1878 beige: "f5f5dc", 1879 bisque: "ffe4c4", 1880 black: "000", 1881 blanchedalmond: "ffebcd", 1882 blue: "00f", 1883 blueviolet: "8a2be2", 1884 brown: "a52a2a", 1885 burlywood: "deb887", 1886 burntsienna: "ea7e5d", 1887 cadetblue: "5f9ea0", 1888 chartreuse: "7fff00", 1889 chocolate: "d2691e", 1890 coral: "ff7f50", 1891 cornflowerblue: "6495ed", 1892 cornsilk: "fff8dc", 1893 crimson: "dc143c", 1894 cyan: "0ff", 1895 darkblue: "00008b", 1896 darkcyan: "008b8b", 1897 darkgoldenrod: "b8860b", 1898 darkgray: "a9a9a9", 1899 darkgreen: "006400", 1900 darkgrey: "a9a9a9", 1901 darkkhaki: "bdb76b", 1902 darkmagenta: "8b008b", 1903 darkolivegreen: "556b2f", 1904 darkorange: "ff8c00", 1905 darkorchid: "9932cc", 1906 darkred: "8b0000", 1907 darksalmon: "e9967a", 1908 darkseagreen: "8fbc8f", 1909 darkslateblue: "483d8b", 1910 darkslategray: "2f4f4f", 1911 darkslategrey: "2f4f4f", 1912 darkturquoise: "00ced1", 1913 darkviolet: "9400d3", 1914 deeppink: "ff1493", 1915 deepskyblue: "00bfff", 1916 dimgray: "696969", 1917 dimgrey: "696969", 1918 dodgerblue: "1e90ff", 1919 firebrick: "b22222", 1920 floralwhite: "fffaf0", 1921 forestgreen: "228b22", 1922 fuchsia: "f0f", 1923 gainsboro: "dcdcdc", 1924 ghostwhite: "f8f8ff", 1925 gold: "ffd700", 1926 goldenrod: "daa520", 1927 gray: "808080", 1928 green: "008000", 1929 greenyellow: "adff2f", 1930 grey: "808080", 1931 honeydew: "f0fff0", 1932 hotpink: "ff69b4", 1933 indianred: "cd5c5c", 1934 indigo: "4b0082", 1935 ivory: "fffff0", 1936 khaki: "f0e68c", 1937 lavender: "e6e6fa", 1938 lavenderblush: "fff0f5", 1939 lawngreen: "7cfc00", 1940 lemonchiffon: "fffacd", 1941 lightblue: "add8e6", 1942 lightcoral: "f08080", 1943 lightcyan: "e0ffff", 1944 lightgoldenrodyellow: "fafad2", 1945 lightgray: "d3d3d3", 1946 lightgreen: "90ee90", 1947 lightgrey: "d3d3d3", 1948 lightpink: "ffb6c1", 1949 lightsalmon: "ffa07a", 1950 lightseagreen: "20b2aa", 1951 lightskyblue: "87cefa", 1952 lightslategray: "789", 1953 lightslategrey: "789", 1954 lightsteelblue: "b0c4de", 1955 lightyellow: "ffffe0", 1956 lime: "0f0", 1957 limegreen: "32cd32", 1958 linen: "faf0e6", 1959 magenta: "f0f", 1960 maroon: "800000", 1961 mediumaquamarine: "66cdaa", 1962 mediumblue: "0000cd", 1963 mediumorchid: "ba55d3", 1964 mediumpurple: "9370db", 1965 mediumseagreen: "3cb371", 1966 mediumslateblue: "7b68ee", 1967 mediumspringgreen: "00fa9a", 1968 mediumturquoise: "48d1cc", 1969 mediumvioletred: "c71585", 1970 midnightblue: "191970", 1971 mintcream: "f5fffa", 1972 mistyrose: "ffe4e1", 1973 moccasin: "ffe4b5", 1974 navajowhite: "ffdead", 1975 navy: "000080", 1976 oldlace: "fdf5e6", 1977 olive: "808000", 1978 olivedrab: "6b8e23", 1979 orange: "ffa500", 1980 orangered: "ff4500", 1981 orchid: "da70d6", 1982 palegoldenrod: "eee8aa", 1983 palegreen: "98fb98", 1984 paleturquoise: "afeeee", 1985 palevioletred: "db7093", 1986 papayawhip: "ffefd5", 1987 peachpuff: "ffdab9", 1988 peru: "cd853f", 1989 pink: "ffc0cb", 1990 plum: "dda0dd", 1991 powderblue: "b0e0e6", 1992 purple: "800080", 1993 rebeccapurple: "663399", 1994 red: "f00", 1995 rosybrown: "bc8f8f", 1996 royalblue: "4169e1", 1997 saddlebrown: "8b4513", 1998 salmon: "fa8072", 1999 sandybrown: "f4a460", 2000 seagreen: "2e8b57", 2001 seashell: "fff5ee", 2002 sienna: "a0522d", 2003 silver: "c0c0c0", 2004 skyblue: "87ceeb", 2005 slateblue: "6a5acd", 2006 slategray: "708090", 2007 slategrey: "708090", 2008 snow: "fffafa", 2009 springgreen: "00ff7f", 2010 steelblue: "4682b4", 2011 tan: "d2b48c", 2012 teal: "008080", 2013 thistle: "d8bfd8", 2014 tomato: "ff6347", 2015 turquoise: "40e0d0", 2016 violet: "ee82ee", 2017 wheat: "f5deb3", 2018 white: "fff", 2019 whitesmoke: "f5f5f5", 2020 yellow: "ff0", 2021 yellowgreen: "9acd32", 2022 }); 2023 2024 // Make it easy to access colors via `hexNames[hex]` 2025 var hexNames = (tinycolor.hexNames = flip(names)); 2026 2027 // Utilities 2028 // --------- 2029 2030 // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` 2031 function flip(o) { 2032 var flipped = {}; 2033 for (var i in o) { 2034 if (o.hasOwnProperty(i)) { 2035 flipped[o[i]] = i; 2036 } 2037 } 2038 return flipped; 2039 } 2040 2041 // Return a valid alpha value [0,1] with all invalid values being set to 1 2042 function boundAlpha(a) { 2043 a = parseFloat(a); 2044 2045 if (isNaN(a) || a < 0 || a > 1) { 2046 a = 1; 2047 } 2048 2049 return a; 2050 } 2051 2052 // Take input from [0, n] and return it as [0, 1] 2053 function bound01(n, max) { 2054 if (isOnePointZero(n)) { 2055 n = "100%"; 2056 } 2057 2058 var processPercent = isPercentage(n); 2059 n = mathMin(max, mathMax(0, parseFloat(n))); 2060 2061 // Automatically convert percentage into number 2062 if (processPercent) { 2063 n = parseInt(n * max, 10) / 100; 2064 } 2065 2066 // Handle floating point rounding errors 2067 if (Math.abs(n - max) < 0.000001) { 2068 return 1; 2069 } 2070 2071 // Convert into [0, 1] range if it isn't already 2072 return (n % max) / parseFloat(max); 2073 } 2074 2075 // Force a number between 0 and 1 2076 function clamp01(val) { 2077 return mathMin(1, mathMax(0, val)); 2078 } 2079 2080 // Parse a base-16 hex value into a base-10 integer 2081 function parseIntFromHex(val) { 2082 return parseInt(val, 16); 2083 } 2084 2085 // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 2086 // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0> 2087 function isOnePointZero(n) { 2088 return typeof n == "string" && n.indexOf(".") != -1 && parseFloat(n) === 1; 2089 } 2090 2091 // Check to see if string passed in is a percentage 2092 function isPercentage(n) { 2093 return typeof n === "string" && n.indexOf("%") != -1; 2094 } 2095 2096 // Force a hex value to have 2 characters 2097 function pad2(c) { 2098 return c.length == 1 ? "0" + c : "" + c; 2099 } 2100 2101 // Replace a decimal with it's percentage value 2102 function convertToPercentage(n) { 2103 if (n <= 1) { 2104 n = n * 100 + "%"; 2105 } 2106 2107 return n; 2108 } 2109 2110 // Converts a decimal to a hex value 2111 function convertDecimalToHex(d) { 2112 return Math.round(parseFloat(d) * 255).toString(16); 2113 } 2114 // Converts a hex value to a decimal 2115 function convertHexToDecimal(h) { 2116 return parseIntFromHex(h) / 255; 2117 } 2118 2119 var matchers = (function () { 2120 // <http://www.w3.org/TR/css3-values/#integers> 2121 var CSS_INTEGER = "[-\\+]?\\d+%?"; 2122 2123 // <http://www.w3.org/TR/css3-values/#number-value> 2124 var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; 2125 2126 // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. 2127 var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; 2128 2129 // Actual matching. 2130 // Parentheses and commas are optional, but not required. 2131 // Whitespace can take the place of commas or opening paren 2132 var PERMISSIVE_MATCH3 = 2133 "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; 2134 var PERMISSIVE_MATCH4 = 2135 "[\\s|\\(]+(" + 2136 CSS_UNIT + 2137 ")[,|\\s]+(" + 2138 CSS_UNIT + 2139 ")[,|\\s]+(" + 2140 CSS_UNIT + 2141 ")[,|\\s]+(" + 2142 CSS_UNIT + 2143 ")\\s*\\)?"; 2144 2145 return { 2146 CSS_UNIT: new RegExp(CSS_UNIT), 2147 rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), 2148 rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), 2149 hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), 2150 hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), 2151 hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), 2152 hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), 2153 hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2154 hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2155 hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, 2156 hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, 2157 }; 2158 })(); 2159 2160 // `isValidCSSUnit` 2161 // Take in a single string / number and check to see if it looks like a CSS unit 2162 // (see `matchers` above for definition). 2163 function isValidCSSUnit(color) { 2164 return !!matchers.CSS_UNIT.exec(color); 2165 } 2166 2167 // `stringInputToObject` 2168 // Permissive string parsing. Take in a number of formats, and output an object 2169 // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` 2170 function stringInputToObject(color) { 2171 color = color.replace(trimLeft, "").replace(trimRight, "").toLowerCase(); 2172 var named = false; 2173 if (names[color]) { 2174 color = names[color]; 2175 named = true; 2176 } else if (color == "transparent") { 2177 return { r: 0, g: 0, b: 0, a: 0, format: "name" }; 2178 } 2179 2180 // Try to match string input using regular expressions. 2181 // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] 2182 // Just return an object and let the conversion functions handle that. 2183 // This way the result will be the same whether the tinycolor is initialized with string or object. 2184 var match; 2185 if ((match = matchers.rgb.exec(color))) { 2186 return { r: match[1], g: match[2], b: match[3] }; 2187 } 2188 if ((match = matchers.rgba.exec(color))) { 2189 return { r: match[1], g: match[2], b: match[3], a: match[4] }; 2190 } 2191 if ((match = matchers.hsl.exec(color))) { 2192 return { h: match[1], s: match[2], l: match[3] }; 2193 } 2194 if ((match = matchers.hsla.exec(color))) { 2195 return { h: match[1], s: match[2], l: match[3], a: match[4] }; 2196 } 2197 if ((match = matchers.hsv.exec(color))) { 2198 return { h: match[1], s: match[2], v: match[3] }; 2199 } 2200 if ((match = matchers.hsva.exec(color))) { 2201 return { h: match[1], s: match[2], v: match[3], a: match[4] }; 2202 } 2203 if ((match = matchers.hex8.exec(color))) { 2204 return { 2205 r: parseIntFromHex(match[1]), 2206 g: parseIntFromHex(match[2]), 2207 b: parseIntFromHex(match[3]), 2208 a: convertHexToDecimal(match[4]), 2209 format: named ? "name" : "hex8", 2210 }; 2211 } 2212 if ((match = matchers.hex6.exec(color))) { 2213 return { 2214 r: parseIntFromHex(match[1]), 2215 g: parseIntFromHex(match[2]), 2216 b: parseIntFromHex(match[3]), 2217 format: named ? "name" : "hex", 2218 }; 2219 } 2220 if ((match = matchers.hex4.exec(color))) { 2221 return { 2222 r: parseIntFromHex(match[1] + "" + match[1]), 2223 g: parseIntFromHex(match[2] + "" + match[2]), 2224 b: parseIntFromHex(match[3] + "" + match[3]), 2225 a: convertHexToDecimal(match[4] + "" + match[4]), 2226 format: named ? "name" : "hex8", 2227 }; 2228 } 2229 if ((match = matchers.hex3.exec(color))) { 2230 return { 2231 r: parseIntFromHex(match[1] + "" + match[1]), 2232 g: parseIntFromHex(match[2] + "" + match[2]), 2233 b: parseIntFromHex(match[3] + "" + match[3]), 2234 format: named ? "name" : "hex", 2235 }; 2236 } 2237 2238 return false;
2239 } 2240 2241 function validateWCAG2Parms(parms) { 2242 // return valid WCAG2 parms for isReadable. 2243 // If input parms are invalid, return {"level":"AA", "size":"small"} 2244 var level, size; 2245 parms = parms || { level: "AA", size: "small" }; 2246 level = (parms.level || "AA").toUpperCase(); 2247 size = (parms.size || "small").toLowerCase(); 2248 if (level !== "AA" && level !== "AAA") { 2249 level = "AA"; 2250 } 2251 if (size !== "small" && size !== "large") { 2252 size = "small"; 2253 } 2254 return { level: level, size: size }; 2255 } 2256 2257 const $$1 = jQuery; 2258 class Server { 2259 constructor() { 2260 this.apiUrl = MapSVG.urls.api; 2261 } 2262 getUrl(path) { 2263 return this.apiUrl + path; 2264 } 2265 get(path, data) { 2266 return $$1.ajax({ 2267 url: this.apiUrl + path, 2268 type: "GET", 2269 data: data, 2270 beforeSend: function (xhr) { 2271 if (MapSVG.nonce()) { 2272 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2273 } 2274 }, 2275 }); 2276 } 2277 post(path, data) { 2278 const ajaxParams = { 2279 url: this.apiUrl + path, 2280 type: "POST", 2281 data: data, 2282 beforeSend: function (xhr) { 2283 if (MapSVG.nonce()) { 2284 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2285 } 2286 }, 2287 }; 2288 if (data instanceof FormData) { 2289 ajaxParams["processData"] = false; 2290 ajaxParams["contentType"] = false; 2291 } 2292 return $$1.ajax(ajaxParams); 2293 } 2294 put(path, data) { 2295 const ajaxParams = { 2296 url: this.apiUrl + path, 2297 type: "POST", 2298 data: data, 2299 beforeSend: function (xhr) { 2300 if (MapSVG.nonce()) { 2301 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2302 } 2303 xhr.setRequestHeader("X-HTTP-Method-Override", "PUT"); 2304 }, 2305 }; 2306 if (data instanceof FormData) { 2307 ajaxParams["processData"] = false; 2308 ajaxParams["contentType"] = false; 2309 } 2310 return $$1.ajax(ajaxParams); 2311 } 2312 delete(path, data) { 2313 return $$1.ajax({ 2314 url: this.apiUrl + path, 2315 type: "POST", 2316 data: data, 2317 beforeSend: function (xhr) { 2318 if (MapSVG.nonce()) { 2319 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2320 } 2321 xhr.setRequestHeader("X-HTTP-Method-Override", "DELETE"); 2322 }, 2323 }); 2324 } 2325 ajax(path, data) { 2326 data.url = this.getUrl(path); 2327 data.beforeSend = function (xhr) { 2328 if (MapSVG.nonce()) { 2329 xhr.setRequestHeader("X-WP-Nonce", MapSVG.nonce()); 2330 } 2331 }; 2332 return $$1.ajax(data); 2333 } 2334 } 2335 2336 class Events { 2337 constructor(context) { 2338 this.events = {}; 2339 this.context = context; 2340 } 2341 on(event, callbackOrObjectType, callback) { 2342 if (!this.events[event]) 2343 this.events[event] = []; 2344 let callbackFunction; 2345 if (typeof callbackOrObjectType === "string") { 2346 callbackFunction = callback; 2347 } 2348 else { 2349 callbackFunction = callbackOrObjectType; 2350 } 2351 this.events[event].push(callbackFunction); 2352 return this; 2353 } 2354 off(event, callback) { 2355 const _this = this; 2356 if (this.events[event] && this.events[event].length) { 2357 this.events[event].forEach(function (_callback, index) { 2358 if (typeof callback === "undefined") { 2359 _this.events[event].splice(index, 1); 2360 } 2361 else if (_callback === callback) { 2362 _this.events[event].splice(index, 1); 2363 } 2364 }); 2365 } 2366 return this; 2367 } 2368 trigger(event, thisArg, args) { 2369 if (this.events[event] && this.events[event].length) 2370 this.events[event].forEach((callback) => { 2371 try { 2372 callback && callback.apply(thisArg || this.context, args || [this.context]); 2373 } 2374 catch (err) { 2375 console.error(err); 2376 } 2377 }); 2378 return this; 2379 } 2380 } 2381 2382 class ArrayIndexed extends Array { 2383 constructor(indexKey, items, options) { 2384 if (items) { 2385 super(...items); 2386 } 2387 else { 2388 super(); 2389 } 2390 this.key = indexKey; 2391 this.dict = {}; 2392 this.nextId = 1; 2393 if (options) { 2394 this.options = options; 2395 } 2396 else { 2397 this.options = { autoId: false, unique: false }; 2398 } 2399 if (this.length > 0) { 2400 let i = 0; 2401 const _this = this; 2402 if (this.options.autoId) { 2403 let maxId = 0; 2404 let missingIds = false;
2405 this.forEach(function (item) { 2406 if (item[_this.key] != null) { 2407 if (item[_this.key] > maxId) { 2408 maxId = item[_this.key]; 2409 } 2410 } 2411 else { 2412 missingIds = true; 2413 } 2414 }); 2415 this.nextId = ++maxId; 2416 if (missingIds) { 2417 this.forEach(function (item) { 2418 if (item[_this.key] == null) { 2419 item[_this.key] = _this.nextId; 2420 _this.nextId++; 2421 } 2422 }); 2423 } 2424 } 2425 this.forEach(function (item) { 2426 _this.dict[item[_this.key]] = i; 2427 i++; 2428 }); 2429 } 2430 } 2431 push(item) { 2432 const length = super.push(item); 2433 if (this.options.autoId === true) { 2434 item[this.key] = this.nextId; 2435 this.nextId++; 2436 } 2437 this.dict[item[this.key]] = length - 1; 2438 return length; 2439 } 2440 pop() { 2441 const item = this[this.length - 1]; 2442 const id = item[this.key]; 2443 const length = super.pop(); 2444 delete this.dict[id]; 2445 this.reindex(); 2446 return super.pop(); 2447 } 2448 update(data) { 2449 if (data[this.key] != null) { 2450 const obj = this.get(data[this.key]); 2451 for (const i in data) { 2452 obj[i] = data[i]; 2453 } 2454 return obj; 2455 } 2456 return false; 2457 } 2458 get(id) { 2459 return this.findById(id); 2460 } 2461 findById(id) { 2462 return this[this.dict[id]]; 2463 } 2464 deleteById(id) { 2465 const index = this.dict[id]; 2466 if (typeof index !== "undefined") { 2467 delete this.dict[id]; 2468 this.splice(index, 1); 2469 } 2470 } 2471 delete(id) { 2472 this.deleteById(id); 2473 } 2474 clear() { 2475 this.length = 0; 2476 this.reindex(); 2477 } 2478 reindex() { 2479 const _this = this; 2480 this.dict = {}; 2481 this.forEach(function (item, index) { 2482 _this.dict[item[_this.key]] = index; 2483 }); 2484 } 2485 sort(compareFn) { 2486 super.sort(compareFn); 2487 this.reindex(); 2488 return this; 2489 } 2490 splice(start, deleteCount) { 2491 const res = super.splice(start, deleteCount); 2492 this.reindex(); 2493 return res; 2494 } 2495 } 2496 2497 class SchemaField { 2498 constructor(field) { 2499 const booleans = ["visible", "searchable", "readonly", "protected"]; 2500 for (const key in field) { 2501 this[key] = field[key]; 2502 } 2503 booleans.forEach((paramName) => { 2504 if (typeof this[paramName] !== "undefined") { 2505 this[paramName] = MapSVG.parseBoolean(this[paramName]); 2506 } 2507 else { 2508 this[paramName] = false; 2509 } 2510 }); 2511 if (typeof this.options !== "undefined") { 2512 if (!(this.options instanceof ArrayIndexed)) { 2513 this.options = new ArrayIndexed("value", this.options); 2514 } 2515 } 2516 } 2517 } 2518 2519 class Schema { 2520 constructor(options) { 2521 this.fields = new ArrayIndexed("name"); 2522 this.build(options); 2523 this.lastChangeTime = Date.now(); 2524 this.events = new Events(this); 2525 } 2526 build(options) { 2527 const allowedParams = ["id", "title", "type", "name", "fields"]; 2528 allowedParams.forEach((paramName) => { 2529 const setter = "set" + MapSVG.ucfirst(paramName); 2530 if (typeof options[paramName] !== "undefined" && typeof this[setter] == "function") { 2531 this[setter](options[paramName]); 2532 } 2533 }); 2534 } 2535 update(options) { 2536 this.build(options); 2537 } 2538 setId(id) { 2539 this.id = id; 2540 } 2541 setTitle(title) { 2542 this.title = title; 2543 } 2544 setName(name) { 2545 this.name = name; 2546 } 2547 loaded() { 2548 return this.fields.length !== 0; 2549 } 2550 setFields(fields) { 2551 if (fields) { 2552 this.fields.clear(); 2553 fields.forEach((fieldParams) => { 2554 this.fields.push(new SchemaField(fieldParams)); 2555 }); 2556 } 2557 } 2558 getFields() { 2559 return this.fields; 2560 } 2561 getFieldsAsArray() { 2562 return this.fields; 2563 } 2564 getFieldNames() { 2565 return this.fields.map((f) => f.name); 2566 } 2567 getField(field) { 2568 return this.fields.findById(field); 2569 } 2570 getFieldByType(type) { 2571 let f = null; 2572 this.fields.forEach(function (field) { 2573 if (field.type === type) 2574 f = field; 2575 }); 2576 return f; 2577 } 2578 getColumns(filters) { 2579 filters = filters || {}; 2580 const columns = this.fields; 2581 const needfilters = Object.keys(filters).length !== 0; 2582 let results = []; 2583 if (needfilters) { 2584 let filterpass; 2585 columns.forEach(function (obj) { 2586 filterpass = true; 2587 for (const param in filters) { 2588 filterpass = obj[param] == filters[param]; 2589 } 2590 filterpass && results.push(obj); 2591 }); 2592 } 2593 else { 2594 results = columns; 2595 } 2596 return results; 2597 } 2598 getData() { 2599 const data = { 2600 id: this.id, 2601 title: this.title, 2602 name: this.name, 2603 fields: this.fields, 2604 type: this.type, 2605 }; 2606 return data; 2607 } 2608 } 2609 2610 class Query { 2611 constructor(options) { 2612 this.filters = {}; 2613 this.filterout = {}; 2614 this.page = 1; 2615 if (options) { 2616 for (const i in options) { 2617 if (typeof options[i] !== "undefined") { 2618 this[i] = options[i]; 2619 } 2620 } 2621 } 2622 } 2623 setFields(fields) { 2624 const _this = this; 2625 for (const key in fields) { 2626 if (key == "filters") { 2627 _this.setFilters(fields[key]); 2628 } 2629 else { 2630 _this[key] = fields[key]; 2631 } 2632 } 2633 } 2634 update(query) { 2635 for (const i in query) { 2636 if (typeof query[i] !== "undefined") { 2637 if (i === "filters") { 2638 this.setFilters(query[i]); 2639 } 2640 else { 2641 this[i] = query[i]; 2642 } 2643 } 2644 } 2645 } 2646 get() { 2647 return { 2648 search: this.search, 2649 searchField: this.searchField, 2650 searchFallback: this.searchFallback, 2651 filters: this.filters, 2652 filterout: this.filterout, 2653 page: this.page, 2654 sort: this.sort, 2655 perpage: this.perpage, 2656 lastpage: this.lastpage, 2657 }; 2658 } 2659 clearFilters() { 2660 this.resetFilters(); 2661 } 2662 setFilters(fields) { 2663 const _this = this; 2664 for (const key in fields) { 2665 if (fields[key] === null || fields[key] === "" || fields[key] === undefined) { 2666 if (_this.filters[key]) { 2667 delete _this.filters[key]; 2668 } 2669 } 2670 else { 2671 _this.filters[key] = fields[key]; 2672 } 2673 } 2674 } 2675 setSearch(search) { 2676 this.search = search; 2677 } 2678 setFilterOut(fields) { 2679 if (fields === null) { 2680 delete this.filterout; 2681 } 2682 else {
2683 this.filterout = fields; 2684 } 2685 } 2686 resetFilters(fields) { 2687 this.filters = {}; 2688 this.setSearch(""); 2689 } 2690 setFilterField(field, value) { 2691 this.filters[field] = value; 2692 } 2693 hasFilters() { 2694 return Object.keys(this.filters).length > 0 || this.search.length > 0; 2695 } 2696 removeFilter(fieldName) { 2697 this.filters[fieldName] = null; 2698 delete this.filters[fieldName]; 2699 } 2700 requestSchema(requestSchema) { 2701 this.withSchema = requestSchema ? requestSchema : true; 2702 } 2703 } 2704 2705 class LocationAddress { 2706 constructor(fields) { 2707 for (const i in fields) { 2708 this[i] = fields[i]; 2709 } 2710 } 2711 getData() { 2712 const copy = {}; 2713 [ 2714 "route", 2715 "address_formatted", 2716 "administrative_area_level_1", 2717 "administrative_area_level_1_short", 2718 "administrative_area_level_2", 2719 "administrative_area_level_2_short", 2720 "country", 2721 "country_short", 2722 "postal_code", 2723 ].forEach((field) => { 2724 if (this[field]) { 2725 copy[field] = this[field]; 2726 } 2727 }); 2728 return copy; 2729 } 2730 get state() { 2731 return this.country_short === "US" ? this.administrative_area_level_1 : null; 2732 } 2733 get state_short() { 2734 return this.country_short === "US" ? this.administrative_area_level_1_short : null; 2735 } 2736 get county() { 2737 return this.country_short === "US" ? this.administrative_area_level_2 : null; 2738 } 2739 get zip() { 2740 return this.postal_code; 2741 } 2742 } 2743 2744 class ScreenPoint { 2745 constructor(x, y) { 2746 this.x = x; 2747 this.y = y; 2748 } 2749 } 2750 class SVGPoint { 2751 constructor(x, y) { 2752 let _x, _y; 2753 if (typeof x === "object") { 2754 if (x.x && x.y) { 2755 _x = parseFloat(x.x + ""); 2756 _y = parseFloat(x.y + ""); 2757 } 2758 else { 2759 console.error("MapSVG: incorrect format of {x, y} object for SVGPoint."); 2760 _x = 0; 2761 _y = 0; 2762 } 2763 } 2764 else { 2765 _x = parseFloat(x + ""); 2766 _y = parseFloat(y + ""); 2767 } 2768 this.x = _x; 2769 this.y = _y; 2770 } 2771 toString() { 2772 return this.x + "," + this.y; 2773 } 2774 } 2775 class GeoPoint { 2776 constructor(lat, lng) { 2777 let _lat, _lng; 2778 if (typeof lat === "object") { 2779 if (lat.lat && lat.lng) { 2780 _lat = parseFloat(lat.lat + ""); 2781 _lng = parseFloat(lat.lng + ""); 2782 } 2783 else { 2784 console.error("MapSVG: incorrect format of {lat, lng} object for GeoPoint."); 2785 _lat = 0; 2786 _lng = 0; 2787 } 2788 } 2789 else { 2790 _lat = parseFloat(lat + ""); 2791 _lng = parseFloat(lng + ""); 2792 } 2793 this.lat = _lat; 2794 this.lng = _lng; 2795 } 2796 toString() { 2797 return this.lat + "," + this.lng; 2798 } 2799 } 2800 class Location { 2801 constructor(options) { 2802 this.update(options); 2803 } 2804 update(options) { 2805 if (options.object) { 2806 this.setObject(options.object); 2807 } 2808 if (options.img) { 2809 this.setImage(options.img); 2810 } 2811 if (options.address) { 2812 this.setAddress(options.address); 2813 } 2814 if (options.svgPoint) { 2815 this.setSvgPoint(options.svgPoint); 2816 } 2817 if (options.geoPoint) { 2818 this.setGeoPoint(options.geoPoint); 2819 } 2820 } 2821 setObject(object) { 2822 this.object = object; 2823 } 2824 setImage(imgUrl) { 2825 if (typeof imgUrl !== "string") { 2826 return; 2827 } 2828 let src = imgUrl.split("/").pop(); 2829 if (imgUrl.indexOf("uploads") !== -1) { 2830 src = "uploads/" + src; 2831 } 2832 this.img = src; 2833 this.imagePath = this.getImageUrl(); 2834 this.marker && this.marker && this.marker.setImage(this.imagePath); 2835 } 2836 getImageUrl() { 2837 if (this.img && this.img.indexOf("uploads/") === 0) { 2838 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2839 } 2840 else { 2841 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2842 } 2843 } 2844 setAddress(address) { 2845 this.address = new LocationAddress(address); 2846 } 2847 setSvgPoint(svgPoint) { 2848 this.svgPoint = svgPoint instanceof SVGPoint ? svgPoint : new SVGPoint(svgPoint); 2849 if (this.marker) { 2850 this.marker.setSvgPointFromLocation(); 2851 } 2852 } 2853 setGeoPoint(geoPoint) { 2854 this.geoPoint = geoPoint instanceof GeoPoint ? geoPoint : new GeoPoint(geoPoint); 2855 if (this.marker) { 2856 this.marker.setSvgPointFromLocation(); 2857 } 2858 } 2859 getMarkerImage() { 2860 if (this.img && this.img.indexOf("uploads/") === 0) { 2861 return MapSVG.urls.uploads + "markers/" + this.img.replace("uploads/", ""); 2862 } 2863 else { 2864 return MapSVG.urls.root + "markers/" + (this.img || "_pin_default.png"); 2865 } 2866 } 2867 getData() { 2868 const data = { 2869 img: this.img, 2870 imagePath: this.imagePath, 2871 markerImagePath: this.marker && this.marker.object 2872 ? this.marker.object.getMarkerImage() 2873 : this.imagePath, 2874 address: this.address, 2875 }; 2876 if (this.geoPoint) { 2877 data.geoPoint = { lat: this.geoPoint.lat, lng: this.geoPoint.lng }; 2878 } 2879 if (this.svgPoint) { 2880 data.svgPoint = { x: this.svgPoint.x, y: this.svgPoint.y }; 2881 } 2882 return data; 2883 } 2884 } 2885 2886 class CustomObject { 2887 constructor(params, schema) { 2888 this.initialLoad = true; 2889 this.setSchema(schema); 2890 this.dirtyFields = []; 2891 this.regions = []; 2892 this._regions = {}; 2893 if (params.id !== undefined) { 2894 this.id = params.id; 2895 } 2896 this.initialLoad = true; 2897 this.build(params); 2898 this.initialLoad = false;
2899 if (this.id) { 2900 this.clearDirtyFields(); 2901 } 2902 } 2903 setSchema(schema) { 2904 this.schema = schema; 2905 this.schema.events.on("changed", () => this.setLocationField()); 2906 this.fields = schema.getFieldNames(); 2907 this.setLocationField(); 2908 } 2909 build(params) { 2910 for (const fieldName in params) { 2911 const field = this.schema.getField(fieldName); 2912 if (field) { 2913 if (!this.initialLoad) { 2914 this.dirtyFields.push(fieldName); 2915 } 2916 switch (field.type) { 2917 case "region": 2918 this.regions = params[fieldName]; 2919 break; 2920 case "location": 2921 if (params[fieldName] != null && 2922 params[fieldName] != "" && 2923 Object.keys(params[fieldName]).length !== 0) { 2924 const data = { 2925 img: this.isMarkersByFieldEnabled() 2926 ? this.getMarkerImage() 2927 : params[fieldName].img, 2928 address: new LocationAddress(params[fieldName].address), 2929 }; 2930 if (params[fieldName].geoPoint && 2931 params[fieldName].geoPoint.lat && 2932 params[fieldName].geoPoint.lng) { 2933 data.geoPoint = new GeoPoint(params[fieldName].geoPoint); 2934 } 2935 else if (params[fieldName].svgPoint && 2936 params[fieldName].svgPoint.x && 2937 params[fieldName].svgPoint.y) { 2938 data.svgPoint = new SVGPoint(params[fieldName].svgPoint); 2939 } 2940 if (this.location != null) { 2941 this.location.update(data); 2942 } 2943 else { 2944 this.location = new Location(data); 2945 } 2946 } 2947 else { 2948 this.location = null; 2949 } 2950 break; 2951 case "post": 2952 if (params.post) { 2953 this.post = params.post; 2954 } 2955 break; 2956 case "select": 2957 this[fieldName] = params[fieldName]; 2958 if (!field.multiselect) { 2959 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2960 } 2961 break; 2962 case "radio": 2963 this[fieldName] = params[fieldName]; 2964 this[fieldName + "_text"] = this.getEnumLabel(field, params, fieldName); 2965 break; 2966 default: 2967 this[fieldName] = params[fieldName]; 2968 break; 2969 } 2970 } 2971 } 2972 const locationField = this.getLocationField(); 2973 if (locationField && this.isMarkersByFieldEnabled() && this.isMarkerFieldChanged(params)) { 2974 this.reloadMarkerImage(); 2975 } 2976 } 2977 isMarkerFieldChanged(params) { 2978 return Object.keys(params).indexOf(this.getLocationField().markerField) !== -1; 2979 } 2980 setLocationField() { 2981 } 2982 getLocationField() { 2983 return this.schema.getFieldByType("location"); 2984 } 2985 reloadMarkerImage() { 2986 this.location && this.location.setImage(this.getMarkerImage()); 2987 } 2988 getMarkerImage() { 2989 let fieldValue; 2990 if (this.isMarkersByFieldEnabled()) { 2991 const locationField = this.getLocationField(); 2992 fieldValue = this[locationField.markerField]; 2993 if (!fieldValue) { 2994 return locationField.defaultMarkerPath || MapSVG.defaultMarkerImage; 2995 } 2996 else { 2997 if (locationField.markerField === "regions") { 2998 fieldValue = fieldValue[0] && fieldValue[0].id; 2999 } 3000 else if (typeof fieldValue === "object" && fieldValue.length) { 3001 fieldValue = fieldValue[0].value; 3002 } 3003 return (locationField.markersByField[fieldValue] || 3004 locationField.defaultMarkerPath || 3005 MapSVG.defaultMarkerImage); 3006 } 3007 } 3008 else { 3009 return this.location.imagePath; 3010 } 3011 } 3012 isMarkersByFieldEnabled() { 3013 const locationField = this.getLocationField(); 3014 if (!locationField) { 3015 return false;
3016 } 3017 if (locationField.markersByFieldEnabled && 3018 locationField.markerField && 3019 Object.values(locationField.markersByField).length > 0) { 3020 return true; 3021 } 3022 else { 3023 return false; 3024 } 3025 } 3026 clone() { 3027 const data = this.getData(); 3028 return new CustomObject(data, this.schema); 3029 } 3030 getEnumLabel(field, params, fieldName) { 3031 const value = field.options.get(params[fieldName]); 3032 if (typeof value !== "undefined") { 3033 return value.label; 3034 } 3035 else { 3036 return ""; 3037 } 3038 } 3039 update(params) { 3040 this.build(params); 3041 } 3042 getDirtyFields() { 3043 const data = {}; 3044 this.dirtyFields.forEach((field) => { 3045 data[field] = this[field]; 3046 }); 3047 data.id = this.id; 3048 if (data.location != null && data.location instanceof Location) { 3049 data.location = data.location.getData(); 3050 } 3051 if (this.schema.getFieldByType("region")) { 3052 data.regions = this.regions; 3053 } 3054 return data; 3055 } 3056 clearDirtyFields() { 3057 this.dirtyFields = []; 3058 } 3059 getData() { 3060 const data = {}; 3061 const fields = this.schema.getFields(); 3062 fields.forEach((field) => { 3063 switch (field.type) { 3064 case "region": 3065 data[field.name] = this[field.name]; 3066 break; 3067 case "select": 3068 data[field.name] = this[field.name]; 3069 if (!field.multiselect) { 3070 data[field.name + "_text"] = this[field.name + "_text"]; 3071 } 3072 break; 3073 case "post": 3074 data[field.name] = this[field.name]; 3075 data["post"] = this.post; 3076 break; 3077 case "status": 3078 case "radio": 3079 data[field.name] = this[field.name]; 3080 data[field.name + "_text"] = this[field.name + "_text"]; 3081 break; 3082 case "location": 3083 data[field.name] = this[field.name] ? this[field.name].getData() : null; 3084 break; 3085 default: 3086 data[field.name] = this[field.name]; 3087 break; 3088 } 3089 }); 3090 return data; 3091 } 3092 getRegions(regionsTableName) { 3093 return this.regions; 3094 } 3095 getRegionsForTable(regionsTableName) { 3096 return this.regions 3097 ? this.regions.filter((region) => !region.tableName || region.tableName === regionsTableName) 3098 : []; 3099 } 3100 } 3101 3102 const $$2 = jQuery; 3103 class Repository { 3104 constructor(objectName, path) { 3105 this.server = new Server(); 3106 this.query = new Query(); 3107 this.events = new Events(this); 3108 this.className = ""; 3109 this.objectNameSingle = objectName; 3110 this.objectNameMany = objectName + "s"; 3111 this.setPath(path); 3112 this.objects = new ArrayIndexed("id"); 3113 this.completeChunks = 0; 3114 } 3115 setNoFiltersNoLoad(value) { 3116 this.noFiltersNoLoad = value; 3117 } 3118 setDataSource(path) { 3119 this.setPath(path); 3120 this.query = new Query({ withSchema: true }); 3121 return this.find().done(() => { 3122 this.query.update({ withSchema: false }); 3123 }); 3124 } 3125 setPath(path) { 3126 this.path = path.replace(/\/+$/, "") + "/"; 3127 } 3128 setSchema(schema) { 3129 this.schema = schema; 3130 } 3131 getSchema() { 3132 return this.schema; 3133 } 3134 loadDataFromResponse(response) { 3135 let data; 3136 data = this.decodeData(response); 3137 this.objects.clear(); 3138 if (data[this.objectNameMany] && data[this.objectNameMany].length) { 3139 this.hasMoreRecords = 3140 this.query.perpage && data[this.objectNameMany].length > this.query.perpage; 3141 if (this.hasMoreRecords) { 3142 data[this.objectNameMany].pop(); 3143 }
3144 data[this.objectNameMany].forEach((obj) => { 3145 this.objects.push(obj); 3146 }); 3147 } 3148 else { 3149 this.hasMoreRecords = false; 3150 } 3151 this.loaded = true; 3152 this.events.trigger("loaded"); 3153 } 3154 reload() { 3155 return this.find(); 3156 } 3157 create(object) { 3158 const defer = jQuery.Deferred(); 3159 defer.promise(); 3160 const data = {}; 3161 data[this.objectNameSingle] = this.encodeData(object); 3162 this.server 3163 .post(this.path, data) 3164 .done((response) => { 3165 const data = this.decodeData(response); 3166 const object = data[this.objectNameSingle]; 3167 this.objects.push(object); 3168 defer.resolve(object); 3169 this.events.trigger("created", this, [object]); 3170 }) 3171 .fail((response) => { 3172 defer.reject(response); 3173 }); 3174 return defer; 3175 } 3176 findById(id, nocache = false) { 3177 const defer = jQuery.Deferred(); 3178 defer.promise(); 3179 let object; 3180 if (!nocache) { 3181 object = this.objects.findById(id.toString()); 3182 } 3183 if (!nocache && object) { 3184 defer.resolve(object); 3185 } 3186 else { 3187 this.server 3188 .get(this.path + id) 3189 .done((response) => { 3190 const data = this.decodeData(response); 3191 defer.resolve(data[this.objectNameSingle]); 3192 }) 3193 .fail((response) => { 3194 defer.reject(response); 3195 }); 3196 } 3197 return defer; 3198 } 3199 find(query) { 3200 this.events.trigger("load"); 3201 const defer = jQuery.Deferred(); 3202 defer.promise(); 3203 if (typeof query !== "undefined") { 3204 this.query.update(query); 3205 } 3206 if (this.noFiltersNoLoad && !this.query.hasFilters()) { 3207 this.objects.clear(); 3208 this.events.trigger("loaded"); 3209 defer.resolve(this.getLoaded()); 3210 return defer; 3211 } 3212 if (!this.schema) { 3213 this.query.update({ withSchema: true }); 3214 } 3215 this.server 3216 .get(this.path, this.query) 3217 .done((response) => { 3218 if (!this.schema) { 3219 this.query.update({ withSchema: false }); 3220 } 3221 this.loadDataFromResponse(response); 3222 defer.resolve(this.getLoaded()); 3223 }) 3224 .fail((response) => { 3225 defer.reject(response); 3226 }); 3227 return defer; 3228 } 3229 getLoaded() { 3230 return this.objects; 3231 } 3232 getLoadedObject(id) { 3233 return this.objects.findById(id.toString()); 3234 } 3235 getLoadedAsArray() { 3236 return this.objects; 3237 } 3238 update(object) { 3239 const defer = jQuery.Deferred(); 3240 defer.promise(); 3241 const data = {}; 3242 const objectUpdatedFields = "getDirtyFields" in object ? object.getDirtyFields() : object; 3243 data[this.objectNameSingle] = this.encodeData(objectUpdatedFields); 3244 this.server 3245 .put(this.path + objectUpdatedFields.id, data) 3246 .done((response) => { 3247 if ("clearDirtyFields" in object) { 3248 object.clearDirtyFields(); 3249 } 3250 defer.resolve(object); 3251 this.events.trigger("updated", this, object); 3252 }) 3253 .fail((response, stat) => { 3254 defer.reject(response, stat); 3255 }); 3256 return defer; 3257 } 3258 delete(id) { 3259 const defer = jQuery.Deferred(); 3260 defer.promise(); 3261 this.server 3262 .delete(this.path + id) 3263 .done((response) => { 3264 this.objects.delete(id.toString()); 3265 this.events.trigger("deleted"); 3266 defer.resolve(); 3267 }) 3268 .fail((response) => { 3269 defer.reject(response); 3270 }); 3271 return defer; 3272 } 3273 clear() { 3274 const defer = jQuery.Deferred(); 3275 defer.promise(); 3276 this.server 3277 .delete(this.path) 3278 .done((response) => { 3279 this.objects.clear(); 3280 this.events.trigger("loaded"); 3281 this.events.trigger("cleared"); 3282 defer.resolve(); 3283 }) 3284 .fail((response) => { 3285 defer.reject(response); 3286 }); 3287 return defer; 3288 } 3289 onFirstPage() { 3290 return this.query.page === 1; 3291 } 3292 onLastPage() { 3293 return this.hasMoreRecords === false; 3294 } 3295 encodeData(params) { 3296 return params; 3297 } 3298 decodeData(dataJSON) { 3299 let data; 3300 if (typeof dataJSON === "string") { 3301 data = JSON.parse(dataJSON); 3302 } 3303 else { 3304 data = dataJSON; 3305 } 3306 if ((data.object || data.region || data.regions || data.objects) && data.schema) { 3307 this.setSchema(new Schema(data.schema)); 3308 } 3309 const dataFormatted = {}; 3310 for (const key in data) { 3311 if (data[key]) { 3312 switch (key) { 3313 case "object": 3314 case "region": 3315 dataFormatted[key] = new CustomObject(data[key], this.schema); 3316 break; 3317 case "objects": 3318 case "regions": 3319 dataFormatted[key] = data[key].map((obj) => new CustomObject(obj, this.schema)); 3320 break; 3321 case "schema": 3322 dataFormatted[key] = this.schema || new Schema(data[key]); 3323 break; 3324 case "schemas": 3325 dataFormatted[key] = data[key].map((obj) => new Schema(obj)); 3326 break; 3327 } 3328 } 3329 } 3330 return dataFormatted; 3331 } 3332 import(data, convertLatlngToAddress, mapsvg) { 3333 const _this = this; 3334 const locationField = _this.schema.getFieldByType("location"); 3335 let language = "en"; 3336 if (locationField && locationField.language) { 3337 language = locationField.language; 3338 } 3339 data = this.formatCSV(data, mapsvg); 3340 return this.importByChunks(data, language, convertLatlngToAddress).done(function () { 3341 _this.find(); 3342 }); 3343 } 3344 importByChunks(data, language, convertLatlngToAddress) { 3345 const _this = this; 3346 let i, j, temparray, chunk = 50; 3347 const chunks = []; 3348 for (i = 0, j = data.length; i < j; i += chunk) { 3349 temparray = data.slice(i, i + chunk); 3350 chunks.push(temparray); 3351 } 3352 if (chunks.length > 0) { 3353 let delay = 0; 3354 const delayPlus = chunks[0][0] && chunks[0][0].location ? 1000 : 0; 3355 var defer = $$2.Deferred(); 3356 defer.promise(); 3357 _this.completeChunks = 0; 3358 chunks.forEach(function (chunk) { 3359 delay += delayPlus; 3360 setTimeout(function () { 3361 const data = { 3362 language: language, 3363 convertLatlngToAddress: convertLatlngToAddress, 3364 }; 3365 data[_this.objectNameMany] = JSON.stringify(chunk); 3366 _this.server 3367 .post(_this.path + "import", data) 3368 .done(function (_data) { 3369 _this.completeChunk(chunks, defer); 3370 }) 3371 .fail((response) => { 3372 console.error(response); 3373 }); 3374 }, delay); 3375 }); 3376 } 3377 return defer; 3378 } 3379 completeChunk(chunks, defer) { 3380 const _this = this; 3381 _this.completeChunks++; 3382 if (_this.completeChunks === chunks.length) { 3383 defer.resolve(); 3384 } 3385 } 3386 formatCSV(data, mapsvg) { 3387 const _this = this; 3388 const latLngRegex = /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/g; 3389 const regionsTable = mapsvg.regionsRepository.getSchema().name; 3390 data.forEach(function (object, index) { 3391 const newObject = {}; 3392 for (const key in object) { 3393 let field = _this.schema.getField(key); 3394 if (key === "post") { 3395 field = { type: "post" }; 3396 } 3397 if (field !== undefined) { 3398 switch (field.type) { 3399 case "region":
3400 newObject[key] = {}; 3401 newObject[key] = object[key] 3402 .split(",") 3403 .map(function (regionId) { 3404 return regionId.trim(); 3405 }) 3406 .filter(function (rId) { 3407 return (mapsvg.getRegion(rId) !== undefined || 3408 mapsvg.regions.find(function (item) { 3409 return item.title === rId; 3410 }) !== undefined); 3411 }) 3412 .map(function (rId) { 3413 let r = mapsvg.getRegion(rId); 3414 if (typeof r === "undefined") { 3415 r = mapsvg.regions.find(function (item) { 3416 return item.title === rId; 3417 }); 3418 } 3419 return { id: r.id, title: r.title, tableName: regionsTable }; 3420 }); 3421 break; 3422 case "location": 3423 if (object[key].match(latLngRegex)) { 3424 const coords = object[key].split(",").map(function (n) { 3425 return parseFloat(n); 3426 }); 3427 if (coords.length == 2 && 3428 coords[0] > -90 && 3429 coords[0] < 90 && 3430 coords[1] > -180 && 3431 coords[1] < 180) { 3432 newObject[key] = { 3433 geoPoint: { lat: coords[0], lng: coords[1] }, 3434 }; 3435 } 3436 else { 3437 newObject[key] = ""; 3438 } 3439 } 3440 else if (object[key]) { 3441 newObject[key] = { address: object[key] }; 3442 } 3443 if (typeof newObject[key] == "object") { 3444 newObject[key].img = mapsvg.options.defaultMarkerImage; 3445 } 3446 break; 3447 case "select": 3448 const field = _this.schema.getField(key); 3449 if (field.multiselect) { 3450 const labels = _this.schema.getField(key).options.map(function (f) { 3451 return f.label; 3452 }); 3453 newObject[key] = object[key] 3454 .split(",") 3455 .map(function (label) { 3456 return label.trim(); 3457 }) 3458 .filter(function (label) { 3459 return labels.indexOf(label) !== -1; 3460 }) 3461 .map(function (label) { 3462 return _this.schema 3463 .getField(key) 3464 .options.filter(function (option) { 3465 return option.label == label; 3466 })[0]; 3467 }); 3468 if (newObject[key].length === 0) { 3469 const values = _this.schema 3470 .getField(key) 3471 .options.map(function (f) { 3472 return f.value + ""; 3473 });
3474 newObject[key] = object[key] 3475 .split(",") 3476 .map(function (value) { 3477 return value.trim(); 3478 }) 3479 .filter(function (value) { 3480 return values.indexOf(value) !== -1; 3481 }) 3482 .map(function (value) { 3483 return _this.schema 3484 .getField(key) 3485 .options.filter(function (option) { 3486 return option.value == value; 3487 })[0]; 3488 }); 3489 } 3490 } 3491 else { 3492 newObject[key] = object[key]; 3493 } 3494 break; 3495 case "radio": 3496 case "text": 3497 case "textarea": 3498 case "status": 3499 default: 3500 newObject[key] = object[key]; 3501 break; 3502 } 3503 } 3504 } 3505 data[index] = newObject; 3506 }); 3507 return data; 3508 } 3509 } 3510 3511 class MapsRepository extends Repository { 3512 constructor() { 3513 super("map", "maps"); 3514 this.path = "maps/"; 3515 } 3516 encodeData(params) { 3517 const data = {}; 3518 if (typeof params.options !== "undefined") { 3519 data.options = JSON.stringify(params.options); 3520 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3521 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3522 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3523 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3524 data.options = data.options.replace(/int\(11\)/g, "!mapsvg-encoded-int"); 3525 } 3526 if (typeof params.title !== "undefined") { 3527 data.title = params.title; 3528 } 3529 if (typeof params.id !== "undefined") { 3530 data.id = params.id; 3531 } 3532 if (typeof params.status !== "undefined") { 3533 data.status = params.status; 3534 } 3535 return data; 3536 } 3537 decodeData(dataJSON) { 3538 let data; 3539 if (typeof dataJSON === "string") { 3540 data = JSON.parse(dataJSON); 3541 } 3542 else { 3543 data = dataJSON; 3544 } 3545 return data; 3546 } 3547 copy(id, title) { 3548 const defer = jQuery.Deferred(); 3549 defer.promise(); 3550 const data = { options: { title: title } }; 3551 this.server 3552 .post(this.path + id + "/copy", this.encodeData(data)) 3553 .done((response) => { 3554 const data = this.decodeData(response); 3555 this.objects.clear(); 3556 this.events.trigger("loaded"); 3557 this.events.trigger("cleared"); 3558 defer.resolve(data.map); 3559 }) 3560 .fail(() => { 3561 defer.reject(); 3562 }); 3563 return defer; 3564 } 3565 createFromV2(object) { 3566 const defer = jQuery.Deferred(); 3567 defer.promise(); 3568 const data = {}; 3569 data[this.objectNameSingle] = this.encodeData(object); 3570 this.server 3571 .post(this.path + "/createFromV2", data) 3572 .done((response) => { 3573 const data = this.decodeData(response); 3574 const object = data[this.objectNameSingle]; 3575 this.objects.push(object); 3576 defer.resolve(object); 3577 this.events.trigger("created", this, [object]); 3578 }) 3579 .fail(() => { 3580 defer.reject(); 3581 }); 3582 return defer; 3583 } 3584 delete(id) { 3585 const defer = jQuery.Deferred(); 3586 defer.promise(); 3587 this.server 3588 .delete(this.path + id) 3589 .done((response) => { 3590 this.objects.delete(id.toString()); 3591 this.events.trigger("deleted"); 3592 defer.resolve(); 3593 }) 3594 .fail(() => { 3595 defer.reject(); 3596 }); 3597 return defer; 3598 } 3599 } 3600 3601 class MapsV2Repository extends Repository { 3602 constructor() { 3603 super("map", "maps"); 3604 this.path = "maps-v2/"; 3605 } 3606 encodeData(params) { 3607 const data = {}; 3608 data.options = JSON.stringify(params.options); 3609 data.options = data.options.replace(/select/g, "!mapsvg-encoded-slct"); 3610 data.options = data.options.replace(/table/g, "!mapsvg-encoded-tbl"); 3611 data.options = data.options.replace(/database/g, "!mapsvg-encoded-db"); 3612 data.options = data.options.replace(/varchar/g, "!mapsvg-encoded-vc"); 3613 data.id = params.id; 3614 data.title = params.title; 3615 return data; 3616 } 3617 decodeData(dataJSON) { 3618 let data; 3619 if (typeof dataJSON === "string") { 3620 data = JSON.parse(dataJSON); 3621 } 3622 else { 3623 data = dataJSON; 3624 } 3625 return data; 3626 } 3627 } 3628 3629 class Converter {
3630 constructor(mapElement, defViewBox, viewBox, geoViewBox) { 3631 this.mapElement = mapElement; 3632 this.defViewBox = defViewBox; 3633 this.viewBox = viewBox; 3634 this.yShift = 0; 3635 if (geoViewBox) { 3636 this.setGeoViewBox(geoViewBox); 3637 } 3638 } 3639 setYShift() { 3640 if (this.defViewBox.width === 20426) { 3641 this.yShift = 0; 3642 return; 3643 } 3644 if (this.geoViewBox) { 3645 const topLeftPoint = this.convertGeoToSVG(this.geoViewBox.ne); 3646 this.yShift = topLeftPoint.y - this.defViewBox.y; 3647 } 3648 } 3649 setGeoViewBox(geoViewBox) { 3650 this.geoViewBox = geoViewBox; 3651 this.mapLonDelta = this.geoViewBox.ne.lng - this.geoViewBox.sw.lng; 3652 this.mapLatBottomDegree = (this.geoViewBox.sw.lat * Math.PI) / 180; 3653 this.worldMapWidth = (this.defViewBox.width / this.mapLonDelta) * 360; 3654 this.worldMapRadius = ((this.defViewBox.width / this.mapLonDelta) * 360) / (2 * Math.PI); 3655 this.setYShift(); 3656 } 3657 setWorldShift(on) { 3658 this.worldShift = on; 3659 } 3660 getScale() { 3661 return this.mapElement.clientWidth / this.viewBox.width; 3662 } 3663 convertSVGToPixel(svgPoint) { 3664 const scale = this.getScale(); 3665 let shiftXByGM = 0; 3666 const shiftYByGM = 0; 3667 if (this.worldShift) { 3668 if (this.viewBox.x - this.defViewBox.x > this.defViewBox.width) { 3669 shiftXByGM = 3670 this.worldMapWidth * 3671 Math.floor((this.viewBox.x - this.defViewBox.x) / this.defViewBox.width); 3672 } 3673 } 3674 return new ScreenPoint((svgPoint.x - this.viewBox.x + shiftXByGM) * scale, (svgPoint.y - this.viewBox.y + shiftYByGM) * scale); 3675 } 3676 convertPixelToSVG(screenPoint) { 3677 const scale = this.getScale(); 3678 return new SVGPoint(screenPoint.x / scale + this.viewBox.x, screenPoint.y / scale + this.viewBox.y); 3679 } 3680 convertGeoToSVG(geoPoint) { 3681 if (!this.geoViewBox) { 3682 throw new Error("Can't do convertGeoToSVG() - geoViewBox is not provided."); 3683 } 3684 let x = (geoPoint.lng - this.geoViewBox.sw.lng) * (this.defViewBox.width / this.mapLonDelta); 3685 const lat = (geoPoint.lat * Math.PI) / 180; 3686 const mapOffsetY = (this.worldMapRadius / 2) * 3687 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3688 let y = this.defViewBox.height - 3689 ((this.worldMapRadius / 2) * Math.log((1 + Math.sin(lat)) / (1 - Math.sin(lat))) - 3690 mapOffsetY); 3691 x += this.defViewBox.x; 3692 y += this.defViewBox.y; 3693 y -= this.yShift; 3694 return new SVGPoint(x, y); 3695 } 3696 convertSVGToGeo(svgPoint) { 3697 if (!this.geoViewBox) { 3698 throw new Error("Can't do convertSVGToGeo() - geoViewBox is not provided."); 3699 } 3700 const tx = svgPoint.x - this.defViewBox.x; 3701 const ty = svgPoint.y - this.defViewBox.y; 3702 const mapOffsetY = (this.worldMapRadius / 2) * 3703 Math.log((1 + Math.sin(this.mapLatBottomDegree)) / (1 - Math.sin(this.mapLatBottomDegree))); 3704 const equatorY = this.defViewBox.height + mapOffsetY; 3705 const a = (equatorY - ty) / this.worldMapRadius; 3706 let lat = (180 / Math.PI) * (2 * Math.atan(Math.exp(a)) - Math.PI / 2); 3707 let lng = this.geoViewBox.sw.lng + (tx / this.defViewBox.width) * this.mapLonDelta; 3708 lat = parseFloat(lat.toFixed(6)); 3709 lng = parseFloat(lng.toFixed(6)); 3710 return new GeoPoint(lat, lng); 3711 } 3712 } 3713 3714 const $$3 = jQuery; 3715 class ResizeSensor { 3716 constructor(element, callback) { 3717 const _this = this; 3718 _this.element = element; 3719 _this.callback = callback; 3720 const style = getComputedStyle(element); 3721 let zIndex = parseInt(style.zIndex); 3722 if (isNaN(zIndex)) { 3723 zIndex = 0; 3724 } 3725 zIndex--; 3726 _this.expand = document.createElement("div"); 3727 _this.expand.style.position = "absolute";
3728 _this.expand.style.left = "0px"; 3729 _this.expand.style.top = "0px"; 3730 _this.expand.style.right = "0px"; 3731 _this.expand.style.bottom = "0px"; 3732 _this.expand.style.overflow = "hidden"; 3733 _this.expand.style.zIndex = zIndex.toString(); 3734 _this.expand.style.visibility = "hidden"; 3735 const expandChild = document.createElement("div"); 3736 expandChild.style.position = "absolute"; 3737 expandChild.style.left = "0px"; 3738 expandChild.style.top = "0px"; 3739 expandChild.style.width = "10000000px"; 3740 expandChild.style.height = "10000000px"; 3741 _this.expand.appendChild(expandChild); 3742 _this.shrink = document.createElement("div"); 3743 _this.shrink.style.position = "absolute"; 3744 _this.shrink.style.left = "0px"; 3745 _this.shrink.style.top = "0px"; 3746 _this.shrink.style.right = "0px"; 3747 _this.shrink.style.bottom = "0px"; 3748 _this.shrink.style.overflow = "hidden"; 3749 _this.shrink.style.zIndex = zIndex.toString(); 3750 _this.shrink.style.visibility = "hidden"; 3751 const shrinkChild = document.createElement("div"); 3752 shrinkChild.style.position = "absolute"; 3753 shrinkChild.style.left = "0px"; 3754 shrinkChild.style.top = "0px"; 3755 shrinkChild.style.width = "200%"; 3756 shrinkChild.style.height = "200%"; 3757 _this.shrink.appendChild(shrinkChild); 3758 _this.element.appendChild(_this.expand); 3759 _this.element.appendChild(_this.shrink); 3760 const size = element.getBoundingClientRect(); 3761 _this.currentWidth = size.width; 3762 _this.currentHeight = size.height; 3763 _this.setScroll(); 3764 _this.expand.addEventListener("scroll", function () { 3765 _this.onScroll(); 3766 }); 3767 _this.shrink.addEventListener("scroll", function () { 3768 _this.onScroll(); 3769 }); 3770 } 3771 onScroll() { 3772 const _this = this; 3773 const size = _this.element.getBoundingClientRect(); 3774 const newWidth = size.width; 3775 const newHeight = size.height; 3776 if (newWidth != _this.currentWidth || newHeight != _this.currentHeight) { 3777 _this.currentWidth = newWidth; 3778 _this.currentHeight = newHeight; 3779 _this.callback(); 3780 } 3781 this.setScroll(); 3782 } 3783 setScroll() { 3784 this.expand.scrollLeft = 10000000; 3785 this.expand.scrollTop = 10000000; 3786 this.shrink.scrollLeft = 10000000; 3787 this.shrink.scrollTop = 10000000; 3788 } 3789 destroy() { 3790 this.expand.remove(); 3791 this.shrink.remove(); 3792 } 3793 } 3794 3795 class ViewBox { 3796 constructor(x, y, width, height) { 3797 if (typeof x === "object") { 3798 if (x.hasOwnProperty("x") && 3799 x.hasOwnProperty("y") && 3800 x.hasOwnProperty("width") && 3801 x.hasOwnProperty("height")) { 3802 this.x = typeof x.x === "string" ? parseFloat(x.x) : x.x; 3803 this.y = typeof x.y === "string" ? parseFloat(x.y) : x.y; 3804 this.width = typeof x.width === "string" ? parseFloat(x.width) : x.width; 3805 this.height = typeof x.height === "string" ? parseFloat(x.height) : x.height; 3806 } 3807 else if (typeof x === "object" && x.length && x.length === 4) { 3808 this.x = typeof x[0] === "string" ? parseFloat(x[0]) : x[0]; 3809 this.y = typeof x[1] === "string" ? parseFloat(x[1]) : x[1]; 3810 this.width = typeof x[2] === "string" ? parseFloat(x[2]) : x[2]; 3811 this.height = typeof x[3] === "string" ? parseFloat(x[3]) : x[3]; 3812 } 3813 } 3814 else { 3815 this.x = typeof x === "string" ? parseFloat(x) : x; 3816 this.y = typeof y === "string" ? parseFloat(y) : y; 3817 this.width = typeof width === "string" ? parseFloat(width) : width; 3818 this.height = typeof height === "string" ? parseFloat(height) : height; 3819 } 3820 } 3821 update(newViewBox) { 3822 this.x = newViewBox.x; 3823 this.y = newViewBox.y; 3824 this.width = newViewBox.width; 3825 this.height = newViewBox.height; 3826 } 3827 toString() { 3828 return this.x + " " + this.y + " " + this.width + " " + this.height; 3829 } 3830 toArray() { 3831 return [this.x, this.y, this.width, this.height]; 3832 } 3833 clone() { 3834 return new ViewBox({ x: this.x, y: this.y, width: this.width, height: this.height }); 3835 } 3836 fitsInViewBox(viewBox, atLeastByOneDimension) { 3837 if (atLeastByOneDimension === true) { 3838 return viewBox.width >
3838 this.width || viewBox.height > this.height; 3839 } 3840 else { 3841 return viewBox.width > this.width && viewBox.height > this.height; 3842 } 3843 } 3844 addPadding(padding) { 3845 if (padding.top) { 3846 this.y -= padding.top; 3847 this.height += padding.top; 3848 } 3849 if (padding.right) { 3850 this.width += padding.right; 3851 } 3852 if (padding.bottom) { 3853 this.height += padding.bottom; 3854 } 3855 if (padding.left) { 3856 this.x -= padding.left; 3857 this.width += padding.left; 3858 } 3859 } 3860 } 3861 class GeoViewBox { 3862 constructor(sw, ne) { 3863 this.sw = sw; 3864 this.ne = ne; 3865 } 3866 } 3867 3868 const $$4 = jQuery; 3869 class MapObject { 3870 constructor(element, mapsvg) { 3871 this.id = ""; 3872 this.objects = []; 3873 this.events = new Events(this); 3874 this.element = element; 3875 this.mapsvg = mapsvg; 3876 } 3877 getBBox() { 3878 return new ViewBox(1, 2, 3, 4); 3879 } 3880 getGeoBounds() { 3881 const bbox = this.getBBox(); 3882 const pointSW = new SVGPoint(bbox.x, bbox.y + bbox.height); 3883 const pointNE = new SVGPoint(bbox.x + bbox.width, bbox.y); 3884 const sw = this.mapsvg.converter.convertSVGToGeo(pointSW); 3885 const ne = this.mapsvg.converter.convertSVGToGeo(pointNE); 3886 return { sw: sw, ne: ne }; 3887 } 3888 getComputedStyle(prop, elem) { 3889 elem = elem || this.element; 3890 return MapObject.getComputedStyle(prop, elem); 3891 } 3892 static getComputedStyle(prop, elem) { 3893 const _p1 = elem.getAttribute(prop); 3894 if (_p1) { 3895 return _p1; 3896 } 3897 const _p2 = elem.getAttribute("style"); 3898 if (_p2) { 3899 const s = _p2.split(";"); 3900 const z = s.filter(function (e) { 3901 e = e.trim(); 3902 const attr = e.split(":"); 3903 if (attr[0] == prop) 3904 return true; 3905 }); 3906 if (z.length) { 3907 return z[0].split(":").pop().trim(); 3908 } 3909 } 3910 const parent = elem.parentElement; 3911 const elemType = parent ? parent.tagName : null; 3912 if (elemType && elemType != "svg") 3913 return MapObject.getComputedStyle(prop, parent); 3914 else 3915 return undefined; 3916 } 3917 getStyle(prop) { 3918 const _p1 = this.attr(prop); 3919 if (_p1) { 3920 return _p1; 3921 } 3922 const _p2 = this.attr("style"); 3923 if (_p2) { 3924 const s = _p2.split(";"); 3925 const z = s.filter(function (e) { 3926 var e = e.trim(); 3927 if (e.indexOf(prop) === 0) 3928 return e; 3929 }); 3930 return z.length ? z[0].split(":").pop().trim() : undefined; 3931 } 3932 return ""; 3933 } 3934 getCenter() { 3935 const x = this.element.getBoundingClientRect().left; 3936 const y = this.element.getBoundingClientRect().top; 3937 const w = this.element.getBoundingClientRect().width; 3938 const h = this.element.getBoundingClientRect().height; 3939 const point = new ScreenPoint(x + w / 2, y + h / 2); 3940 return point; 3941 } 3942 getCenterSVG() { 3943 const bbox = this.getBBox(); 3944 const point = new SVGPoint(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2); 3945 return point; 3946 } 3947 getCenterLatLng(yShift) { 3948 yShift = yShift ? yShift : 0; 3949 const bbox = this.getBBox(); 3950 const x = bbox.x + bbox.width / 2; 3951 const y = bbox.y + bbox.height / 2 - yShift; 3952 const point = new SVGPoint(x, y); 3953 return this.mapsvg.converter.convertSVGToGeo(point); 3954 } 3955 attr(v1, v2 = null) { 3956 const svgDom = this.element; 3957 if (typeof v1 == "object") { 3958 for (const key in v1) { 3959 const item = v1[key]; 3960 if (typeof item === "string" || typeof item === "number") { 3961 svgDom.setAttribute(key, "" + item); 3962 } 3963 } 3964 } 3965 else if (typeof v1 == "string" && (typeof v2 == "string" || typeof v2 == "number")) { 3966 svgDom.setAttribute(v1, "" + v2); 3967 } 3968 else if (v2 == undefined) { 3969 return svgDom.getAttribute(v1); 3970 } 3971 } 3972 setId(id) { 3973 if (id !== undefined) { 3974 this.id = id; 3975 this.element.setAttribute("id", id); 3976 } 3977 } 3978 } 3979 3980 const $$5 = jQuery; 3981 class Marker extends MapObject { 3982 constructor(params) { 3983 super(null, params.mapsvg); 3984 this.element = $$5("<div />").addClass("mapsvg-marker")[0]; 3985 this.image = $$5('<img src="" />').addClass("mapsvg-marker-image")[0]; 3986 if (params.object) { 3987 this.setObject(params.object); 3988 } 3989 if (!(params.location instanceof Location)) { 3990 throw new Error("MapSVG.Marker: no Location provided for Marker initializaton"); 3991 } 3992 else { 3993 this.location = params.location; 3994 this.location.marker = this; 3995 } 3996 this.setImage(this.location.imagePath); 3997 $$5(this.element).append(this.image); 3998 if (params.width && params.height) { 3999 this.setSize(params.width, params.height); 4000 } 4001 else { 4002 this.setSize(15, 24); 4003 } 4004 this.setId(this.mapsvg.markerId()); 4005 this.setSvgPointFromLocation(); 4006 this.setAltAttr(); 4007 } 4008 reload() { 4009 this.setImage(); 4010 this.setSvgPointFromLocation(); 4011 } 4012 getImagePath() { 4013 return (this.object && this.object.getMarkerImage()) || this.location.getMarkerImage(); 4014 } 4015 setSize(width, height) { 4016 this.width = width; 4017 this.height = height; 4018 this.setCentered(this.width === this.height); 4019 } 4020 setSvgPointFromLocation() { 4021 const svgPoint = this.location.geoPoint && 4022 this.location.geoPoint.lat !== 0 && 4023 this.location.geoPoint.lng !== 0 4024 ? this.mapsvg.converter.convertGeoToSVG(this.location.geoPoint) 4025 : this.location.svgPoint; 4026 if (svgPoint) { 4027 this.setSvgPoint(svgPoint); 4028 } 4029 } 4030 setId(id) { 4031 MapObject.prototype.setId.call(this, id); 4032 this.mapsvg.markers.reindex(); 4033 } 4034 getBBox() { 4035 if (this.centered) { 4036 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); 4037 } 4038 else { 4039 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); 4040 } 4041 } 4042 getOptions() { 4043 const o = { 4044 id: this.id, 4045 src: this.src, 4046 svgPoint: this.svgPoint, 4047 geoPoint: this.geoPoint, 4048 }; 4049 $$5.each(o, function (key, val) { 4050 if (val == undefined) { 4051 delete o[key]; 4052 } 4053 }); 4054 return o; 4055 } 4056 update(data) { 4057 for (const key in data) { 4058 const setter = "set" + MapSVG.ucfirst(key); 4059 if (setter in this) 4060 this[setter](data[key]); 4061 } 4062 } 4063 setImage(src, skipChangingLocationImage = false) { 4064 if (!src) { 4065 src = this.getImagePath(); 4066 } 4067 this.src = MapSVG.safeURL(src); 4068 const img = new Image(); 4069 const marker = this; 4070 img.onload = function () { 4071 if (marker.image.getAttribute("src") !== "src") { 4072 marker.image.setAttribute("src", marker.src); 4073 } 4074 marker.setSize(this.width, this.height); 4075 marker.adjustScreenPosition(); 4076 }; 4077 img.src = this.src; 4078 this.events.trigger("change"); 4079 } 4080 setAltAttr() { 4081 const marker = this; 4082 marker.altAttr = 4083 typeof marker.object != "undefined" && 4084 typeof marker.object.title != "undefined" && 4085 marker.object.title !== "" 4086 ? marker.object.title 4087 : marker.id; 4088 marker.image.setAttribute("alt", marker.altAttr); 4089 } 4090 setSvgPoint(svgPoint) { 4091 this.svgPoint = svgPoint; 4092 this.adjustScreenPosition(); 4093 this.events.trigger("change"); 4094 } 4095 adjustScreenPosition() { 4096 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 4097 pos.x -= this.width / 2; 4098 pos.y -= !this.centered ? this.height : this.height / 2; 4099 this.setScreenPosition(pos.x, pos.y); 4100 } 4101 moveSrceenPositionBy(deltaX, deltaY) { 4102 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 4103 this.setScreenPosition(x, y); 4104 } 4105 setScreenPosition(x, y) { 4106 if (this.screenPoint instanceof ScreenPoint) { 4107 this.screenPoint.x = x; 4108 this.screenPoint.y = y; 4109 } 4110 else { 4111 this.screenPoint = new ScreenPoint(x, y); 4112 } 4113 this.updateVisibility(); 4114 if (this.visible === true) { 4115 this.element.style.transform = "translate(" + x + "px," + y + "px)"; 4116 this.adjustLabelScreenPosition(); 4117 } 4118 } 4119 adjustLabelScreenPosition() { 4120 if (this.label) { 4121 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()); 4122 } 4123 } 4124 inViewBox() { 4125 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 4126 return (x - this.width / 2 < 2 * mapFullWidth && 4127 x + this.width / 2 > -mapFullWidth && 4128 y - this.height / 2 < 2 * mapFullHeight && 4129 y + this.height / 2 > -mapFullHeight); 4130 } 4131 updateVisibility() { 4132 if (this.inViewBox() === true) { 4133 this.visible = true; 4134 this.element.classList.remove("mapsvg-out-of-sight"); 4135 if (this.label) { 4136 this.label.classList.remove("mapsvg-out-of-sight"); 4137 } 4138 } 4139 else { 4140 this.visible = false;
4141 this.element.classList.add("mapsvg-out-of-sight"); 4142 if (this.label) { 4143 this.label.classList.add("mapsvg-out-of-sight"); 4144 } 4145 } 4146 return this.visible; 4147 } 4148 isMoving() { 4149 return this.moving; 4150 } 4151 setMoving(value) { 4152 this.moving = value; 4153 } 4154 drag(startCoords, scale, endCallback, clickCallback) { 4155 const _this = this; 4156 this.svgPointBeforeDrag = new SVGPoint(this.svgPoint.x, this.svgPoint.y); 4157 this.setMoving(true); 4158 $$5("body").on("mousemove.drag.mapsvg", function (e) { 4159 e.preventDefault(); 4160 $$5(_this.mapsvg.containers.map).addClass("no-transitions"); 4161 const mouseNew = MapSVG.mouseCoords(e); 4162 const dx = mouseNew.x - startCoords.x; 4163 const dy = mouseNew.y - startCoords.y; 4164 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 4165 _this.setSvgPoint(newSvgPoint); 4166 }); 4167 $$5("body").on("mouseup.drag.mapsvg", function (e) { 4168 e.preventDefault(); 4169 _this.undrag(); 4170 const mouseNew = MapSVG.mouseCoords(e); 4171 const dx = mouseNew.x - startCoords.x; 4172 const dy = mouseNew.y - startCoords.y; 4173 const newSvgPoint = new SVGPoint(_this.svgPointBeforeDrag.x + dx / scale, _this.svgPointBeforeDrag.y + dy / scale); 4174 _this.setSvgPoint(newSvgPoint); 4175 if (_this.mapsvg.isGeo()) { 4176 _this.geoPoint = _this.mapsvg.converter.convertSVGToGeo(newSvgPoint); 4177 } 4178 endCallback && endCallback.call(_this); 4179 if (_this.svgPointBeforeDrag.x == _this.svgPoint.x && 4180 _this.svgPointBeforeDrag.y == _this.svgPoint.y) 4181 clickCallback && clickCallback.call(_this); 4182 }); 4183 } 4184 undrag() { 4185 this.setMoving(false); 4186 $$5("body").off(".drag.mapsvg"); 4187 $$5(this.mapsvg.containers.map).removeClass("no-transitions"); 4188 } 4189 delete() { 4190 if (this.label) { 4191 this.label.remove(); 4192 this.label = null; 4193 } 4194 $$5(this.element).empty().remove(); 4195 } 4196 setObject(obj) { 4197 this.object = obj; 4198 $$5(this.element).attr("data-object-id", this.object.id); 4199 } 4200 hide() { 4201 $$5(this.element).addClass("mapsvg-marker-hidden"); 4202 if (this.label) { 4203 $$5(this.label).hide(); 4204 } 4205 } 4206 show() { 4207 $$5(this.element).removeClass("mapsvg-marker-hidden"); 4208 if (this.label) { 4209 $$5(this.label).show(); 4210 } 4211 } 4212 highlight() { 4213 $$5(this.element).addClass("mapsvg-marker-hover"); 4214 } 4215 unhighlight() { 4216 $$5(this.element).removeClass("mapsvg-marker-hover"); 4217 } 4218 select() { 4219 this.selected = true; 4220 $$5(this.element).addClass("mapsvg-marker-active"); 4221 } 4222 deselect() { 4223 this.selected = false; 4224 $$5(this.element).removeClass("mapsvg-marker-active"); 4225 } 4226 getData() { 4227 return this.object; 4228 } 4229 getChoroplethColor() { 4230 const markerValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4231 let color; 4232 if (!markerValue) { 4233 color = this.mapsvg.options.choropleth.coloring.noData.color; 4234 } 4235 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 4236 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 4237 ? 0 4238 : (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); 4239 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 4240 } 4241 else { 4242 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 4243 if (!paletteColors[0].valueFrom && markerValue < paletteColors[0].valueTo) { 4244 color = paletteColors[0].color; 4245 } 4246 else if (!paletteColors[paletteColors.length - 1].valueTo && 4247 markerValue > paletteColors[paletteColors.length - 1].valueFrom) { 4248 color = paletteColors[paletteColors.length - 1].color; 4249 } 4250 else {
4251 paletteColors.forEach(function (paletteColor) { 4252 if (markerValue >= paletteColor.valueFrom && 4253 markerValue < paletteColor.valueTo) { 4254 color = paletteColor.color; 4255 } 4256 }); 4257 color = color 4258 ? color 4259 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4260 } 4261 } 4262 return color; 4263 } 4264 getBubbleSize() { 4265 let bubbleSize; 4266 if (this.object[this.mapsvg.options.choropleth.sourceField]) { 4267 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]); 4268 bubbleSize = 4269 ((sourceFieldvalue - minSourceFieldvalue) / 4270 (maxSourceFieldvalue - minSourceFieldvalue)) * 4271 (maxBubbleSize - minBubbleSize) + 4272 Number(minBubbleSize); 4273 } 4274 else { 4275 bubbleSize = false; 4276 } 4277 return bubbleSize; 4278 } 4279 getBubbleScreenPosition() { 4280 const bubbleSize = Number(this.getBubbleSize()); 4281 return { 4282 x: this.width / 2 - bubbleSize / 2, 4283 y: this.height - bubbleSize / 2, 4284 }; 4285 } 4286 drawBubble() { 4287 const bubbleId = "mapsvg-bubble-" + this.object.id; 4288 const bubbleValue = parseFloat(this.object[this.mapsvg.options.choropleth.sourceField]); 4289 if (bubbleValue) { 4290 if (!this.bubble) { 4291 this.bubble = $$5('<div id="' + 4292 bubbleId + 4293 '" data-marker-id="' + 4294 this.element.id + 4295 '" class="mapsvg-bubble mapsvg-marker-bubble"></div>')[0]; 4296 $$5(this.element).append(this.bubble); 4297 } 4298 const color = this.getChoroplethColor(), bubbleSize = Number(this.getBubbleSize()); 4299 $$5(this.bubble) 4300 .css("background-color", color) 4301 .css("width", bubbleSize + "px") 4302 .css("height", bubbleSize + "px") 4303 .css("lineHeight", bubbleSize - 2 + "px"); 4304 } 4305 else { 4306 $$5("#" + bubbleId).remove(); 4307 delete this.bubble; 4308 } 4309 } 4310 setBubbleMode(bubbleMode) { 4311 this.bubbleMode = bubbleMode; 4312 if (bubbleMode) { 4313 this.setCentered(true); 4314 this.drawBubble(); 4315 if (this.bubble) { 4316 this.width = this.bubble.offsetWidth; 4317 this.height = this.bubble.offsetHeight; 4318 this.adjustScreenPosition(); 4319 } 4320 } 4321 else { 4322 this.setImage(this.src); 4323 } 4324 } 4325 setLabel(html) { 4326 if (html) { 4327 if (!this.label) { 4328 this.label = $$5("<div />").addClass("mapsvg-marker-label")[0]; 4329 $$5(this.element).append(this.label); 4330 } 4331 $$5(this.label).html(html); 4332 } 4333 else { 4334 if (this.label) { 4335 $$5(this.label).remove(); 4336 delete this.label; 4337 } 4338 } 4339 } 4340 setCentered(on) { 4341 this.centered = on; 4342 } 4343 } 4344 4345 const $$6 = jQuery; 4346 class MarkerCluster extends MapObject { 4347 constructor(options, mapsvg) { 4348 super(null, mapsvg); 4349 this.svgPoint = options.svgPoint; 4350 this.cellX = options.cellX; 4351 this.cellY = options.cellY; 4352 this.markers = options.markers || []; 4353 this.cellSize = 50; 4354 this.width = 30; 4355 this.elem = $$6('<div class="mapsvg-marker-cluster">' + this.markers.length + "</div>")[0]; 4356 $$6(this.elem).data("cluster", this); 4357 if (this.markers.length < 2) { 4358 $$6(this.elem).hide(); 4359 } 4360 this.adjustScreenPosition(); 4361 } 4362 addMarker(marker) { 4363 this.markers.push(marker); 4364 if (this.markers.length > 1) { 4365 if (this.markers.length === 2) { 4366 $$6(this.elem).show(); 4367 } 4368 if (this.markers.length === 2) { 4369 const x = this.markers.map(function (m) { 4370 return m.svgPoint.x; 4371 }); 4372 this.min_x = Math.min.apply(null, x); 4373 this.max_x = Math.max.apply(null, x); 4374 const y = this.markers.map(function (m) { 4375 return m.svgPoint.y; 4376 }); 4377 this.min_y = Math.min.apply(null, y); 4378 this.max_y = Math.max.apply(null, y); 4379 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4380 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4381 } 4382 if (this.markers.length > 2) { 4383 if (marker.svgPoint.x < this.min_x) { 4384 this.min_x = marker.svgPoint.x; 4385 } 4386 else if (marker.svgPoint.x > this.max_x) { 4387 this.max_x = marker.svgPoint.x; 4388 } 4389 if (marker.svgPoint.y < this.min_y) { 4390 this.min_y = marker.svgPoint.y; 4391 } 4392 else if (marker.svgPoint.x > this.max_x) { 4393 this.max_y = marker.svgPoint.y; 4394 } 4395 this.svgPoint.x = this.min_x + (this.max_x - this.min_x) / 2; 4396 this.svgPoint.y = this.min_y + (this.max_y - this.min_y) / 2; 4397 } 4398 } 4399 else { 4400 this.svgPoint.x = marker.svgPoint.x; 4401 this.svgPoint.y = marker.svgPoint.y; 4402 } 4403 $$6(this.elem).text(this.markers.length); 4404 this.adjustScreenPosition(); 4405 } 4406 canTakeMarker(marker) { 4407 const _this = this; 4408 const screenPoint = _this.mapsvg.converter.convertSVGToPixel(marker.svgPoint); 4409 return (this.cellX === Math.ceil(screenPoint.x / this.cellSize) && 4410 this.cellY === Math.ceil(screenPoint.y / this.cellSize)); 4411 } 4412 destroy() { 4413 this.markers = null; 4414 $$6(this.elem).remove(); 4415 } 4416 adjustScreenPosition() { 4417 const pos = this.mapsvg.converter.convertSVGToPixel(this.svgPoint); 4418 pos.x -= this.width / 2; 4419 pos.y -= this.width / 2; 4420 this.setScreenPosition(pos.x, pos.y); 4421 } 4422 moveSrceenPositionBy(deltaX, deltaY) { 4423 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 4424 this.setScreenPosition(x, y); 4425 } 4426 setScreenPosition(x, y) { 4427 if (this.screenPoint instanceof ScreenPoint) { 4428 this.screenPoint.x = x; 4429 this.screenPoint.y = y; 4430 } 4431 else { 4432 this.screenPoint = new ScreenPoint(x, y); 4433 } 4434 this.updateVisibility(); 4435 if (this.visible === true) { 4436 this.elem.style.transform = "translate(" + x + "px," + y + "px)"; 4437 } 4438 } 4439 inViewBox() { 4440 const x = this.screenPoint.x, y = this.screenPoint.y, mapFullWidth = this.mapsvg.containers.map.offsetWidth, mapFullHeight = this.mapsvg.containers.map.offsetHeight; 4441 return (x - this.width / 2 < mapFullWidth && 4442 x + this.width / 2 > 0 && 4443 y - this.width / 2 < mapFullHeight && 4444 y + this.width / 2 > 0); 4445 } 4446 updateVisibility() { 4447 if (this.inViewBox() === true) { 4448 this.visible = true; 4449 this.elem.classList.remove("mapsvg-out-of-sight"); 4450 } 4451 else { 4452 this.visible = false;
4453 this.elem.classList.add("mapsvg-out-of-sight"); 4454 } 4455 return this.visible; 4456 } 4457 getBBox() { 4458 let bbox = { 4459 x: this.svgPoint.x, 4460 y: this.svgPoint.y, 4461 width: this.cellSize / this.mapsvg.getScale(), 4462 height: this.cellSize / this.mapsvg.getScale(), 4463 }; 4464 bbox = $$6.extend(true, {}, bbox); 4465 return new ViewBox(bbox.x, bbox.y, bbox.width, bbox.height); 4466 } 4467 getData() { 4468 return this.markers.map((m) => m.object); 4469 } 4470 } 4471 4472 const $$7 = jQuery; 4473 class Region extends MapObject { 4474 constructor(element, mapsvg) { 4475 super(element, mapsvg); 4476 this.id = this.element.getAttribute("id"); 4477 if (this.id && this.mapsvg.options.regionPrefix) { 4478 this.setId(this.id.replace(this.mapsvg.options.regionPrefix, "")); 4479 } 4480 this.id_no_spaces = this.id.replace(/\s/g, "_"); 4481 this.element.setAttribute("class", (this.element.className || "") + " mapsvg-region"); 4482 this.setStyleInitial(); 4483 const regionOptions = this.mapsvg.options.regions && this.mapsvg.options.regions[this.id] 4484 ? this.mapsvg.options.regions[this.id] 4485 : null; 4486 this.disabled = this.getDisabledState(); 4487 this.disabled && this.attr("class", this.attr("class") + " mapsvg-disabled"); 4488 this.default_attr = {}; 4489 this.selected_attr = {}; 4490 this.hover_attr = {}; 4491 let selected = false; 4492 if (regionOptions && regionOptions.selected) { 4493 selected = true; 4494 delete regionOptions.selected; 4495 } 4496 regionOptions && this.update(regionOptions); 4497 this.setFill(); 4498 if (selected) { 4499 this.setSelected(); 4500 } 4501 this.saveState(); 4502 } 4503 adjustStroke(scale) { 4504 $$7(this.element).css({ "stroke-width": this.style["stroke-width"] / scale }); 4505 } 4506 setStyleInitial() { 4507 this.style = { fill: this.getComputedStyle("fill") }; 4508 this.style.stroke = this.getComputedStyle("stroke") || ""; 4509 let w; 4510 w = this.getComputedStyle("stroke-width"); 4511 w = w ? w.replace("px", "") : "1"; 4512 w = parseFloat(w); 4513 this.style["stroke-width"] = w; 4514 $$7(this.element).attr("data-stroke-width", w); 4515 } 4516 saveState() { 4517 this.initialState = JSON.stringify(this.getOptions()); 4518 } 4519 getBBox() { 4520 const _bbox = this.element.getBBox(); 4521 const bbox = new ViewBox(_bbox.x, _bbox.y, _bbox.width, _bbox.height); 4522 const matrix = this.element.getTransformToElement(this.mapsvg.containers.svg); 4523 if (!matrix) { 4524 return _bbox; 4525 } 4526 const x2 = bbox.x + bbox.width; 4527 const y2 = bbox.y + bbox.height; 4528 let position = this.mapsvg.containers.svg.createSVGPoint(); 4529 position.x = bbox.x; 4530 position.y = bbox.y; 4531 position = position.matrixTransform(matrix); 4532 bbox.x = position.x; 4533 bbox.y = position.y; 4534 position.x = x2; 4535 position.y = y2; 4536 position = position.matrixTransform(matrix); 4537 bbox.width = position.x - bbox.x; 4538 bbox.height = position.y - bbox.y; 4539 return bbox; 4540 } 4541 changed() { 4542 return JSON.stringify(this.getOptions()) != this.initialState; 4543 } 4544 edit() { 4545 this.elemOriginal = $$7(this.element).clone()[0]; 4546 } 4547 editCommit() { 4548 this.elemOriginal = null; 4549 } 4550 editCancel() { 4551 this.mapsvg.containers.svg.appendChild(this.elemOriginal); 4552 this.element = this.elemOriginal; 4553 this.elemOriginal = null; 4554 } 4555 getOptions(forTemplate) { 4556 let o; 4557 o = { 4558 id: this.id, 4559 id_no_spaces: this.id_no_spaces, 4560 title: this.title, 4561 fill: this.mapsvg.options.regions[this.id] && this.mapsvg.options.regions[this.id].fill, 4562 data: this.data, 4563 choroplethValue: this.choroplethValue, 4564 }; 4565 if (forTemplate) { 4566 o.disabled = this.disabled; 4567 } 4568 for (const key in o) {
4569 if (typeof o[key] === "undefined") { 4570 delete o[key]; 4571 } 4572 } 4573 if (this.customAttrs) { 4574 const that = this; 4575 this.customAttrs.forEach(function (attr) { 4576 o[attr] = that[attr]; 4577 }); 4578 } 4579 return o; 4580 } 4581 forTemplate() { 4582 const data = { 4583 id: this.id, 4584 title: this.title, 4585 objects: this.objects, 4586 data: this.data, 4587 }; 4588 if (this.data) { 4589 for (const key in this.data) { 4590 if (key != "title" && key != "id") 4591 data[key] = this.data[key]; 4592 } 4593 } 4594 return data; 4595 } 4596 getData() { 4597 return this.forTemplate(); 4598 } 4599 update(options) { 4600 for (const key in options) { 4601 const setter = "set" + MapSVG.ucfirst(key); 4602 if (setter in this) 4603 this[setter](options[key]); 4604 else { 4605 this[key] = options[key]; 4606 this.customAttrs = this.customAttrs || []; 4607 this.customAttrs.push(key); 4608 } 4609 } 4610 } 4611 setTitle(title) { 4612 if (title) { 4613 this.title = title; 4614 } 4615 this.element.setAttribute("title", this.title); 4616 } 4617 setStyle(style) { 4618 $$7.extend(true, this.style, style); 4619 this.setFill(); 4620 } 4621 getChoroplethColor() { 4622 const o = this.mapsvg.options.choropleth; 4623 let color = ""; 4624 if (this.data && 4625 (this.data[this.mapsvg.options.regionChoroplethField] || 4626 this.data[this.mapsvg.options.regionChoroplethField] === 0)) { 4627 const w = o.maxAdjusted === 0 4628 ? 0 4629 : (parseFloat(this.data[this.mapsvg.options.regionChoroplethField]) - o.min) / 4630 o.maxAdjusted; 4631 const c = { 4632 r: Math.round(o.colors.diffRGB.r * w + o.colors.lowRGB.r), 4633 g: Math.round(o.colors.diffRGB.g * w + o.colors.lowRGB.g), 4634 b: Math.round(o.colors.diffRGB.b * w + o.colors.lowRGB.b), 4635 a: (o.colors.diffRGB.a * w + o.colors.lowRGB.a).toFixed(2), 4636 }; 4637 color = "rgba(" + c.r + "," + c.g + "," + c.b + "," + c.a + ")"; 4638 } 4639 else { 4640 color = o.colors.noData; 4641 } 4642 return color; 4643 } 4644 _new_getChoroplethColor() { 4645 let regionValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]), color; 4646 if (!regionValue) { 4647 color = this.mapsvg.options.choropleth.coloring.noData.color; 4648 } 4649 else if (this.mapsvg.options.choropleth.coloring.mode === "gradient") { 4650 const gradient = this.mapsvg.options.choropleth.coloring.gradient, w = gradient.values.maxAdjusted === 0 4651 ? 0 4652 : (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); 4653 color = "rgba(" + r + "," + g + "," + b + "," + a + ")"; 4654 } 4655 else { 4656 const paletteColors = this.mapsvg.options.choropleth.coloring.palette.colors; 4657 if (!paletteColors[0].valueFrom && regionValue < paletteColors[0].valueTo) { 4658 color = paletteColors[0].color; 4659 } 4660 else if (!paletteColors[paletteColors.length - 1].valueTo && 4661 regionValue > paletteColors[paletteColors.length - 1].valueFrom) { 4662 color = paletteColors[paletteColors.length - 1].color; 4663 } 4664 else {
4665 paletteColors.forEach(function (paletteColor) { 4666 if (regionValue >= paletteColor.valueFrom && 4667 regionValue < paletteColor.valueTo) { 4668 color = paletteColor.color; 4669 } 4670 }); 4671 color = color 4672 ? color 4673 : this.mapsvg.options.choropleth.coloring.palette.outOfRange.color; 4674 } 4675 } 4676 return color; 4677 } 4678 getBubbleSize() { 4679 let bubbleSize; 4680 if (this.data[this.mapsvg.options.choropleth.sourceField]) { 4681 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]); 4682 bubbleSize = 4683 ((sourceFieldvalue - minSourceFieldvalue) / 4684 (maxSourceFieldvalue - minSourceFieldvalue)) * 4685 (maxBubbleSize - minBubbleSize) + 4686 minBubbleSize; 4687 } 4688 else { 4689 bubbleSize = false; 4690 } 4691 return bubbleSize; 4692 } 4693 setFill(fill) { 4694 if (this.mapsvg.options.colorsIgnore) { 4695 $$7(this.element).css(this.style); 4696 return; 4697 } 4698 if (fill) { 4699 const regions = {}; 4700 regions[this.id] = { fill: fill }; 4701 $$7.extend(true, this.mapsvg.options, { regions: regions }); 4702 } 4703 else if (!fill && 4704 fill !== undefined && 4705 this.mapsvg.options.regions && 4706 this.mapsvg.options.regions[this.id] && 4707 this.mapsvg.options.regions[this.id].fill) { 4708 delete this.mapsvg.options.regions[this.id].fill; 4709 } 4710 if (this.mapsvg.options.choropleth.on) { 4711 this.default_attr["fill"] = this.getChoroplethColor(); 4712 } 4713 else if (this.status !== undefined && 4714 this.mapsvg.regions && 4715 this.mapsvg.regionsRepository.getSchema().getFieldByType("status") && 4716 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict && 4717 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status] && 4718 this.mapsvg.regionsRepository.getSchema().getFieldByType("status").optionsDict[this.status].color) { 4719 this.default_attr["fill"] = this.mapsvg.regionsRepository 4720 .getSchema() 4721 .getFieldByType("status").optionsDict[this.status].color; 4722 } 4723 else if (this.mapsvg.options.regions[this.id] && 4724 this.mapsvg.options.regions[this.id].fill) { 4725 this.default_attr["fill"] = this.mapsvg.options.regions[this.id].fill; 4726 } 4727 else if (this.mapsvg.options.colors.base) { 4728 this.default_attr["fill"] = this.mapsvg.options.colors.base; 4729 } 4730 else if (this.style.fill != "none") { 4731 this.default_attr["fill"] = this.style.fill 4732 ? this.style.fill 4733 : this.mapsvg.options.colors.baseDefault; 4734 } 4735 else { 4736 this.default_attr["fill"] = "none"; 4737 } 4738 if (MapSVG.isNumber(this.mapsvg.options.colors.selected)) 4739 this.selected_attr["fill"] = tinycolor(this.default_attr.fill) 4740 .lighten(parseFloat("" + this.mapsvg.options.colors.selected)) 4741 .toRgbString(); 4742 else 4743 this.selected_attr["fill"] = this.mapsvg.options.colors.selected; 4744 if (MapSVG.isNumber(this.mapsvg.options.colors.hover)) 4745 this.hover_attr["fill"] = tinycolor(this.default_attr.fill) 4746 .lighten(parseFloat("" + this.mapsvg.options.colors.hover)) 4747 .toRgbString(); 4748 else 4749 this.hover_attr["fill"] = this.mapsvg.options.colors.hover; 4750 $$7(this.element).css("fill", this.default_attr["fill"]); 4751 this.fill = this.default_attr["fill"]; 4752 if (this.style.stroke != "none" && this.mapsvg.options.colors.stroke != undefined) { 4753 $$7(this.element).css("stroke", this.mapsvg.options.colors.stroke); 4754 } 4755 else { 4756 const s = this.style.stroke == undefined ? "" : this.style.stroke; 4757 $$7(this.element).css("stroke", s); 4758 } 4759 if (this.selected) 4760 this.setSelected(); 4761 } 4762 setDisabled(on, skipSetFill) { 4763 on = on !== undefined ? MapSVG.parseBoolean(on) : this.getDisabledState(); 4764 const prevDisabled = this.disabled; 4765 this.disabled = on; 4766 this.attr("class", this.attr("class").replace("mapsvg-disabled", "")); 4767 if (on) { 4768 this.attr("class", this.attr("class") + " mapsvg-disabled"); 4769 } 4770 if (this.disabled != prevDisabled) 4771 this.mapsvg.deselectRegion(this); 4772 !skipSetFill && this.setFill(); 4773 } 4774 setStatus(status) { 4775 const statusOptions = this.mapsvg.options.regionStatuses && this.mapsvg.options.regionStatuses[status]; 4776 if (statusOptions) { 4777 this.status = status; 4778 if (this.data) { 4779 this.data.status = status; 4780 this.data.status_text = statusOptions.label; 4781 } 4782 this.setDisabled(statusOptions.disabled, true); 4783 } 4784 else { 4785 this.status = undefined; 4786 if (this.data) { 4787 this.data.status = undefined; 4788 this.data.status_text = undefined; 4789 } 4790 this.setDisabled(false, true); 4791 } 4792 this.setFill(); 4793 } 4794 setSelected() { 4795 this.mapsvg.selectRegion(this); 4796 } 4797 setchoroplethValue(val) { 4798 if ($$7.isNumeric(val)) { 4799 if (typeof val === "string") { 4800 val = parseFloat(val); 4801 } 4802 this.choroplethValue = val; 4803 } 4804 else { 4805 this.choroplethValue = undefined; 4806 } 4807 } 4808 getDisabledState(asDefault) { 4809 const opts = this.mapsvg.options.regions[this.id]; 4810 if (!asDefault && opts && opts.disabled !== undefined) { 4811 return opts.disabled; 4812 } 4813 else { 4814 return (this.mapsvg.options.disableAll || 4815 this.style.fill === "none" || 4816 this.id == "labels" || 4817 this.id == "Labels"); 4818 } 4819 } 4820 highlight() { 4821 $$7(this.element).css({ fill: this.hover_attr.fill }); 4822 $$7(this.element).addClass("mapsvg-region-hover"); 4823 } 4824 unhighlight() { 4825 $$7(this.element).css({ fill: this.default_attr.fill }); 4826 $$7(this.element).removeClass("mapsvg-region-hover"); 4827 } 4828 select() { 4829 $$7(this.element).css({ fill: this.selected_attr.fill }); 4830 this.selected = true; 4831 $$7(this.element).addClass("mapsvg-region-active"); 4832 } 4833 deselect() { 4834 $$7(this.element).css({ fill: this.default_attr.fill }); 4835 this.selected = false;
4836 $$7(this.element).removeClass("mapsvg-region-active"); 4837 } 4838 setData(data) { 4839 this.data = data; 4840 if (typeof data.title !== "undefined") { 4841 this.setTitle(data.title); 4842 } 4843 } 4844 drawBubble() { 4845 if (this.data) { 4846 const bubbleId = "mapsvg-bubble-" + this.id; 4847 const bubbleValue = parseFloat(this.data[this.mapsvg.options.choropleth.sourceField]); 4848 if (bubbleValue) { 4849 if (!this.center) { 4850 this.center = this.getCenterSVG(); 4851 } 4852 const pos = this.mapsvg.converter.convertSVGToPixel(this.center); 4853 if (!this.bubble) { 4854 this.bubble = $$7('<div id="' + 4855 bubbleId + 4856 '" class="mapsvg-bubble mapsvg-region-bubble"></div>')[0]; 4857 $$7(this.mapsvg.layers.bubbles).append(this.bubble); 4858 } 4859 const color = this.getChoroplethColor(); 4860 const bubbleSize = Number(this.getBubbleSize()); 4861 $$7(this.bubble) 4862 .css("transform", "translate(-50%,-50%) translate(" + pos.x + "px," + pos.y + "px)") 4863 .css("background-color", color) 4864 .css("width", bubbleSize + "px") 4865 .css("height", bubbleSize + "px") 4866 .css("lineHeight", bubbleSize - 2 + "px"); 4867 } 4868 else { 4869 delete this.bubble; 4870 } 4871 } 4872 } 4873 adjustLabelScreenPosition() { 4874 if (this.label) { 4875 if (!this.center) { 4876 this.center = this.getCenterSVG(); 4877 } 4878 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.label.offsetWidth / 2, y = pos.y - this.label.offsetHeight / 2; 4879 this.setLabelScreenPosition(x, y); 4880 } 4881 } 4882 adjustBubbleScreenPosition() { 4883 if (this.bubble) { 4884 if (!this.center) { 4885 this.center = this.getCenterSVG(); 4886 } 4887 const pos = this.mapsvg.converter.convertSVGToPixel(this.center), x = pos.x - this.bubble.offsetWidth / 2, y = pos.y - this.bubble.offsetHeight / 2; 4888 this.setBubbleScreenPosition(x, y); 4889 } 4890 } 4891 moveLabelScreenPositionBy(deltaX, deltaY) { 4892 if (this.label) { 4893 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; 4894 this.setLabelScreenPosition(x, y); 4895 } 4896 } 4897 moveBubbleScreenPositionBy(deltaX, deltaY) { 4898 if (this.bubble) { 4899 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; 4900 this.setBubbleScreenPosition(x, y); 4901 } 4902 } 4903 setLabelScreenPosition(x, y) { 4904 if (this.label) { 4905 this.label.style.transform = "translate(" + x + "px," + y + "px)"; 4906 } 4907 } 4908 setBubbleScreenPosition(x, y) { 4909 if (this.bubble) { 4910 this.bubble.style.transform = "translate(" + x + "px," + y + "px)"; 4911 } 4912 } 4913 } 4914 4915 class SchemaRepository extends Repository { 4916 constructor() { 4917 const objectName = "schema"; 4918 super(objectName, +objectName + "s"); 4919 this.className = "Schema"; 4920 this.objectNameSingle = objectName; 4921 this.objectNameMany = objectName + "s"; 4922 this.path = objectName + "s/"; 4923 this.events = new Events(this); 4924 } 4925 create(schema) { 4926 const defer = jQuery.Deferred(); 4927 defer.promise(); 4928 const data = {}; 4929 data[this.objectNameSingle] = this.encodeData(schema); 4930 this.server 4931 .post(this.path, data) 4932 .done((response) => { 4933 const data = this.decodeData(response); 4934 schema.id = data[this.objectNameSingle].id; 4935 this.objects.push(schema); 4936 this.events.trigger("created"); 4937 schema.events.trigger("created"); 4938 defer.resolve(schema); 4939 }) 4940 .fail(() => { 4941 defer.reject(); 4942 }); 4943 return defer; 4944 } 4945 update(schema) { 4946 const defer = jQuery.Deferred(); 4947 defer.promise(); 4948 const data = {}; 4949 data[this.objectNameSingle] = this.encodeData(schema); 4950 this.server 4951 .put(this.path + schema.id, data) 4952 .done((response) => { 4953 const data = this.decodeData(response); 4954 this.objects.push(schema); 4955 defer.resolve(schema); 4956 this.events.trigger("changed"); 4957 schema.events.trigger("changed"); 4958 }) 4959 .fail(() => { 4960 defer.reject(); 4961 }); 4962 return defer; 4963 } 4964 encodeData(schema) { 4965 const _schema = schema.getData(); 4966 let fieldsJsonString = JSON.stringify(_schema); 4967 fieldsJsonString = fieldsJsonString.replace(/select/g, "!mapsvg-encoded-slct"); 4968 fieldsJsonString = fieldsJsonString.replace(/table/g, "!mapsvg-encoded-tbl"); 4969 fieldsJsonString = fieldsJsonString.replace(/database/g, "!mapsvg-encoded-db"); 4970 fieldsJsonString = fieldsJsonString.replace(/varchar/g, "!mapsvg-encoded-vc"); 4971 fieldsJsonString = fieldsJsonString.replace(/int\(11\)/g, "!mapsvg-encoded-int"); 4972 const back = JSON.parse(fieldsJsonString); 4973 back.fields = JSON.stringify(_schema.fields); 4974 return back; 4975 } 4976 } 4977 4978 const $$8 = jQuery; 4979 class Controller { 4980 constructor(options) { 4981 this.containers = { 4982 main: options.container, 4983 }; 4984 this.mapsvg = options.mapsvg; 4985 this.template = options.template || ""; 4986 this.scrollable = options.scrollable === undefined ? true : options.scrollable; 4987 this.withToolbar = options.withToolbar === undefined ? true : options.withToolbar; 4988 this.autoresize = MapSVG.parseBoolean(options.autoresize); 4989 this.templates = { 4990 toolbar: Handlebars.compile(this.getToolbarTemplate()), 4991 main: Handlebars.compile(this.getMainTemplate()), 4992 }; 4993 this.data = options.data; 4994 this.width = options.width; 4995 this.color = options.color; 4996 this.events = new Events(this); 4997 if (options.events) { 4998 for (const eventName in options.events) { 4999 if (typeof options.events[eventName] === "function") { 5000 this.events.on(eventName, options.events[eventName]); 5001 } 5002 } 5003 } 5004 } 5005 viewDidLoad() { 5006 const _this = this; 5007 _this.updateScroll(); 5008 if (this.autoresize) { 5009 _this.adjustHeight(); 5010 this.resizeSensor.setScroll(); 5011 } 5012 } 5013 _viewDidLoad() { 5014 this.updateScroll(); 5015 } 5016 viewDidAppear() { } 5017 viewDidDisappear() { } 5018 updateScroll() { 5019 if (!this.scrollable) 5020 return; 5021 const _this = this; 5022 $$8(this.containers.contentWrap).nanoScroller({ 5023 preventPageScrolling: true, 5024 }); 5025 setTimeout(function () { 5026 $$8(_this.containers.contentWrap).nanoScroller({ 5027 preventPageScrolling: true, 5028 }); 5029 }, 300); 5030 } 5031 adjustHeight() { 5032 const _this = this; 5033 $$8(_this.containers.main).height($$8(_this.containers.main).find(".mapsvg-auto-height").outerHeight() + 5034 (_this.containers.toolbar ? $$8(_this.containers.toolbar).outerHeight() : 0)); 5035 } 5036 _init() { 5037 const _this = this; 5038 _this.render(); 5039 _this.init(); 5040 } 5041 init() { } 5042 getToolbarTemplate() { 5043 return ""; 5044 } 5045 setMainTemplate(template) { 5046 return (this.templates.main = Handlebars.compile(template)); 5047 } 5048 getMainTemplate() { 5049 return this.template; 5050 } 5051 render() { 5052 const _this = this; 5053 this.containers.view = $$8("<div />") 5054 .attr("id", "mapsvg-controller-" + this.name) 5055 .addClass("mapsvg-controller-view")[0]; 5056 this.containers.contentWrap = $$8("<div />").addClass("mapsvg-controller-view-wrap")[0]; 5057 this.containers.contentWrap2 = $$8("<div />")[0]; 5058 this.containers.sizer = $$8("<div />").addClass("mapsvg-auto-height")[0]; 5059 this.containers.contentView = $$8("<div />").addClass("mapsvg-controller-view-content")[0]; 5060 this.containers.sizer.appendChild(this.containers.contentView); 5061 if (this.scrollable) { 5062 $$8(this.containers.contentWrap).addClass("nano"); 5063 $$8(this.containers.contentWrap2).addClass("nano-content"); 5064 } 5065 this.containers.contentWrap.appendChild(this.containers.contentWrap2); 5066 this.containers.contentWrap2.appendChild(this.containers.sizer); 5067 if (this.withToolbar && this.templates.toolbar) { 5068 this.containers.toolbar = $$8("<div />").addClass("mapsvg-controller-view-toolbar")[0]; 5069 this.containers.view.appendChild(this.containers.toolbar); 5070 } 5071 this.containers.view.append(this.containers.contentWrap); 5072 this.containers.main.appendChild(this.containers.view);
5073 $$8(this.containers.main).data("controller", this); 5074 if (this.width) 5075 this.containers.view.style.width = this.width; 5076 if (this.color) 5077 this.containers.view.style["background-color"] = this.color; 5078 _this.viewReadyToFill(); 5079 this.redraw(); 5080 setTimeout(function () { 5081 _this._viewDidLoad(); 5082 _this.viewDidLoad(); 5083 _this.setEventHandlersCommon(); 5084 _this.setEventHandlers(); 5085 }, 1); 5086 } 5087 viewReadyToFill() { 5088 const _this = this; 5089 if (_this.autoresize) { 5090 _this.resizeSensor = new ResizeSensor(this.containers.sizer, () => { 5091 _this.adjustHeight(); 5092 _this.updateScroll(); 5093 _this.events.trigger("resize", this, [this]); 5094 }); 5095 } 5096 } 5097 redraw(data) { 5098 if (data !== undefined) { 5099 this.data = data; 5100 } 5101 try { 5102 $$8(this.containers.contentView).html(this.templates.main(this.data)); 5103 } 5104 catch (err) { 5105 console.error(err); 5106 $$8(this.containers.contentView).html(""); 5107 } 5108 if (this.withToolbar && this.templates.toolbar) 5109 $$8(this.containers.toolbar).html(this.templates.toolbar(this.data)); 5110 this.updateTopShift(); 5111 if (this.noPadding) 5112 this.containers.contentView.style.padding = "0"; 5113 this.updateScroll(); 5114 } 5115 updateTopShift() { 5116 const _this = this; 5117 if (!this.withToolbar) 5118 return; 5119 $$8(_this.containers.contentWrap).css({ 5120 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5121 }); 5122 setTimeout(function () { 5123 $$8(_this.containers.contentWrap).css({ 5124 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5125 }); 5126 }, 100); 5127 setTimeout(function () { 5128 $$8(_this.containers.contentWrap).css({ 5129 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5130 }); 5131 }, 200); 5132 setTimeout(function () { 5133 $$8(_this.containers.contentWrap).css({ 5134 top: $$8(_this.containers.toolbar).outerHeight(true) + "px", 5135 }); 5136 _this.updateScroll(); 5137 }, 500); 5138 } 5139 setEventHandlersCommon() { } 5140 setEventHandlers() { } 5141 destroy() { 5142 delete this.resizeSensor; 5143 $$8(this.containers.view).empty().remove(); 5144 } 5145 } 5146 5147 const $$9 = jQuery; 5148 class DirectoryController extends Controller { 5149 constructor(options) { 5150 super(options); 5151 this.repository = options.repository; 5152 this.noPadding = true; 5153 this.position = options.position; 5154 this.search = options.search; 5155 } 5156 getToolbarTemplate() { 5157 let t = '<div class="mapsvg-directory-search-wrap">'; 5158 t += '<div class="mapsvg-directory-filter-wrap filter-wrap"></div>'; 5159 t += "</div>"; 5160 t += "</div>"; 5161 return t; 5162 } 5163 viewDidLoad() { 5164 const _this = this; 5165 this.menuBtn = $$9('<div class="mapsvg-button-menu"><i class="mapsvg-icon-menu"></i> ' + 5166 this.mapsvg.options.mobileView.labelList + 5167 "</div>")[0]; 5168 this.mapBtn = $$9('<div class="mapsvg-button-map"><i class="mapsvg-icon-map"></i> ' + 5169 this.mapsvg.options.mobileView.labelMap + 5170 "</div>")[0]; 5171 if (MapSVG.isPhone && _this.mapsvg.options.menu.hideOnMobile) { 5172 if (this.mapsvg.options.menu.showFirst == "map") { 5173 this.toggle(false); 5174 } 5175 else { 5176 this.toggle(true); 5177 } 5178 } 5179 this.mobileButtons = $$9('<div class="mapsvg-mobile-buttons"></div>')[0]; 5180 this.mobileButtons.append(this.menuBtn, this.mapBtn); 5181 if (this.mapsvg.options.menu.on !== false) { 5182 this.mapsvg.containers.wrapAll.appendChild(this.mobileButtons); 5183 } 5184 this.events.trigger("shown", this.containers.view); 5185 } 5186 setEventHandlers() { 5187 const _this = this; 5188 $$9(window).on("resize", function () { 5189 _this.updateTopShift(); 5190 }); 5191 $$9(this.menuBtn).on("click", function () { 5192 _this.toggle(true); 5193 }); 5194 $$9(this.mapBtn).on("click", function () { 5195 _this.toggle(false); 5196 _this.mapsvg.redraw(); 5197 }); 5198 $$9(this.containers.view) 5199 .on("click.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5200 if (e.target.nodeName == "A") { 5201 return; 5202 } 5203 const objID = $$9(this).data("object-id"); 5204 let regions; 5205 let marker; 5206 let detailsViewObject; 5207 let eventObject; 5208 _this.deselectItems(); 5209 _this.selectItems(objID, false); 5210 if (MapSVG.isPhone && _this.mapsvg.options.menu.showMapOnClick) { 5211 _this.toggle(false); 5212 } 5213 if (_this.mapsvg.options.menu.source == "regions") { 5214 regions = [_this.mapsvg.getRegion(objID)]; 5215 eventObject = regions[0]; 5216 detailsViewObject = regions[0]; 5217 } 5218 else { 5219 detailsViewObject = _this.repository.getLoadedObject(objID); 5220 eventObject = detailsViewObject; 5221 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5222 if (_regions) { 5223 regions = _regions 5224 .map(function (region) { 5225 return _this.mapsvg.getRegion(region.id); 5226 }) 5227 .filter(function (r) { 5228 return r !== undefined; 5229 }); 5230 } 5231 } 5232 if (detailsViewObject.location && detailsViewObject.location.marker) 5233 marker = detailsViewObject.location.marker; 5234 if (_this.mapsvg.options.actions.directoryItem.click.showDetail
5234s) { 5235 _this.mapsvg.loadDetailsView(detailsViewObject); 5236 } 5237 if (regions && regions.length > 0) { 5238 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 5239 _this.mapsvg.zoomTo(regions, _this.mapsvg.options.actions.directoryItem.click.zoomToLevel); 5240 } 5241 if (regions.length > 1) { 5242 _this.mapsvg.setMultiSelect(true); 5243 } 5244 regions.forEach(function (region) { 5245 const center = region.getCenter(); 5246 e.clientX = center[0]; 5247 e.clientY = center[1]; 5248 if (_this.mapsvg.options.actions.directoryItem.click.selectRegion) { 5249 _this.mapsvg.selectRegion(region, true); 5250 } 5251 if (_this.mapsvg.options.actions.directoryItem.click.showRegionPopover) { 5252 if (_this.mapsvg.options.actions.directoryItem.click.zoom) { 5253 setTimeout(function () { 5254 _this.mapsvg.showPopover(region); 5255 }, 500); 5256 } 5257 else { 5258 _this.mapsvg.showPopover(region); 5259 } 5260 } 5261 if (_this.mapsvg.options.actions.directoryItem.click.fireRegionOnClick) { 5262 _this.mapsvg.events.trigger("click.region", region, [region]); 5263 } 5264 }); 5265 if (regions.length > 1) { 5266 _this.mapsvg.setMultiSelect(false, false); 5267 } 5268 } 5269 if (marker) { 5270 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5271 _this.mapsvg.zoomTo(marker, _this.mapsvg.options.actions.directoryItem.click.zoomToMarkerLevel); 5272 } 5273 if (_this.mapsvg.options.actions.directoryItem.click.showMarkerPopover) { 5274 if (_this.mapsvg.options.actions.directoryItem.click.zoomToMarker) { 5275 setTimeout(function () { 5276 _this.mapsvg.showPopover(detailsViewObject); 5277 }, 500); 5278 } 5279 else { 5280 _this.mapsvg.showPopover(detailsViewObject); 5281 } 5282 } 5283 if (_this.mapsvg.options.actions.directoryItem.click.fireMarkerOnClick) { 5284 _this.mapsvg.events.trigger("click.marker", marker, [e, _this.mapsvg]); 5285 } 5286 _this.mapsvg.selectMarker(marker); 5287 } 5288 _this.events.trigger("click", this, [e, eventObject, _this.mapsvg]); 5289 const actions = _this.mapsvg.options.actions; 5290 if (actions.directoryItem.click.goToLink) { 5291 const linkParts = actions.directoryItem.click.linkField.split("."); 5292 let url; 5293 if (linkParts.length > 1) { 5294 const obj = linkParts.shift(); 5295 const attr = "." + linkParts.join("."); 5296 if (obj == "Region") { 5297 if (regions[0] && regions[0].data) 5298 url = eval("regions[0].data" + attr); 5299 } 5300 else { 5301 if (detailsViewObject) 5302 url = eval("detailsViewObject" + attr); 5303 } 5304 if (url) { 5305 if (actions.directoryItem.click.newTab) { 5306 const win = window.open(url, "_blank"); 5307 win.focus(); 5308 } 5309 else { 5310 window.location.href = url; 5311 } 5312 } 5313 } 5314 } 5315 if (actions.directoryItem.click.showAnotherMap) { 5316 if (_this.mapsvg.editMode) { 5317 alert('"Show another map" action is disabled in the preview'); 5318 return true; 5319 } 5320 const linkParts2 = actions.directoryItem.click.showAnotherMapField.split("."); 5321 if (linkParts2.length > 1) { 5322 const obj2 = linkParts2.shift(); 5323 const attr2 = "." + linkParts2.join("."); 5324 let map_id; 5325 if (obj2 == "Region") { 5326 if (regions[0] && regions[0].data) 5327 map_id = eval("regions[0].data" + attr2); 5328 } 5329 else { 5330 if (detailsViewObject) 5331 map_id = eval("detailsViewObject" + attr2); 5332 } 5333 if (map_id) { 5334 const container = actions.directoryItem.click.showAnotherMapContainerId 5335 ? $$9("#" + actions.directoryItem.click.showAnotherMapContainerId)[0] 5336 : $$9(_this.mapsvg.containers.map)[0]; 5337 _this.mapsvg.loadMap(map_id, container); 5338 } 5339 } 5340 } 5341 }) 5342 .on("mouseover.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5343 const objID = $$9(this).data("object-id"); 5344 let regions; 5345 let detailsViewObject; 5346 let eventObject; 5347 let marker; 5348 if (_this.mapsvg.options.menu.source == "regions") { 5349 regions = [_this.mapsvg.getRegion(objID)]; 5350 eventObject = regions[0]; 5351 detailsViewObject = regions[0]; 5352 } 5353 else { 5354 detailsViewObject = _this.repository.getLoadedObject(objID); 5355 eventObject = detailsViewObject; 5356 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5357 if (_regions) { 5358 regions = _regions.map(function (region) { 5359 return _this.mapsvg.getRegion(region.id); 5360 }); 5361 } 5362 if (detailsViewObject.location) { 5363 marker = detailsViewObject.location.marker; 5364 } 5365 } 5366 if (regions && regions.length) { 5367 _this.mapsvg.highlightRegions(regions); 5368 } 5369 if (marker) { 5370 _this.mapsvg.highlightMarker(marker); 5371 if (_this.mapsvg.options.actions.directoryItem.hover.centerOnMarker) { 5372 _this.mapsvg.centerOn(marker); 5373 } 5374 } 5375 _this.events.trigger("mouseover", $$9(this), [e, eventObject, _this.mapsvg]); 5376 }) 5377 .on("mouseout.menu.mapsvg", ".mapsvg-directory-item", function (e) { 5378 const objID = $$9(this).data("object-id"); 5379 let regions; 5380 let detailsViewObject; 5381 let eventObject; 5382 let marker; 5383 if (_this.mapsvg.options.menu.source == "regions") { 5384 regions = [_this.mapsvg.getRegion(objID)]; 5385 eventObject = regions[0]; 5386 detailsViewObject = regions[0]; 5387 } 5388 else { 5389 detailsViewObject = _this.repository.getLoadedObject(objID); 5390 eventObject = detailsViewObject; 5391 const _regions = detailsViewObject.getRegions(_this.mapsvg.regionsRepository.schema.name); 5392 if (_regions) { 5393 regions = _regions.map(function (region) { 5394 return _this.mapsvg.getRegion(region.id); 5395 }); 5396 } 5397 if (detailsViewObject.location) { 5398 marker = detailsViewObject.location.marker; 5399 } 5400 } 5401 if (regions && regions.length) { 5402 _this.mapsvg.unhighlightRegions(); 5403 } 5404 if (marker) { 5405 _this.mapsvg.unhighlightMarker(); 5406 } 5407 _this.events.trigger("mouseout", $$9(this), [e, eventObject, _this.mapsvg]); 5408 }); 5409 $$9(this.containers.contentView).on("click", ".mapsvg-category-item", function () { 5410 const panel = $$9(this).next(".mapsvg-category-block"); 5411 if (panel[0].style.maxHeight || panel.hasClass("active")) { 5412 panel[0].style.maxHeight = null; 5413 } 5414 else { 5415 panel[0].style.maxHeight = panel[0].scrollHeight + "px"; 5416 } 5417 if ($$9(this).hasClass("active")) { 5418 $$9(this).toggleClass("active", false); 5419 $$9(this).next(".mapsvg-category-block").addClass("collapsed").removeClass("active"); 5420 } 5421 else { 5422 if (_this.mapsvg.options.menu.categories.collapseOther) { 5423 $$9(this).parent().find(".mapsvg-category-item.active").removeClass("active"); 5424 $$9(this) 5425 .parent() 5426 .find(".mapsvg-category-block.active") 5427 .removeClass("active") 5428 .addClass("collapsed"); 5429 } 5430 $$9(this).toggleClass("active", true); 5431 $$9(this).next(".mapsvg-category-block").removeClass("collapsed").addClass("active"); 5432 } 5433 const panels = $$9(".mapsvg-category-block.collapsed"); 5434 panels.each(function (i, panel) { 5435 panel.style.maxHeight = null; 5436 }); 5437 }); 5438 } 5439 highlightItems(ids) { 5440 const _this = this; 5441 if (typeof ids != "object") 5442 ids = [ids]; 5443 ids.forEach(function (id) { 5444 $$9(_this.containers.view) 5445 .find("#mapsvg-directory-item-" + _this.convertId(id)
5445) 5446 .addClass("hover"); 5447 }); 5448 } 5449 unhighlightItems() { 5450 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("hover"); 5451 } 5452 selectItems(ids, scrollTo = true) { 5453 if (typeof ids != "object") 5454 ids = [ids]; 5455 ids.forEach((id) => { 5456 $$9(this.containers.view) 5457 .find("#mapsvg-directory-item-" + this.convertId(id)) 5458 .addClass("selected"); 5459 }); 5460 if (scrollTo && $$9("#mapsvg-directory-item-" + ids[0]).length > 0) { 5461 this.scrollable && 5462 $$9(this.containers.contentWrap).nanoScroller({ 5463 scrollTo: $$9(this.containers.view).find("#mapsvg-directory-item-" + this.convertId(ids[0])), 5464 }); 5465 } 5466 } 5467 deselectItems() { 5468 $$9(this.containers.view).find(".mapsvg-directory-item").removeClass("selected"); 5469 } 5470 removeItems(ids) { 5471 $$9(this.containers.view) 5472 .find("#mapsvg-directory-item-" + this.convertId(ids)) 5473 .remove(); 5474 } 5475 filterOut(items) { 5476 const _this = this; 5477 if (this.repository.path.indexOf("regions") !== -1) { 5478 let f; 5479 f = { 5480 field: "", 5481 val: "", 5482 }; 5483 if (_this.mapsvg.options.menu.filterout.field) { 5484 f.field = _this.mapsvg.options.menu.filterout.field; 5485 f.val = _this.mapsvg.options.menu.filterout.val; 5486 } 5487 items = items.filter(function (item) { 5488 let ok = true; 5489 const status = _this.mapsvg.options.regionStatuses; 5490 if (status[item.status]) { 5491 ok = !status[item.status].disabled; 5492 } 5493 if (ok && f.field) { 5494 ok = item[f.field] != f.val; 5495 } 5496 return ok; 5497 }); 5498 } 5499 return items; 5500 } 5501 loadItemsToDirectory() { 5502 let items = []; 5503 const _this = this; 5504 if (!_this.repository.loaded) 5505 return false; 5506 if (_this.mapsvg.options.menu.categories && 5507 _this.mapsvg.options.menu.categories.on && 5508 _this.mapsvg.options.menu.categories.groupBy) { 5509 const categoryField = _this.mapsvg.options.menu.categories.groupBy; 5510 if (_this.repository.getSchema().getField(categoryField) === undefined || 5511 _this.repository.getSchema().getField(categoryField).options === undefined) { 5512 return false; 5513 } 5514 const categories = _this.repository.getSchema().getField(categoryField).options; 5515 categories.forEach(function (category) { 5516 let dbItems = _this.repository.getLoaded(); 5517 dbItems = _this.filterOut(dbItems); 5518 const itemArr = []; 5519 dbItems.forEach((item) => { 5520 itemArr.push(item); 5521 }); 5522 const catItems = itemArr.filter(function (object) { 5523 if (categoryField === "regions") { 5524 const objectRegions = typeof object[categoryField] !== "undefined" && 5525 object[categoryField].length 5526 ? object[categoryField] 5527 : []; 5528 const objectRegionIDs = objectRegions.map(function (region) { 5529 return region.id; 5530 }); 5531 return objectRegionIDs.indexOf(category.id) !== -1; 5532 } 5533 else { 5534 return object[categoryField] == category.value; 5535 } 5536 }); 5537 category.counter = catItems.length; 5538 if (categoryField === "regions") { 5539 category.label = category.title; 5540 category.value = category.id; 5541 } 5542 catItems.sort(function (a, b) { 5543 const field = _this.mapsvg.options.menu.sortBy; 5544 return a[field] == b[field] 5545 ? 0 5546 : (_this.mapsvg.options.menu.sortDirection === "asc" 5547 ? +(a[field] > [field]) 5548 : +(a[field] < [field])) || -1; 5549 }); 5550 items.push({ category: category, items: catItems }); 5551 }); 5552 if (_this.mapsvg.options.menu.categories.hideEmpty) { 5553 items = items.filter(function (item) { 5554 return item.category.counter > 0; 5555 }); 5556 } 5557 } 5558 else { 5559 if (_this.mapsvg.options.menu.source === "regions") { 5560 items = _this.repository.getLoaded().map((r) => { 5561 const data = r.getData(); 5562 data.objects = _this.mapsvg.getRegion(data.id).objects; 5563 data.id_no_spaces = data.id.split(" ").join("_"); 5564 return data; 5565 }); 5566 items = _this.filterOut(items); 5567 } 5568 else { 5569 items = _this.repository 5570 .getLoaded() 5571 .map((r) => r.getData(_this.mapsvg.regionsRepository.schema.name)); 5572 } 5573 } 5574 try { 5575 $$9(this.containers.contentView).html(this.templates.main({ items: items })); 5576 } 5577 catch (err) { 5578 console.error('MapSVG: Error in the "Directory item" template'); 5579 console.error(err); 5580 } 5581 if (items.length === 0) { 5582 $$9(this.containers.contentView).html('<div class="mapsvg-no-results">' + 5583 this.mapsvg.options.menu.noResultsText + 5584 "</div>"); 5585 } 5586 if (_this.mapsvg.options.menu.categories.on) { 5587 if (_this.mapsvg.options.menu.categories.collapse && items.length > 1) { 5588 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("collapsed"); 5589 } 5590 else if (_this.mapsvg.options.menu.categories.collapse && items.length === 1) { 5591 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5592 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5593 const panel = $$9(this.containers.contentView).find(".mapsvg-category-block")[0]; 5594 if (panel) 5595 panel.style.maxHeight = panel.scrollHeight + "px"; 5596 } 5597 else if (!_this.mapsvg.options.menu.categories.collapse) { 5598 $$9(this.containers.contentView).find(".mapsvg-category-item").addClass("active"); 5599 $$9(this.containers.contentView).find(".mapsvg-category-block").addClass("active"); 5600 const panels = $$9(this.containers.contentView).find(".mapsvg-category-block"); 5601 if (panels.length) 5602 panels.each(function (i, panel) { 5603 panel.style.maxHeight = panel.scrollHeight + "px"; 5604 }); 5605 } 5606 } 5607 this.updateTopShift(); 5608 this.updateScroll(); 5609 } 5610 toggle(on) { 5611 const _this = this; 5612 if (on) { 5613 $$9(this.containers.main).parent().show(); 5614 $$9(_this.mapsvg.containers.mapContainer).hide(); 5615 $$9(this.menuBtn).addClass("active"); 5616 $$9(this.mapBtn).removeClass("active"); 5617 } 5618 else { 5619 $$9(this.containers.main).parent().hide(); 5620 $$9(_this.mapsvg.containers.mapContainer).show(); 5621 $$9(this.menuBtn).removeClass("active"); 5622 $$9(this.mapBtn).addClass("active"); 5623 } 5624 if (!$$9(this.containers.main).parent().is(":visible")) { 5625 if (MapSVG.isPhone) { 5626 $$9(_this.mapsvg.containers.wrap).css("height", "auto"); 5627 _this.updateScroll(); 5628 } 5629 } 5630 else { 5631 if (MapSVG.isPhone && 5632 $$9(this.containers.main).height() < parseInt(this.mapsvg.options.menu.minHeight)) { 5633 $$9(_this.mapsvg.containers.wrap).css("height", parseInt(this.mapsvg.options.menu.minHeight) + "px"); 5634 _this.updateScroll(); 5635 } 5636 } 5637 this.updateTopShift(); 5638 } 5639 addPagination(pager) { 5640 $$9(this.containers.contentView).append('<div class="mapsvg-pagination-container"></div>'); 5641 $$9(this.containers.contentView).find(".mapsvg-pagination-container").html(pager); 5642 } 5643 convertId(id) { 5644 return (id + "") 5645 .split(" ") 5646 .join("_") 5647 .replace(/(:|\(|\)|\.|\[|\]|,|=|@)/g, "\\$1"); 5648 } 5649 } 5650 5651 const $$a = jQuery; 5652 class DetailsController extends Controller { 5653 constructor(options) { 5654 super(options); 5655 this.modal = options.modal; 5656 } 5657 getToolbarTemplate() { 5658 if (this.withToolbar) 5659 return '<div class="mapsvg-popover-close mapsvg-details-close"></div>'; 5660 else 5661 return ""; 5662 } 5663 viewDidLoad() { 5664 const _this = this; 5665 this.events.trigger("shown", _this, [_this]); 5666 if (this.modal &&
5667 MapSVG.isPhone && 5668 this.mapsvg.options.detailsView.mobileFullscreen && 5669 !this.mobileCloseBtn) { 5670 this.mobileCloseBtn = $$a('<button class="mapsvg-mobile-modal-close">' + 5671 _this.mapsvg.options.mobileView.labelClose + 5672 "</button>")[0]; 5673 this.containers.view.appendChild(this.mobileCloseBtn); 5674 } 5675 } 5676 setEventHandlers() { 5677 const _this = this; 5678 $$a(this.containers.toolbar).on("click touchend", ".mapsvg-popover-close", function (e) { 5679 e.stopPropagation(); 5680 _this.destroy(); 5681 _this.events.trigger("closed", _this, [_this]); 5682 }); 5683 $$a(this.containers.view).on("click touchend", ".mapsvg-mobile-modal-close", function (e) { 5684 e.stopPropagation(); 5685 _this.destroy(); 5686 _this.events.trigger("closed", _this, [_this]); 5687 }); 5688 } 5689 } 5690 5691 const $$b = jQuery; 5692 class FormElement { 5693 constructor(options, formBuilder, external) { 5694 this.readonly = typeof options.readonly !== "undefined" ? options.readonly : false; 5695 this.protected = typeof options.protected !== "undefined" ? options.protected : false; 5696 this.auto_increment = 5697 typeof options.auto_increment !== "undefined" ? options.auto_increment : false; 5698 this.not_null = typeof options.not_null !== "undefined" ? options.not_null : false; 5699 this.searchable = typeof options.searchable !== "undefined" ? options.searchable : false; 5700 this.visible = typeof options.visible !== "undefined" ? options.visible : true; 5701 this.formBuilder = formBuilder; 5702 this.events = new Events(this); 5703 this.type = options.type; 5704 this.value = options.value; 5705 this.db_type = options.db_type || "varchar(255)"; 5706 this.label = this.label || (options.label === undefined ? "Label" : options.label); 5707 this.name = this.name || options.name || "label"; 5708 this.help = options.help || ""; 5709 this.placeholder = options.placeholder; 5710 this.setExternal(external); 5711 let t = this.type; 5712 if (t === "marker" && this.mapIsGeo) { 5713 t = "marker-geo"; 5714 } 5715 if (t === "location" && this.mapIsGeo) { 5716 t = "location-geo"; 5717 } 5718 if (this.filtersMode) { 5719 this.parameterName = options.parameterName || ""; 5720 this.parameterNameShort = this.parameterName.split(".")[1]; 5721 this.name = this.parameterNameShort; 5722 this.placeholder = options.placeholder || ""; 5723 this.templates = { 5724 main: Handlebars.compile($$b("#mapsvg-filters-tmpl-" + t + "-view").html()), 5725 }; 5726 } 5727 else { 5728 this.templates = { 5729 main: Handlebars.compile($$b("#mapsvg-data-tmpl-" + t + "-view").html()), 5730 }; 5731 } 5732 this.inputs = {}; 5733 } 5734 init() { 5735 this.setDomElements(); 5736 this.setEventHandlers(); 5737 } 5738 setDomElements() { 5739 this.domElements = { 5740 main: $$b(this.templates.main(this.getDataForTemplate()))[0], 5741 }; 5742 $$b(this.domElements.main).data("formElement", this); 5743 this.addSelect2(); 5744 } 5745 setEventHandlers() { 5746 const _this = this; 5747 if (this.formBuilder.editMode) { 5748 $$b(this.domElements.main).on("click", function () { 5749 _this.events.trigger("click", _this, [_this]); 5750 }); 5751 } 5752 } 5753 addSelect2() { 5754 if ($$b().mselect2) { 5755 $$b(this.domElements.main) 5756 .find("select") 5757 .css({ width: "100%", display: "block" }) 5758 .mselect2() 5759 .on("select2:focus", function () { 5760 $$b(this).mselect2("open"); 5761 }); 5762 $$b(this.domElements.main) 5763 .find(".select2-selection--multiple .select2-search__field") 5764 .css("width", "100%"); 5765 } 5766 } 5767 setEditorEventHandlers() { 5768 const _this = this; 5769 $$b(this.domElements.edit).on("click", "button.mapsvg-remove", function () { 5770 $$b(_this.domElements.main).empty().remove(); 5771 $$b(_this.domElements.edit).empty().remove(); 5772 _this.events.trigger("delete", _this, [_this]); 5773 }); 5774 $$b(this.domElements.edit).on("click", ".mapsvg-filter-insert-options", function () { 5775 const objType = _this.parameterName.split(".")[0]; 5776 const fieldName = _this.parameterName.split(".")[1]; 5777 let field; 5778 if (objType == "Object") { 5779 field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 5780 } 5781 else { 5782 if (fieldName == "id") { 5783 const options = []; 5784 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5785 options.push({ label: r.id, value: r.id }); 5786 }); 5787 field = { 5788 options: options, 5789 }; 5790 } 5791 else if (fieldName === "title") { 5792 const options = []; 5793 _this.formBuilder.mapsvg.regions.forEach(function (r) { 5794 options.push({ label: r.title, value: r.title }); 5795 }); 5796 field = { options: options }; 5797 } 5798 else { 5799 field = _this.formBuilder.mapsvg.regionsRepository 5800 .getSchema() 5801 .getField(fieldName); 5802 } 5803 } 5804 if ((field && field.options) || fieldName === "regions") { 5805 let options; 5806 if (fieldName == "regions") { 5807 const _options = _this.formBuilder.mapsvg.regions.map((r) => { 5808 return { id: r.id, title: r.title }; 5809 }); 5810 _options.sort(function (a, b) { 5811 if (a.title < b.title) 5812 return -1; 5813 if (a.title > b.title) 5814 return 1; 5815 return 0; 5816 }); 5817 options = _options.map(function (o) { 5818 return (o.title || o.id) + ":" + o.id; 5819 }); 5820 } 5821 else { 5822 options = field.options.map(function (o) { 5823 return o.label + ":" + o.value; 5824 }); 5825 } 5826 $$b(this) 5827 .closest(".form-group") 5828 .find("textarea") 5829 .val(options.join("\n")) 5830 .trigger("change"); 5831 } 5832 }); 5833 $$b(this.domElements.edit).on("keyup change paste", "input, textarea, select", function () { 5834 const prop = $$b(this).attr("name"); 5835 const array = $$b(this).data("array"); 5836 if (_this.type === "status" && array) { 5837 const param = $$b(this).data("param"); 5838 const index = $$b(this).closest("tr").index(); 5839 _this.options[index] = _this.options[index] || { 5840 label: "", 5841 value: "", 5842 color: "", 5843 disabled: false, 5844 }; 5845 _this.options[index][param] = $$b(this).is(":checkbox") 5846 ? $$b(this).prop("checked") 5847 : $$b(this).val(); 5848 _this.redraw(); 5849 } 5850 else if (_this.type === "distance" && array) { 5851 const param = $$b(this).data("param"); 5852 const index = $$b(this).closest("tr").index(); 5853 if (!_this.options[index]) { 5854 _this.options[index] = { value: "", default: false }; 5855 } 5856 if (param === "default") { 5857 _this.options.forEach(function (option) { 5858 option.default = false;
5859 }); 5860 _this.options[index].default = $$b(this).prop("checked"); 5861 } 5862 else { 5863 _this.options[index].value = $$b(this).val(); 5864 } 5865 _this.redraw(); 5866 } 5867 else if (prop == "label" || prop == "name") { 5868 return false; 5869 } 5870 else { 5871 let value; 5872 value = 5873 $$b(this).attr("type") == "checkbox" ? $$b(this).prop("checked") : $$b(this).val(); 5874 if ($$b(this).attr("type") == "radio") { 5875 const name = $$b(this).attr("name"); 5876 value = $$b('input[name="' + name + '"]:checked').val(); 5877 } 5878 _this.update(prop, value); 5879 } 5880 }); 5881 $$b(this.domElements.edit).on("keyup change paste", 'input[name="label"]', function () { 5882 if (!_this.nameChanged) { 5883 _this.label = $$b(this).val() + ""; 5884 if (_this.type != "region" && _this.type != "location" && _this.type != "title") { 5885 let str = $$b(this).val() + ""; 5886 str = str.toLowerCase().replace(/ /g, "_").replace(/\W/g, ""); 5887 if (str.length < 64) { 5888 $$b(_this.domElements.edit).find('input[name="name"]').val(str); 5889 } 5890 _this.name = str + ""; 5891 } 5892 $$b(_this.domElements.main).find("label").first().html(_this.label); 5893 if (!_this.filtersMode) { 5894 $$b(_this.domElements.main) 5895 .find("label") 5896 .first() 5897 .append('<div class="field-name">' + _this.name + "</div>"); 5898 } 5899 } 5900 }); 5901 $$b(this.domElements.edit).on("keyup change paste", 'input[name="name"]', function (e) { 5902 if (e.target.value) { 5903 if (e.target.value.match(/[^a-zA-Z0-9_]/g)) { 5904 e.target.value = e.target.value.replace(/[^a-zA-Z0-9_]/g, ""); 5905 $$b(e.target).trigger("change"); 5906 } 5907 if (e.target.value[0].match(/[^a-zA-Z_]/g)) { 5908 e.target.value = 5909 e.target.value[0].replace(/[^a-zA-Z_]/g, "") + e.target.value.slice(1); 5910 $$b(e.target).trigger("change"); 5911 } 5912 } 5913 if (_this.type != "region") 5914 _this.name = e.target.value; 5915 $$b(_this.domElements.main) 5916 .find("label") 5917 .html(_this.label + '<div class="field-name">' + _this.name + "</div>"); 5918 _this.nameChanged = true; 5919 }); 5920 $$b(this.domElements.edit).on("keyup change paste", 'textarea[name="help"]', function (e) { 5921 $$b(_this.domElements.main).find(".form-text").text(e.target.value); 5922 }); 5923 } 5924 getEditor() { 5925 if (!this.filtersMode) { 5926 this.templates.edit = 5927 this.templates.edit || 5928 Handlebars.compile($$b("#mapsvg-data-tmpl-" + this.type + "-control").html()); 5929 } 5930 else { 5931 this.templates.edit = 5932 this.templates.edit || 5933 Handlebars.compile($$b("#mapsvg-filters-tmpl-" + this.type + "-control").html()); 5934 } 5935 this.domElements.edit = $$b("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>")[0]; 5936 return this.domElements.edit; 5937 } 5938 destroyEditor() { 5939 $$b(this.domElements.edit).empty().remove(); 5940 } 5941 initEditor() { 5942 $$b(this.domElements.edit).find("input").first().select(); 5943 if ($$b().colorpicker) { 5944 $$b(this.domElements.edit) 5945 .find(".cpicker") 5946 .colorpicker() 5947 .on("changeColor.colorpicker", function (event) { 5948 const input = $$b(this).find("input"); 5949 if (input.val() == "") 5950 $$b(this).find("i").css({ "background-color": "" }); 5951 }); 5952 } 5953 if ($$b().mselect2) {
5954 if (this.type !== "distance") { 5955 $$b(this.domElements.edit) 5956 .find("select") 5957 .css({ width: "100%", display: "block" }) 5958 .mselect2(); 5959 } 5960 } 5961 this.setEditorEventHandlers(); 5962 } 5963 getSchema() { 5964 let data; 5965 data = { 5966 type: this.type, 5967 db_type: this.db_type, 5968 label: this.label, 5969 name: this.name, 5970 value: this.value, 5971 searchable: this.searchable, 5972 help: this.help, 5973 visible: this.visible === undefined ? true : this.visible, 5974 readonly: this.readonly, 5975 placeholder: this.placeholder, 5976 protected: this.protected, 5977 auto_increment: this.auto_increment, 5978 not_null: this.not_null, 5979 }; 5980 if (this.options) { 5981 data.options = this.getSchemaFieldOptionsList(); 5982 } 5983 if (this.filtersMode) { 5984 data.parameterName = this.parameterName; 5985 data.parameterNameShort = this.parameterName.split(".")[1]; 5986 } 5987 return data; 5988 } 5989 getSchemaFieldOptionsList() { 5990 const options = []; 5991 this.options.forEach((option, index) => { 5992 if (this.options[index].value !== "") { 5993 options.push(this.options[index]); 5994 } 5995 }); 5996 return options; 5997 } 5998 getDataForTemplate() { 5999 const data = this.getSchema(); 6000 data._name = data.name; 6001 if (this.namespace) { 6002 data.name = this.name.split("[")[0]; 6003 let suffix = this.name.split("[")[1] || ""; 6004 if (suffix) 6005 suffix = "[" + suffix; 6006 data.name = this.namespace + "[" + data.name + "]" + suffix; 6007 } 6008 data.external = this.external; 6009 return data; 6010 } 6011 update(prop, value) { 6012 const _this = this; 6013 if (prop == "options") { 6014 const options = []; 6015 value = value.split("\n").forEach(function (row) { 6016 row = row.trim().split(":"); 6017 if (_this.type == "checkbox" && row.length == 3) { 6018 options.push({ 6019 label: row[0], 6020 name: row[1], 6021 value: row[2], 6022 }); 6023 } 6024 else if ((_this.type == "radio" || 6025 _this.type == "select" || 6026 _this.type == "checkboxes") && 6027 row.length == 2) { 6028 options.push({ 6029 label: row[0], 6030 value: row[1], 6031 }); 6032 } 6033 }); 6034 this.options = options; 6035 } 6036 else { 6037 this[prop] = value; 6038 } 6039 if (prop == "parameterName") { 6040 $$b(this.domElements.edit).find(".mapsvg-filter-param-name").text(value); 6041 } 6042 } 6043 redraw() { 6044 const newView = $$b(this.templates.main(this.getDataForTemplate())); 6045 $$b(this.domElements.main).html(newView.html()); 6046 if ($$b().mselect2) { 6047 if (this.type !== "distance") { 6048 $$b(this.domElements.main) 6049 .find("select") 6050 .css({ width: "100%", display: "block" }) 6051 .mselect2() 6052 .on("select2:focus", function () { 6053 $$b(this).mselect2("open"); 6054 }); 6055 } 6056 else { 6057 $$b(this.domElements.main) 6058 .find("select") 6059 .mselect2() 6060 .on("select2:focus", function () { 6061 $$b(this).mselect2("open"); 6062 }); 6063 } 6064 } 6065 } 6066 redrawEditor() { 6067 if (this.domElements.edit) { 6068 $$b(this.domElements.edit).empty(); 6069 $$b(this.domElements.edit).html("<div>" + this.templates.edit(this.getDataForTemplate()) + "</div>"); 6070 this.initEditor(); 6071 } 6072 } 6073 setOptions(options) { 6074 if (options) { 6075 this.options = []; 6076 this.optionsDict = {}; 6077 options.forEach((value, key) => { 6078 this.options.push(value); 6079 this.optionsDict[key] = value; 6080 }); 6081 return this.options; 6082 } 6083 else { 6084 return this.setOptions([ 6085 { label: "Option one", name: "option_one", value: 1 }, 6086 { label: "Option two", name: "option_two", value: 2 }, 6087 ]); 6088 } 6089 } 6090 getData() { 6091 return { name: this.name, value: this.getValue() }; 6092 } 6093 destroy() { 6094 if ($$b().mselect2) { 6095 const sel = $$b(this.domElements.main).find(".mapsvg-select2"); 6096 if (sel.length) { 6097 sel.mselect2("destroy"); 6098 } 6099 } 6100 } 6101 show() { 6102 $$b(this.domElements.main).show(); 6103 } 6104 hide() { 6105 $$b(this.domElements.main).hide(); 6106 } 6107 setExternal(params) { 6108 this.external = params; 6109 if (typeof this.external.mapIsGeo !== "undefined") { 6110 this.mapIsGeo = this.external.mapIsGeo; 6111 } 6112 if (typeof this.external.editMode !== "undefined") { 6113 this.editMode = this.external.editMode; 6114 } 6115 if (typeof this.external.filtersMode !== "undefined") { 6116 this.filtersMode = this.external.filtersMode; 6117 } 6118 if (typeof this.external.namespace !== "undefined") { 6119 this.namespace = this.external.namespace; 6120 } 6121 } 6122 getValue() { 6123 return this.value; 6124 } 6125 setValue(value, updateInput = true) { 6126 this.value = value; 6127 if (updateInput) { 6128 this.setInputValue(value); 6129 } 6130 } 6131 setInputValue(value) { 6132 return; 6133 } 6134 triggerChanged() { 6135 this.events.trigger("changed", this, [this]); 6136 } 6137 } 6138 6139 const $$c = jQuery; 6140 class CheckboxFormElement extends FormElement { 6141 constructor(options, formBuilder, external) { 6142 super(options, formBuilder, external); 6143 if (typeof options.showAsSwitch === "undefined") { 6144 this.showAsSwitch = true; 6145 } 6146 else { 6147 this.showAsSwitch = options.showAsSwitch; 6148 } 6149 this.db_type = "tinyint(1)"; 6150 this.checkboxLabel = options.checkboxLabel; 6151 this.checkboxValue = options.checkboxValue; 6152 } 6153 setDomElements() { 6154 super.setDomElements(); 6155 this.inputs.checkbox = $$c(this.domElements.main).find("input")[0]; 6156 this.inputs.switch = $$c(this.domElements.main).find("input")[0]; 6157 } 6158 setEventHandlers() { 6159 super.setEventHandlers(); 6160 $$c(this.inputs.checkbox).on("change", (e) => { 6161 this.setValue(e.target.checked, false); 6162 this.triggerChanged(); 6163 }); 6164 } 6165 setEditorEventHandlers() { 6166 super.setEditorEventHandlers(); 6167 $$c(this.domElements.edit).on("change", "[name='showAsSwitch']", (e) => { 6168 if (this.showAsSwitch) { 6169 $$c(this.domElements.main) 6170 .find("[name='checkboxToSwitch']") 6171 .addClass("form-switch form-switch-md"); 6172 } 6173 if (!this.showAsSwitch) { 6174 $$c(this.domElements.main) 6175 .find("[name='checkboxToSwitch']") 6176 .removeClass("form-switch form-switch-md"); 6177 } 6178 }); 6179 $$c(this.domElements.edit).on("keyup change paste", '[name="checkboxLabel"]',
6179(e) => { 6180 $$c(this.domElements.main).find(".form-check-label").text(e.target.value); 6181 }); 6182 } 6183 getSchema() { 6184 const schema = super.getSchema(); 6185 if (this.checkboxLabel) { 6186 schema.checkboxLabel = this.checkboxLabel; 6187 } 6188 if (this.checkboxValue) { 6189 schema.checkboxValue = this.checkboxValue; 6190 } 6191 schema.showAsSwitch = this.showAsSwitch; 6192 return schema; 6193 } 6194 setInputValue(value) { 6195 this.inputs.checkbox.checked = value === true; 6196 } 6197 } 6198 6199 const $$d = jQuery; 6200 class CheckboxesFormElement extends FormElement { 6201 constructor(options, formBuilder, external) { 6202 super(options, formBuilder, external); 6203 this.db_type = "text"; 6204 this.checkboxLabel = options.checkboxLabel; 6205 this.setOptions(options.options); 6206 } 6207 setDomElements() { 6208 super.setDomElements(); 6209 this.$checkboxes = $$d(this.domElements.main).find('input[type="checkbox"]'); 6210 this.setInputValue(this.value || []); 6211 } 6212 setEventHandlers() { 6213 super.setEventHandlers(); 6214 this.$checkboxes.on("change", (e) => { 6215 const values = []; 6216 $$d(this.domElements.main) 6217 .find("input:checked") 6218 .each((i, el) => { 6219 values.push(jQuery(el).attr("value")); 6220 }); 6221 this.setValue(values, false); 6222 this.triggerChanged(); 6223 }); 6224 } 6225 setInputValue(values) { 6226 if (values === null) { 6227 $$d(this.domElements.main).find(`input`).prop("checked", false); 6228 } 6229 else { 6230 values.forEach((value) => { 6231 $$d(this.domElements.main).find(`input[value="${value}"]`).prop("checked", true); 6232 }); 6233 } 6234 } 6235 } 6236 6237 const $$e = jQuery; 6238 class DateFormElement extends FormElement { 6239 constructor(options, formBuilder, external) { 6240 super(options, formBuilder, external); 6241 if (this.formBuilder.admin) { 6242 this.languages = [ 6243 "en-GB", 6244 "ar", 6245 "az", 6246 "bg", 6247 "bs", 6248 "ca", 6249 "cs", 6250 "cy", 6251 "da", 6252 "de", 6253 "el", 6254 "es", 6255 "et", 6256 "eu", 6257 "fa", 6258 "fi", 6259 "fo", 6260 "fr", 6261 "gl", 6262 "he", 6263 "hr", 6264 "hu", 6265 "hy", 6266 "id", 6267 "is", 6268 "it", 6269 "ja", 6270 "ka", 6271 "kh", 6272 "kk", 6273 "kr", 6274 "lt", 6275 "lv", 6276 "mk", 6277 "ms", 6278 "nb", 6279 "nl", 6280 "nl-BE", 6281 "no", 6282 "pl", 6283 "pt-BR", 6284 "pt", 6285 "ro", 6286 "rs", 6287 "rs-latin", 6288 "ru", 6289 "sk", 6290 "sl", 6291 "sq", 6292 "sr", 6293 "sr-latin", 6294 "sv", 6295 "sw", 6296 "th", 6297 "tr", 6298 "uk", 6299 "vi", 6300 "zh-CN", 6301 "zh-TW", 6302 ]; 6303 } 6304 this.db_type = "varchar(50)"; 6305 this.language = options.language; 6306 } 6307 setDomElements() { 6308 super.setDomElements(); 6309 this.inputs.date = $$e(this.domElements.main).find("input")[0]; 6310 } 6311 setEventHandlers() { 6312 super.setEventHandlers(); 6313 $$e(this.inputs.date).on("change", (e) => { 6314 this.setValue(e.target.value, false); 6315 this.triggerChanged(); 6316 }); 6317 } 6318 getSchema() { 6319 const schema = super.getSchema(); 6320 schema.language = this.language; 6321 return schema; 6322 } 6323 getDataForTemplate() { 6324 const data = super.getDataForTemplate(); 6325 if (this.formBuilder.admin) 6326 data.languages = this.languages; 6327 data.language = this.language; 6328 return data; 6329 } 6330 } 6331 6332 const $$f = jQuery; 6333 class DistanceFormElement extends FormElement { 6334 constructor(options, formBuilder, external) { 6335 super(options, formBuilder, external); 6336 this.name = "distance"; 6337 this.label = this.label || (options.label === undefined ? "Search radius" : options.label); 6338 this.distanceControl = options.distanceControl || "select"; 6339 this.distanceUnits = options.distanceUnits || "km"; 6340 this.distanceUnitsLabel = options.distanceUnitsLabel || "km"; 6341 this.fromLabel = options.fromLabel || "from"; 6342 this.placeholder = options.placeholder; 6343 this.userLocationButton = options.userLocationButton || false; 6344 this.type = options.type; 6345 this.addressField = options.addressField || true; 6346 this.addressFieldPlaceholder = options.addressFieldPlaceholder || "Address"; 6347 this.languages = [ 6348 { value: "sq", label: "Albanian" }, 6349 { value: "ar", label: "Arabic" }, 6350 { 6351 value: "eu", 6352 label: "Basque", 6353 }, 6354 { value: "be", label: "Belarusian" }, 6355 { value: "bg", label: "Bulgarian" }, 6356 { 6357 value: "my", 6358 label: "Burmese", 6359 }, 6360 { value: "bn", label: "Bengali" }, 6361 { value: "ca", label: "Catalan" }, 6362 { 6363 value: "zh-cn", 6364 label: "Chinese (simplified)", 6365 }, 6366 { value: "zh-tw", label: "Chinese (traditional)" }, 6367 { 6368 value: "hr", 6369 label: "Croatian", 6370 }, 6371 { value: "cs", label: "Czech" }, 6372 { value: "da", label: "Danish" }, 6373 { 6374 value: "nl", 6375 label: "Dutch", 6376 }, 6377 { value: "en", label: "English" }, 6378 { 6379 value: "en-au", 6380 label: "English (australian)", 6381 }, 6382 { value: "en-gb", label: "English (great Britain)" }, 6383 { 6384 value: "fa", 6385 label: "Farsi", 6386 }, 6387 { value: "fi", label: "Finnish" }, 6388 { value: "fil", label: "Filipino" }, 6389 { 6390 value: "fr", 6391 label: "French", 6392 }, 6393 { value: "gl", label: "Galician" }, 6394 { value: "de", label: "German" }, 6395 { 6396 value: "el", 6397 label: "Greek", 6398 }, 6399 { value: "gu", label: "Gujarati" }, 6400 { value: "iw", label: "Hebrew" }, 6401 { 6402 value: "hi", 6403 label: "Hindi", 6404 }, 6405 { value: "hu", label: "Hungarian" }, 6406 { value: "id", label: "Indonesian" }, 6407 { 6408 value: "it", 6409 label: "Italian", 6410 }, 6411 { value: "ja", label: "Japanese" }, 6412 { value: "kn", label: "Kannada" }, 6413 { 6414 value: "kk", 6415 label: "Kazakh", 6416 }, 6417 { value: "ko", label: "Korean" }, 6418 { value: "ky", label: "Kyrgyz" }, 6419 { 6420 value: "lt", 6421 label: "Lithuanian", 6422 }, 6423 { value: "lv", label: "Latvian" }, 6424 { value: "mk", label: "Macedonian" }, 6425 { 6426 value: "ml", 6427 label: "Malayalam", 6428 }, 6429 { value: "mr", label: "Marathi" },
6430 { value: "no", label: "Norwegian" }, 6431 { 6432 value: "pl", 6433 label: "Polish", 6434 }, 6435 { value: "pt", label: "Portuguese" }, 6436 { 6437 value: "pt-br", 6438 label: "Portuguese (brazil)", 6439 }, 6440 { value: "pt-pt", label: "Portuguese (portugal)" }, 6441 { 6442 value: "pa", 6443 label: "Punjabi", 6444 }, 6445 { value: "ro", label: "Romanian" }, 6446 { value: "ru", label: "Russian" }, 6447 { 6448 value: "sr", 6449 label: "Serbian", 6450 }, 6451 { value: "sk", label: "Slovak" }, 6452 { value: "sl", label: "Slovenian" }, 6453 { 6454 value: "es", 6455 label: "Spanish", 6456 }, 6457 { value: "sv", label: "Swedish" }, 6458 { value: "tl", label: "Tagalog" }, 6459 { 6460 value: "ta", 6461 label: "Tamil", 6462 }, 6463 { value: "te", label: "Telugu" }, 6464 { value: "th", label: "Thai" }, 6465 { 6466 value: "tr", 6467 label: "Turkish", 6468 }, 6469 { value: "uk", label: "Ukrainian" }, 6470 { value: "uz", label: "Uzbek" }, 6471 { 6472 value: "vi", 6473 label: "Vietnamese", 6474 }, 6475 ]; 6476 this.countries = MapSVG.countries; 6477 this.country = options.country; 6478 this.language = options.language; 6479 this.searchByZip = options.searchByZip; 6480 this.zipLength = parseInt(options.zipLength) || 5; 6481 this.userLocationButton = MapSVG.parseBoolean(options.userLocationButton); 6482 this.options = options.options || [ 6483 { value: "10", default: true }, 6484 { value: "30", default: false }, 6485 { value: "50", default: false }, 6486 { value: "100", default: false }, 6487 ]; 6488 let defOption; 6489 if (this.value) { 6490 this.options.forEach((option) => { 6491 if (option.value === this.value.length) { 6492 defOption = option; 6493 } 6494 }); 6495 } 6496 if (!defOption) { 6497 defOption = this.options.find(function (option) { 6498 return option.default === true; 6499 }); 6500 } 6501 if (!defOption) { 6502 defOption = this.options[0]; 6503 } 6504 const defLengthOption = this.options.find((opt) => opt.selected === true); 6505 this.defaultLength = defOption.value; 6506 this.setDefaultValue(); 6507 } 6508 setDefaultValue() { 6509 this.value = { 6510 units: this.distanceUnits, 6511 geoPoint: { lat: null, lng: null }, 6512 length: this.defaultLength, 6513 address: "", 6514 country: this.country, 6515 }; 6516 } 6517 setDomElements() { 6518 super.setDomElements(); 6519 this.inputs.units = ($$f(this.domElements.main).find('[name="distanceUnits"]')[0]); 6520 this.inputs.geoPoint = ($$f(this.domElements.main).find('[name="distanceGeoPoint"]')[0]); 6521 this.inputs.length = ($$f(this.domElements.main).find('[name="distanceLength"]')[0]); 6522 this.inputs.address = ($$f(this.domElements.main).find('[name="distance"]')[0]); 6523 } 6524 getSchema() { 6525 const schema = super.getSchema(); 6526 schema.distanceControl = this.distanceControl; 6527 schema.distanceUnits = this.distanceUnits; 6528 schema.distanceUnitsLabel = this.distanceUnitsLabel; 6529 schema.fromLabel = this.fromLabel; 6530 schema.addressField = this.addressField; 6531 schema.addressFieldPlaceholder = this.addressFieldPlaceholder; 6532 schema.userLocationButton = this.userLocationButton; 6533 schema.placeholder = this.placeholder; 6534 schema.language = this.language; 6535 schema.country = this.country; 6536 schema.searchByZip = this.searchByZip; 6537 schema.zipLength = parseInt(this.zipLength + ""); 6538 schema.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6539 if (schema.distanceControl === "none") { 6540 schema.distanceDefault = schema.options.filter(function (o) { 6541 return o.default; 6542 })[0].value; 6543 } 6544 schema.options.forEach(function (option, index) { 6545 if (schema.options[index].value === "") { 6546 schema.options.splice(index, 1); 6547 } 6548 else { 6549 schema.options[index].default = MapSVG.parseBoolean(schema.options[index].default); 6550 } 6551 }); 6552 return schema; 6553 } 6554 getDataForTemplate() { 6555 const data = super.getDataForTemplate(); 6556 if (this.formBuilder.admin) { 6557 data.languages = this.languages; 6558 data.countries = this.countries; 6559 } 6560 data.language = this.language; 6561 data.country = this.country; 6562 data.searchByZip = this.searchByZip; 6563 data.zipLength = this.zipLength; 6564 data.userLocationButton = MapSVG.parseBoolean(this.userLocationButton); 6565 return data; 6566 } 6567 destroy() { 6568 if ($$f().mselect2) { 6569 const sel = $$f(this.domElements.main).find(".mapsvg-select2"); 6570 if (sel.length) { 6571 sel.mselect2("destroy"); 6572 } 6573 } 6574 } 6575 initEditor() { 6576 super.initEditor(); 6577 this.mayBeAddDistanceRow(); 6578 if ($$f().mselect2) { 6579 $$f(this.domElements.edit).find("select").mselect2(); 6580 } 6581 } 6582 setEventHandlers() { 6583 super.setEventHandlers(); 6584 const _this = this; 6585 $$f(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-distance-row input", function () { 6586 _this.mayBeAddDistanceRow(); 6587 }); 6588 const server = new Server(); 6589 const locations = new Bloodhound({ 6590 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 6591 queryTokenizer: Bloodhound.tokenizers.whitespace, 6592 remote: { 6593 url: server.getUrl("geocoding") + 6594 "?address=" + 6595 (this.searchByZip === true ? "zip%20" : "") + 6596 "%QUERY%&language=" + 6597 this.language + 6598 (this.country ? "&country=" + this.country : ""), 6599 wildcard: "%QUERY%", 6600 transform: function (response) { 6601 if (response.error_message) { 6602 alert(response.error_message); 6603 } 6604 return response.results; 6605 }, 6606 rateLimitWait: 600, 6607 }, 6608 }); 6609 const thContainer = $$f(this.domElements.main).find(".typeahead"); 6610 this.spinner = $$f("<span class='spinner-border spinner-border-sm'></span>")[0]; 6611 if (this.searchByZip) { 6612 $$f(this.domElements.main).find(".mapsvg-distance-fields").addClass("search-by-zip"); 6613 thContainer.on("change keyup", (e) => { 6614 const zip = $$f(e.target).val().toString(); 6615 if (zip.length === _this.zipLength) { 6616 $$f(this.spinner).appendTo($$f(e.target).closest(".distance-search-wrap")); 6617 this.formBuilder.setIsLoading(true); 6618 locations.search($$f(e.target).val(), (data) => this.handleAddressFieldChange(zip, data), (data) => this.handleAddressFieldChange(zip, data, true)); 6619 } 6620 }); 6621 } 6622 else { 6623 const tH = thContainer 6624 .typeahead({ minLength: 3 }, { 6625 name: "mapsvg-addresses", 6626 display: "formatted_address", 6627 limit: 5, 6628 async: true, 6629 source: (query, sync, async) => { 6630 const request = { address: query }; 6631 if (this.country) { 6632 request.componentRestrictions = { country: this.country }; 6633 } 6634 MapSVG.geocode(request, async); 6635 }, 6636 }) 6637 .on("typeahead:asyncrequest", (e) => { 6638 $$f(this.spinner).appendTo($$f(e.target).closest(".twitter-typeahead")); 6639 this.formBuilder.setIsLoading(true); 6640 }) 6641 .on("typeahead:asynccancel typeahead:asyncreceive", (e) => { 6642 $$f(this.spinner).remove(); 6643 this.formBuilder.setIsLoading(false); 6644 }); 6645 $$f(this.domElements.main).find(".mapsvg-distance-fields").removeClass("search-by-zip"); 6646 } 6647 if (_this.userLocationButton) { 6648 const userLocationButton = $$f(this.domElements.main).find(".user-location-button"); 6649 userLocationButton.on("click", () => { 6650 _this.formBuilder.mapsvg.showUserLocation((location) => { 6651 locations.search(location.geoPoint.lat + "," + location.geoPoint.lng, (data) => this.setAddressByUserLocation(data, location), (data) => this.setAddressByUserLocation(data, location)); 6652 this.setValue({ geoPoint: location.geoPoint }); 6653 this.triggerChanged(); 6654 }); 6655 }); 6656 } 6657 thContainer.on("change keyup", (e) => { 6658 const input = e.target; 6659 if (input.value === "" && this.getValue() !== null) { 6660 this.setValue(null); 6661 this.triggerChanged(); 6662 } 6663 }); 6664 thContainer.on("typeahead:select", (ev, item) => { 6665 this.setValue({ 6666 address: item.formatted_address, 6667 geoPoint: item.geometry.location.toJSON(), 6668 }); 6669 this.triggerChanged(); 6670 thContainer.blur(); 6671 }); 6672 $$f(this.inputs.geoPoint).on("change", (e) => { 6673 const geoPoint = e.target.value.split(",").map((value) => parseFloat(value)); 6674 this.setValue({ geoPoint: { lat: geoPoint[0], lng: geoPoint[1] } }, false); 6675 this.triggerChanged(); 6676 }); 6677 $$f(this.inputs.length).on("change", (e) => { 6678 this.setLength(parseInt(e.target.value), false); 6679 this.triggerChanged(); 6680 }); 6681 } 6682 setAddressByUserLocation(data, location) { 6683 if (data && data[0]) { 6684 this.setAddress(data[0].formatted_address); 6685 } 6686 else { 6687 this.setAddress(location.geoPoint.lat + "," + location.geoPoint.lng); 6688 } 6689 } 6690 handleAddressFieldChange(zip, data, removeSpinner = false) { 6691 if (removeSpinner) { 6692 $$f(this.spinner).remove(); 6693 this.formBuilder.setIsLoading(false); 6694 } 6695 if (data && data[0]) { 6696 this.setValue({ address: zip, geoPoint: data[0].geometry.location }, false); 6697 this.triggerChanged(); 6698 } 6699 } 6700 addSelect2() { 6701 if ($$f().mselect2) { 6702 $$f(this.domElements.main) 6703 .find("select") 6704 .mselect2() 6705 .on("select2:focus", function () { 6706 $$f(this).mselect2("open"); 6707 }); 6708 } 6709 } 6710 mayBeAddDistanceRow() { 6711 const _this = this; 6712 const editDistanceRow = $$f($$f("#mapsvg-edit-distance-row").html()); 6713 const z = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 6714 if (z && z.last() && z.last().val() && z.last().val().toString().trim().length) { 6715 const newRow = editDistanceRow.clone(); 6716 newRow.insertAfter($$f(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 6717 } 6718 const rows = $$f(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 6719 const row1 = rows.eq(rows.length - 2); 6720 const row2 = rows.eq(rows.length - 1); 6721 if (row1.length && 6722 row2.length && 6723 !row1.find("input:eq(0)").val().toString().trim() && 6724 !row2.find("input:eq(0)").val().toString().trim()) { 6725 row2.remove(); 6726 } 6727 } 6728 setValue(value, updateInput = true) { 6729 if (value === null) { 6730 this.setGeoPoint(null); 6731 this.setAddress(""); 6732 } 6733 else { 6734 for (const key in value) { 6735 if (typeof this.value[key] !== undefined) { 6736 const method = "set" + MapSVG.ucfirst(key); 6737 if (typeof this[method] === "function") { 6738 this[method](value[key], updateInput); 6739 } 6740 } 6741 } 6742 } 6743 } 6744 setGeoPoint(geoPoint, updateInput = true) { 6745 this.value.geoPoint = geoPoint === null ? { lat: null, lng: null } : geoPoint; 6746 if (updateInput) { 6747 this.setInputGeoPointValue(geoPoint); 6748 } 6749 } 6750 setInputGeoPointValue(geoPoint) { 6751 this.inputs.geoPoint.value = geoPoint ? geoPoint.lat + "," + geoPoint.lng : ""; 6752 } 6753 setLength(length, updateInput = true) { 6754 this.value.length = parseInt(length.toString()); 6755 this.defaultLength = this.value.length; 6756 if (updateInput) { 6757 this.setInputLengthValue(this.value.length); 6758 } 6759 } 6760 setInputLengthValue(length) { 6761 this.inputs.length.value = length.toString(); 6762 } 6763 setAddress(address, updateInput = true) { 6764 this.value.address = address !== null ? address : ""; 6765 if (updateInput) { 6766 this.setInputAddressValue(this.value.address); 6767 } 6768 } 6769 setInputAddressValue(address) { 6770 this.inputs.address.value = address; 6771 } 6772 getValue() { 6773 return this.value.geoPoint.lat === null ? null : this.value; 6774 } 6775 } 6776 6777 const $$g = jQuery; 6778 class EmptyFormElement extends FormElement { 6779 constructor(options, formBuilder, external) { 6780 super(options, formBuilder, external); 6781 this.readonly = true; 6782 } 6783 } 6784 6785 class IdFormElement extends FormElement { 6786 constructor(options, formBuilder, external) { 6787 super(options, formBuilder, external); 6788 } 6789 getData() { 6790 return { name: "id", value: this.value }; 6791 } 6792 } 6793 6794 function createCommonjsModule(fn, module) { 6795 return module = { exports: {} }, fn(module, module.exports), module.exports; 6796 } 6797 6798 var sortable_min = createCommonjsModule(function (module) { 6799 /**! 6800 * Sortable 6801 * @author RubaXa <[email protected]> 6802 * @license MIT 6803 */ 6804 6805 (function sortableModule(factory) { 6806 6807 { 6808 module.exports = factory(); 6809 } 6810 })(function sortableFactory() { 6811 6812 if (typeof window == "undefined" || !window.document) { 6813 return function sortableError() { 6814 throw new Error("Sortable.js requires a window with a document"); 6815 }; 6816 } 6817 6818 var dragEl, 6819 parentEl, 6820 ghostEl, 6821 cloneEl, 6822 rootEl, 6823 nextEl, 6824 scrollEl, 6825 scrollParentEl, 6826 scrollCustomFn, 6827 lastEl, 6828 lastCSS, 6829 lastParentCSS, 6830 oldIndex, 6831 n
6831ewIndex, 6832 activeGroup, 6833 putSortable, 6834 autoScroll = {}, 6835 tapEvt, 6836 touchEvt, 6837 moved, 6838 /** @const */ 6839 RSPACE = /\s+/g, 6840 expando = "Sortable" + new Date().getTime(), 6841 win = window, 6842 document = win.document, 6843 parseInt = win.parseInt, 6844 $ = win.jQuery || win.Zepto, 6845 Polymer = win.Polymer, 6846 supportDraggable = !!("draggable" in document.createElement("div")), 6847 supportCssPointerEvents = (function (el) { 6848 // false when IE11 6849 if (navigator.userAgent.match(/Trident.*rv[ :]?11\./)) { 6850 return false; 6851 } 6852 el = document.createElement("x"); 6853 el.style.cssText = "pointer-events:auto"; 6854 return el.style.pointerEvents === "auto"; 6855 })(), 6856 _silent = false, 6857 abs = Math.abs, 6858 min = Math.min, 6859 touchDragOverListeners = [], 6860 _autoScroll = _throttle(function ( 6861 /**Event*/ evt, 6862 /**Object*/ options, 6863 /**HTMLElement*/ rootEl 6864 ) { 6865 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 6866 if (rootEl && options.scroll) { 6867 var el, 6868 rect, 6869 sens = options.scrollSensitivity, 6870 speed = options.scrollSpeed, 6871 x = evt.clientX, 6872 y = evt.clientY, 6873 winWidth = window.innerWidth, 6874 winHeight = window.innerHeight, 6875 vx, 6876 vy, 6877 scrollOffsetX, 6878 scrollOffsetY; 6879 6880 // Delect scrollEl 6881 if (scrollParentEl !== rootEl) { 6882 scrollEl = options.scroll; 6883 scrollParentEl = rootEl; 6884 scrollCustomFn = options.scrollFn; 6885 6886 if (scrollEl === true) { 6887 scrollEl = rootEl; 6888 6889 do { 6890 if ( 6891 scrollEl.offsetWidth < scrollEl.scrollWidth || 6892 scrollEl.offsetHeight < scrollEl.scrollHeight 6893 ) { 6894 break; 6895 } 6896 /* jshint boss:true */ 6897 } while ((scrollEl = scrollEl.parentNode)); 6898 } 6899 } 6900 6901 if (scrollEl) { 6902 el = scrollEl; 6903 rect = scrollEl.getBoundingClientRect(); 6904 vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); 6905 vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); 6906 } 6907 6908 if (!(vx || vy)) { 6909 vx = (winWidth - x <= sens) - (x <= sens); 6910 vy = (winHeight - y <= sens) - (y <= sens); 6911 6912 /* jshint expr:true */ 6913 (vx || vy) && (el = win); 6914 } 6915 6916 if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) { 6917 autoScroll.el = el; 6918 autoScroll.vx = vx; 6919 autoScroll.vy = vy; 6920 6921 clearInterval(autoScroll.pid); 6922 6923 if (el) { 6924 autoScroll.pid = setInterval(function () { 6925 scrollOffsetY = vy ? vy * speed : 0; 6926 scrollOffsetX = vx ? vx * speed : 0; 6927 6928 if ("function" === typeof scrollCustomFn) { 6929 return scrollCustomFn.call( 6930 _this, 6931 scrollOffsetX, 6932 scrollOffsetY, 6933 evt 6934 ); 6935 } 6936 6937 if (el === win) { 6938 win.scrollTo( 6939 win.pageXOffset + scrollOffsetX, 6940 win.pageYOffset + scrollOffsetY 6941 ); 6942 } else { 6943 el.scrollTop += scrollOffsetY; 6944 el.scrollLeft += scrollOffsetX; 6945 } 6946 }, 24); 6947 } 6948 } 6949 } 6950 }, 6951 30), 6952 _prepareGroup = function (options) { 6953 function toFn(value, pull) { 6954 if (value === void 0 || value === true) { 6955 value = group.name; 6956 } 6957 6958 if (typeof value === "function") { 6959 return value; 6960 } else { 6961 return function (to, from) { 6962 var fromGroup = from.options.group.name; 6963 6964 return pull 6965 ? value 6966 : value && 6967 (value.join ? value.indexOf(fromGroup) > -1 : fromGroup == value); 6968 }; 6969 } 6970 } 6971 6972 var group = {}; 6973 var originalGroup = options.group; 6974 6975 if (!originalGroup || typeof originalGroup != "object") { 6976 originalGroup = { name: originalGroup }; 6977 } 6978 6979 group.name = originalGroup.name; 6980 group.checkPull = toFn(originalGroup.pull, true); 6981 group.checkPut = toFn(originalGroup.put); 6982 6983 options.group = group; 6984 }; 6985 /** 6986 * @class Sortable 6987 * @param {HTMLElement} el 6988 * @param {Object} [options] 6989 */ 6990 function Sortable(el, options) { 6991 if (!(el && el.nodeType && el.nodeType === 1)) { 6992 throw "Sortable: `el` must be HTMLElement, and not " + {}.toString.call(el); 6993 } 6994 6995 this.el = el; // root element 6996 this.options = options = _extend({}, options); 6997 6998 // Export instance 6999 el[expando] = this; 7000 7001 // Default options 7002 var defaults = { 7003 group: Math.random(), 7004 sort: true, 7005 disabled: false, 7006 store: null, 7007 handle: null, 7008 scroll: true, 7009 scrollSensitivity: 30, 7010 scrollSpeed: 10, 7011 draggable: /[uo]l/i.test(el.nodeName) ? "li" : ">*", 7012 ghostClass: "sortable-ghost", 7013 chosenClass: "sortable-chosen", 7014 dragClass: "sortable-drag", 7015 ignore: "a, img", 7016 filter: null, 7017 animation: 0, 7018 setData: function (dataTransfer, dragEl) { 7019 dataTransfer.setData("Text", dragEl.textContent); 7020 }, 7021 dropBubble: false, 7022 dragoverBubble: false, 7023 dataIdAttr: "data-id", 7024 delay: 0, 7025 forceFallback: false, 7026 fallbackClass: "sortable-fallback", 7027 fallbackOnBody: false, 7028 fallbackTolerance: 0, 7029 fallbackOffset: { x: 0, y: 0 }, 7030 }; 7031 7032 // Set default options 7033 for (var name in defaults) { 7034 !(name in options) && (options[name] = defaults[name]); 7035 } 7036 7037 _prepareGroup(options); 7038 7039 // Bind all private methods 7040 for (var fn in this) { 7041 if (fn.charAt(0) === "_" && typeof this[fn] === "function") { 7042 this[fn] = this[fn].bind(this); 7043 } 7044 } 7045 7046 // Setup drag mode 7047 this.nativeDraggable = options.forceFallback ? false : supportDraggable; 7048 7049 // Bind events 7050 _on(el, "mousedown", this._onTapStart); 7051 _on(el, "touchstart", this._onTapStart); 7052 7053 if (this.nativeDraggable) { 7054 _on(el, "dragover", this); 7055 _on(el, "dragenter", this); 7056 } 7057 7058 touchDragOverListeners.push(this._onDragOver); 7059 7060 // Restore sorting 7061 options.store && this.sort(options.store.get(this)); 7062 } 7063 7064 Sortable.prototype = /** @lends Sortable.prototype */ { 7065 constructor: Sortable, 7066 7067 _onTapStart: function (/** Event|TouchEvent */ evt) { 7068 if (evt.target.tagName == "i" || evt.target.tagName == "I") { 7069 evt.target.click(); 7070 return; 7071 } 7072 var _this = this, 7073 el = this.el, 7074 options = this.options, 7075 type = evt.type, 7076 touch = evt.touches && evt.touches[0], 7077 target = (touch || evt).target, 7078 originalTarget = (evt.target.shadowRoot && evt.path[0]) || target, 7079 filter = options.filter, 7080 startIndex; 7081 7082 // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. 7083 if (dragEl) { 7084 return; 7085 } 7086 7087 if ((type === "mousedown" && evt.button !== 0) || options.disabled) { 7088 return; // only left button or enabled 7089 } 7090 7091 if (options.handle && !_closest(originalTarget, options.handle, el)) { 7092 return; 7093 } 7094 7095 target = _closest(target, options.draggable, el); 7096 7097 if (!target) { 7098 return; 7099 } 7100 7101 // Get the index of the dragged element within its parent 7102 startIndex = _index(target, options.draggable); 7103 7104 // Check filter 7105 if (typeof filter === "function") { 7106 if (filter.call(this, evt, target, this)) { 7107 _dispatchEvent(_this, originalTarget, "filter", target, el, startIndex); 7108 evt.preventDefault(); 7109 return; // cancel dnd 7110 } 7111 } else if (filter) {
7112 filter = filter.split(",").some(function (criteria) { 7113 criteria = _closest(originalTarget, criteria.trim(), el); 7114 7115 if (criteria) { 7116 _dispatchEvent(_this, criteria, "filter", target, el, startIndex); 7117 return true; 7118 } 7119 }); 7120 7121 if (filter) { 7122 evt.preventDefault(); 7123 return; // cancel dnd 7124 } 7125 } 7126 7127 // Prepare `dragstart` 7128 this._prepareDragStart(evt, touch, target, startIndex); 7129 }, 7130 7131 _prepareDragStart: function ( 7132 /** Event */ evt, 7133 /** Touch */ touch, 7134 /** HTMLElement */ target, 7135 /** Number */ startIndex 7136 ) { 7137 var _this = this, 7138 el = _this.el, 7139 options = _this.options, 7140 ownerDocument = el.ownerDocument, 7141 dragStartFn; 7142 7143 if (target && !dragEl && target.parentNode === el) { 7144 tapEvt = evt; 7145 7146 rootEl = el; 7147 dragEl = target; 7148 parentEl = dragEl.parentNode; 7149 nextEl = dragEl.nextSibling; 7150 activeGroup = options.group; 7151 oldIndex = startIndex; 7152 7153 this._lastX = (touch || evt).clientX; 7154 this._lastY = (touch || evt).clientY; 7155 7156 dragEl.style["will-change"] = "transform"; 7157 7158 dragStartFn = function () { 7159 // Delayed drag has been triggered 7160 // we can re-enable the events: touchmove/mousemove 7161 _this._disableDelayedDrag(); 7162 7163 // Make the element draggable 7164 dragEl.draggable = _this.nativeDraggable; 7165 7166 // Chosen item 7167 _toggleClass(dragEl, options.chosenClass, true); 7168 7169 // Bind the events: dragstart/dragend 7170 _this._triggerDragStart(touch); 7171 7172 // Drag start event 7173 _dispatchEvent(_this, rootEl, "choose", dragEl, rootEl, oldIndex); 7174 }; 7175 7176 // Disable "draggable" 7177 options.ignore.split(",").forEach(function (criteria) { 7178 _find(dragEl, criteria.trim(), _disableDraggable); 7179 }); 7180 7181 _on(ownerDocument, "mouseup", _this._onDrop); 7182 _on(ownerDocument, "touchend", _this._onDrop); 7183 _on(ownerDocument, "touchcancel", _this._onDrop); 7184 7185 if (options.delay) { 7186 // If the user moves the pointer or let go the click or touch 7187 // before the delay has been reached: 7188 // disable the delayed drag 7189 _on(ownerDocument, "mouseup", _this._disableDelayedDrag); 7190 _on(ownerDocument, "touchend", _this._disableDelayedDrag); 7191 _on(ownerDocument, "touchcancel", _this._disableDelayedDrag); 7192 _on(ownerDocument, "mousemove", _this._disableDelayedDrag); 7193 _on(ownerDocument, "touchmove", _this._disableDelayedDrag); 7194 7195 _this._dragStartTimer = setTimeout(dragStartFn, options.delay); 7196 } else { 7197 dragStartFn(); 7198 } 7199 } 7200 }, 7201 7202 _disableDelayedDrag: function () { 7203 var ownerDocument = this.el.ownerDocument; 7204 7205 clearTimeout(this._dragStartTimer); 7206 _off(ownerDocument, "mouseup", this._disableDelayedDrag); 7207 _off(ownerDocument, "touchend", this._disableDelayedDrag); 7208 _off(ownerDocument, "touchcancel", this._disableDelayedDrag); 7209 _off(ownerDocument, "mousemove", this._disableDelayedDrag); 7210 _off(ownerDocument, "touchmove", this._disableDelayedDrag); 7211 }, 7212 7213 _triggerDragStart: function (/** Touch */ touch) { 7214 if (touch) { 7215 // Touch device support 7216 tapEvt = { 7217 target: dragEl, 7218 clientX: touch.clientX, 7219 clientY: touch.clientY, 7220 }; 7221 7222 this._onDragStart(tapEvt, "touch"); 7223 } else if (!this.nativeDraggable) { 7224 this._onDragStart(tapEvt, true); 7225 } else { 7226 _on(dragEl, "dragend", this); 7227 _on(rootEl, "dragstart", this._onDragStart); 7228 } 7229 7230 try { 7231 if (document.selection) { 7232 // Timeout neccessary for IE9 7233 setTimeout(function () { 7234 document.selection.empty(); 7235 }); 7236 } else { 7237 window.getSelection().removeAllRanges(); 7238 } 7239 } catch (err) {} 7240 }, 7241 7242 _dragStarted: function () { 7243 if (rootEl && dragEl) { 7244 var options = this.options; 7245 7246 // Apply effect 7247 _toggleClass(dragEl, options.ghostClass, true); 7248 _toggleClass(dragEl, options.dragClass, false); 7249 7250 Sortable.active = this; 7251 7252 // Drag start event 7253 _dispatchEvent(this, rootEl, "start", dragEl, rootEl, oldIndex); 7254 } 7255 }, 7256 7257 _emulateDragOver: function () { 7258 if (touchEvt) { 7259 if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) { 7260 return; 7261 } 7262 7263 this._lastX = touchEvt.clientX; 7264 this._lastY = touchEvt.clientY; 7265 7266 if (!supportCssPointerEvents) { 7267 _css(ghostEl, "display", "none"); 7268 } 7269 7270 var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), 7271 parent = target, 7272 i = touchDragOverListeners.length; 7273 7274 if (parent) { 7275 do { 7276 if (parent[expando]) { 7277 while (i--) { 7278 touchDragOverListeners[i]({ 7279 clientX: touchEvt.clientX, 7280 clientY: touchEvt.clientY, 7281 target: target, 7282 rootEl: parent, 7283 }); 7284 } 7285 7286 break; 7287 } 7288 7289 target = parent; // store last element 7290 } while ( 7291 /* jshint boss:true */ 7292 (parent = parent.parentNode) 7293 ); 7294 } 7295 7296 if (!supportCssPointerEvents) { 7297 _css(ghostEl, "display", ""); 7298 } 7299 } 7300 }, 7301 7302 _onTouchMove: function (/**TouchEvent*/ evt) { 7303 if (tapEvt) { 7304 var options = this.options, 7305 fallbackTolerance = options.fallbackTolerance, 7306 fallbackOffset = options.fallbackOffset, 7307 touch = evt.touches ? evt.touches[0] : evt, 7308 dx = touch.clientX - tapEvt.clientX + fallbackOffset.x, 7309 dy = touch.clientY - tapEvt.clientY + fallbackOffset.
7309y, 7310 translate3d = evt.touches 7311 ? "translate3d(" + dx + "px," + dy + "px,0)" 7312 : "translate(" + dx + "px," + dy + "px)"; 7313 7314 // only set the status to dragging, when we are actually dragging 7315 if (!Sortable.active) { 7316 if ( 7317 fallbackTolerance && 7318 min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < 7319 fallbackTolerance 7320 ) { 7321 return; 7322 } 7323 7324 this._dragStarted(); 7325 } 7326 7327 // as well as creating the ghost element on the document body 7328 this._appendGhost(); 7329 7330 moved = true; 7331 touchEvt = touch; 7332 7333 _css(ghostEl, "webkitTransform", translate3d); 7334 _css(ghostEl, "mozTransform", translate3d); 7335 _css(ghostEl, "msTransform", translate3d); 7336 _css(ghostEl, "transform", translate3d); 7337 7338 evt.preventDefault(); 7339 } 7340 }, 7341 7342 _appendGhost: function () { 7343 if (!ghostEl) { 7344 var rect = dragEl.getBoundingClientRect(), 7345 css = _css(dragEl), 7346 options = this.options, 7347 ghostRect; 7348 7349 ghostEl = dragEl.cloneNode(true); 7350 7351 _toggleClass(ghostEl, options.ghostClass, false); 7352 _toggleClass(ghostEl, options.fallbackClass, true); 7353 _toggleClass(ghostEl, options.dragClass, true); 7354 7355 _css(ghostEl, "top", rect.top - parseInt(css.marginTop, 10)); 7356 _css(ghostEl, "left", rect.left - parseInt(css.marginLeft, 10)); 7357 _css(ghostEl, "width", rect.width); 7358 _css(ghostEl, "height", rect.height); 7359 _css(ghostEl, "opacity", "0.8"); 7360 _css(ghostEl, "position", "fixed"); 7361 _css(ghostEl, "zIndex", "100000"); 7362 _css(ghostEl, "pointerEvents", "none"); 7363 7364 (options.fallbackOnBody && document.body.appendChild(ghostEl)) || 7365 rootEl.appendChild(ghostEl); 7366 7367 // Fixing dimensions. 7368 ghostRect = ghostEl.getBoundingClientRect(); 7369 _css(ghostEl, "width", rect.width * 2 - ghostRect.width); 7370 _css(ghostEl, "height", rect.height * 2 - ghostRect.height); 7371 } 7372 }, 7373 7374 _onDragStart: function (/**Event*/ evt, /**boolean*/ useFallback) { 7375 var dataTransfer = evt.dataTransfer, 7376 options = this.options; 7377 7378 this._offUpEvents(); 7379 7380 if (activeGroup.checkPull(this, this, dragEl, evt) == "clone") { 7381 cloneEl = _clone(dragEl); 7382 _css(cloneEl, "display", "none"); 7383 rootEl.insertBefore(cloneEl, dragEl); 7384 _dispatchEvent(this, rootEl, "clone", dragEl); 7385 } 7386 7387 _toggleClass(dragEl, options.dragClass, true); 7388 7389 if (useFallback) { 7390 if (useFallback === "touch") { 7391 // Bind touch events 7392 _on(document, "touchmove", this._onTouchMove); 7393 _on(document, "touchend", this._onDrop); 7394 _on(document, "touchcancel", this._onDrop); 7395 } else { 7396 // Old brwoser 7397 _on(document, "mousemove", this._onTouchMove); 7398 _on(document, "mouseup", this._onDrop); 7399 } 7400 7401 this._loopId = setInterval(this._emulateDragOver, 50); 7402 } else { 7403 if (dataTransfer) { 7404 dataTransfer.effectAllowed = "move"; 7405 options.setData && options.setData.call(this, dataTransfer, dragEl); 7406 } 7407 7408 _on(document, "drop", this); 7409 setTimeout(this._dragStarted, 0); 7410 } 7411 }, 7412 7413 _onDragOver: function (/**Event*/ evt) { 7414 var el = this.el, 7415 target, 7416 dragRect, 7417 targetRect, 7418 revert, 7419 options = this.options, 7420 group = options.group, 7421 activeSortable = Sortable.active, 7422 isOwner = activeGroup === group, 7423 canSort = options.sort; 7424 7425 if (evt.preventDefault !== void 0) { 7426 evt.preventDefault(); 7427 !options.dragoverBubble && evt.stopPropagation(); 7428 } 7429 7430 moved = true; 7431 7432 if ( 7433 activeGroup && 7434 !options.disabled && 7435 (isOwner 7436 ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list 7437 : putSortable === this || 7438 (activeGroup.checkPull(this, activeSortable, dragEl, evt) && 7439 group.checkPut(this, activeSortable, dragEl, evt))) && 7440 (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback 7441 ) { 7442 // Smart auto-scrolling 7443 _autoScroll(evt, options, this.el); 7444 7445 if (_silent) { 7446 return; 7447 } 7448 7449 target = _closest(evt.target, options.draggable, el); 7450 dragRect = dragEl.getBoundingClientRect(); 7451 putSortable = this; 7452 7453 if (revert) { 7454 _cloneHide(true); 7455 parentEl = rootEl; // actualization 7456 7457 if (cloneEl || nextEl) { 7458 rootEl.insertBefore(dragEl, cloneEl || nextEl); 7459 } else if (!canSort) { 7460 rootEl.appendChild(dragEl); 7461 } 7462 7463 return; 7464 } 7465 7466 if ( 7467 el.children.length === 0 || 7468 el.children[0] === ghostEl || 7469 (el === evt.target && (target = _ghostIsLast(el, evt))) 7470 ) { 7471 if (target) { 7472 if (target.animated) { 7473 return; 7474 } 7475 7476 targetRect = target.getBoundingClientRect(); 7477 } 7478 7479 _cloneHide(isOwner); 7480 7481 if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { 7482 if (!dragEl.contains(el)) { 7483 el.appendChild(dragEl); 7484 parentEl = el; // actualization 7485 } 7486 7487 this._animate(dragRect, dragEl); 7488 target && this._animate(targetRect, target); 7489 } 7490 } else if ( 7491 target && 7492 !target.animated && 7493 target !== dragEl && 7494 target.parentNode[expando] !== void 0 7495 ) { 7496 if (lastEl !== target) { 7497 lastEl = target; 7498 lastCSS = _css(target); 7499 lastParentCSS = _css(target.parentNode); 7500 } 7501 7502 targetRect = target.getBoundingClientRect(); 7503 7504 var width = targetRect.right - targetRect.left, 7505 height = targetRect.bottom - targetRect.top, 7506 floating = 7507 /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display) || 7508 (lastParentCSS.display == "flex" && 7509 lastParentCSS["flex-direction"].indexOf("row") === 0), 7510 isWide = target.offsetWidth > dragEl.offsetWidth, 7511 isLong = target.offsetHeight > dragEl.offsetHeight, 7512 halfway = 7513 (floating 7514 ? (evt.clientX - targetRect.left) / width 7515 : (evt.clientY - targetRect.top) / height) > 0.5, 7516 nextSibling = target.nextElementSibling, 7517 moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt), 7518 after; 7519 7520 if (moveVector !== false) { 7521 _silent = true; 7522 setTimeout(_unsilent, 30); 7523 7524 _cloneHide(isOwner); 7525 7526 if (moveVector === 1 || moveVector === -1) { 7527 after = moveVector === 1; 7528 } else if (floating) { 7529 var elTop = dragEl.offsetTop, 7530 tgTop = target.offsetTop; 7531 7532 if (elTop === tgTop) { 7533 after = 7534 (target.previousElementSibling === dragEl && !isWide) || 7535 (halfway && isWide); 7536 } else if ( 7537 target.previousElementSibling === dragEl || 7538 dragEl.previousElementSibling === target 7539 ) { 7540 after = (evt.clientY - targetRect.top) / height > 0.5; 7541 } else { 7542 after = tgTop > elTop; 7543 } 7544 } else { 7545 after = (nextSibling !== dragEl && !isLong) || (halfway && isLong); 7546 } 7547 7548 if (!dragEl.contains(el)) { 7549 if (after && !nextSibling) { 7550 el.appendChild(dragEl); 7551 } else { 7552 target.parentNode.insertBefore( 7553 dragEl, 7554 after ? nextSibling : target 7555 ); 7556 } 7557 } 7558 7559 parentEl = dragEl.parentNode; // actualization 7560 7561 this._animate(dragRect, dragEl); 7562 this._animate(targetRect, target); 7563 } 7564 } 7565 } 7566 }, 7567 7568 _animate: function (prevRect, target) { 7569 var ms = this.options.animation; 7570 7571 if (ms) { 7572 var currentRect = target.getBoundingClientRect(); 7573 7574 _css(target, "transition", "none"); 7575 _css( 7576 target, 7577 "transform", 7578 "translate3d(" + 7579 (prevRect.left - currentRect.left) + 7580 "px," + 7581 (prevRect.top - currentRect.top) + 7582 "px,0)" 7583 ); 7584 7585 target.offsetWidth; // repaint 7586 7587 _css(target, "transition", "all " + ms + "ms");
7588 _css(target, "transform", "translate3d(0,0,0)"); 7589 7590 clearTimeout(target.animated); 7591 target.animated = setTimeout(function () { 7592 _css(target, "transition", ""); 7593 _css(target, "transform", ""); 7594 target.animated = false; 7595 }, ms); 7596 } 7597 }, 7598 7599 _offUpEvents: function () { 7600 var ownerDocument = this.el.ownerDocument; 7601 7602 _off(document, "touchmove", this._onTouchMove); 7603 _off(ownerDocument, "mouseup", this._onDrop); 7604 _off(ownerDocument, "touchend", this._onDrop); 7605 _off(ownerDocument, "touchcancel", this._onDrop); 7606 }, 7607 7608 _onDrop: function (/**Event*/ evt) { 7609 var el = this.el, 7610 options = this.options; 7611 7612 clearInterval(this._loopId); 7613 clearInterval(autoScroll.pid); 7614 clearTimeout(this._dragStartTimer); 7615 7616 // Unbind events 7617 _off(document, "mousemove", this._onTouchMove); 7618 7619 if (this.nativeDraggable) { 7620 _off(document, "drop", this); 7621 _off(el, "dragstart", this._onDragStart); 7622 } 7623 7624 this._offUpEvents(); 7625 7626 if (evt) { 7627 if (moved) { 7628 evt.preventDefault(); 7629 !options.dropBubble && evt.stopPropagation(); 7630 } 7631 7632 ghostEl && ghostEl.parentNode.removeChild(ghostEl); 7633 7634 if (dragEl) { 7635 if (this.nativeDraggable) { 7636 _off(dragEl, "dragend", this); 7637 } 7638 7639 _disableDraggable(dragEl); 7640 dragEl.style["will-change"] = ""; 7641 7642 // Remove class's 7643 _toggleClass(dragEl, this.options.ghostClass, false); 7644 _toggleClass(dragEl, this.options.chosenClass, false); 7645 7646 if (rootEl !== parentEl) { 7647 newIndex = _index(dragEl, options.draggable); 7648 7649 if (newIndex >= 0) { 7650 // Add event 7651 _dispatchEvent( 7652 null, 7653 parentEl, 7654 "add", 7655 dragEl, 7656 rootEl, 7657 oldIndex, 7658 newIndex 7659 ); 7660 7661 // Remove event 7662 _dispatchEvent( 7663 this, 7664 rootEl, 7665 "remove", 7666 dragEl, 7667 rootEl, 7668 oldIndex, 7669 newIndex 7670 ); 7671 7672 // drag from one list and drop into another 7673 _dispatchEvent( 7674 null, 7675 parentEl, 7676 "sort", 7677 dragEl, 7678 rootEl, 7679 oldIndex, 7680 newIndex 7681 ); 7682 _dispatchEvent( 7683 this, 7684 rootEl, 7685 "sort", 7686 dragEl, 7687 rootEl, 7688 oldIndex, 7689 newIndex 7690 ); 7691 } 7692 } else { 7693 // Remove clone 7694 cloneEl && cloneEl.parentNode.removeChild(cloneEl); 7695 7696 if (dragEl.nextSibling !== nextEl) { 7697 // Get the index of the dragged element within its parent 7698 newIndex = _index(dragEl, options.draggable); 7699 7700 if (newIndex >= 0) { 7701 // drag & drop within the same list 7702 _dispatchEvent( 7703 this, 7704 rootEl, 7705 "update", 7706 dragEl, 7707 rootEl, 7708 oldIndex, 7709 newIndex 7710 ); 7711 _dispatchEvent( 7712 this, 7713 rootEl, 7714 "sort", 7715 dragEl, 7716 rootEl, 7717 oldIndex, 7718 newIndex 7719 ); 7720 } 7721 } 7722 } 7723 7724 if (Sortable.active) { 7725 /* jshint eqnull:true */ 7726 if (newIndex == null || newIndex === -1) { 7727 newIndex = oldIndex; 7728 } 7729 7730 _dispatchEvent(this, rootEl, "end", dragEl, rootEl, oldIndex, newIndex); 7731 7732 // Save sorting 7733 this.save(); 7734 } 7735 } 7736 } 7737
7738 this._nulling(); 7739 }, 7740 7741 _nulling: function () { 7742 rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = scrollEl = scrollParentEl = tapEvt = touchEvt = moved = newIndex = lastEl = lastCSS = putSortable = activeGroup = Sortable.active = null; 7743 }, 7744 7745 handleEvent: function (/**Event*/ evt) { 7746 var type = evt.type; 7747 7748 if (type === "dragover" || type === "dragenter") { 7749 if (dragEl) { 7750 this._onDragOver(evt); 7751 _globalDragOver(evt); 7752 } 7753 } else if (type === "drop" || type === "dragend") { 7754 this._onDrop(evt); 7755 } 7756 }, 7757 7758 /** 7759 * Serializes the item into an array of string. 7760 * @returns {String[]} 7761 */ 7762 toArray: function () { 7763 var order = [], 7764 el, 7765 children = this.el.children, 7766 i = 0, 7767 n = children.length, 7768 options = this.options; 7769 7770 for (; i < n; i++) { 7771 el = children[i]; 7772 if (_closest(el, options.draggable, this.el)) { 7773 order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); 7774 } 7775 } 7776 7777 return order; 7778 }, 7779 7780 /** 7781 * Sorts the elements according to the array. 7782 * @param {String[]} order order of the items 7783 */ 7784 sort: function (order) { 7785 var items = {}, 7786 rootEl = this.el; 7787 7788 this.toArray().forEach(function (id, i) { 7789 var el = rootEl.children[i]; 7790 7791 if (_closest(el, this.options.draggable, rootEl)) { 7792 items[id] = el; 7793 } 7794 }, this); 7795 7796 order.forEach(function (id) { 7797 if (items[id]) { 7798 rootEl.removeChild(items[id]); 7799 rootEl.appendChild(items[id]); 7800 } 7801 }); 7802 }, 7803 7804 /** 7805 * Save the current sorting 7806 */ 7807 save: function () { 7808 var store = this.options.store; 7809 store && store.set(this); 7810 }, 7811 7812 /** 7813 * 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. 7814 * @param {HTMLElement} el 7815 * @param {String} [selector] default: `options.draggable` 7816 * @returns {HTMLElement|null} 7817 */ 7818 closest: function (el, selector) { 7819 return _closest(el, selector || this.options.draggable, this.el); 7820 }, 7821 7822 /** 7823 * Set/get option 7824 * @param {string} name 7825 * @param {*} [value] 7826 * @returns {*} 7827 */ 7828 option: function (name, value) { 7829 var options = this.options; 7830 7831 if (value === void 0) { 7832 return options[name]; 7833 } else { 7834 options[name] = value; 7835 7836 if (name === "group") { 7837 _prepareGroup(options); 7838 } 7839 } 7840 }, 7841 7842 /** 7843 * Destroy 7844 */ 7845 destroy: function () { 7846 var el = this.el; 7847 7848 el[expando] = null; 7849 7850 _off(el, "mousedown", this._onTapStart); 7851 _off(el, "touchstart", this._onTapStart); 7852 7853 if (this.nativeDraggable) { 7854 _off(el, "dragover", this); 7855 _off(el, "dragenter", this); 7856 } 7857 7858 // Remove draggable attributes 7859 Array.prototype.forEach.call(el.querySelectorAll("[draggable]"), function (el) { 7860 el.removeAttribute("draggable"); 7861 }); 7862 7863 touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); 7864 7865 this._onDrop(); 7866 7867 this.el = el = null; 7868 }, 7869 }; 7870 7871 function _cloneHide(state) { 7872 if (cloneEl && cloneEl.state !== state) { 7873 _css(cloneEl, "display", state ? "none" : ""); 7874 !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl); 7875 cloneEl.state = state; 7876 } 7877 } 7878 7879 function _closest(/**HTMLElement*/ el, /**String*/ selector, /**HTMLElement*/ ctx) { 7880 if (el) { 7881 ctx = ctx || document; 7882 7883 do { 7884 if ((selector === ">*" && el.parentNode === ctx) || _matches(el, selector)) { 7885 return el; 7886 } 7887 /* jshint boss:true */ 7888 } while ((el = _getParentOrHost(el))); 7889 } 7890 7891 return null; 7892 } 7893 7894 function _getParentOrHost(el) { 7895 var parent = el.host; 7896 7897 return parent && parent.nodeType ? parent : el.parentNode; 7898 } 7899 7900 function _globalDragOver(/**Event*/ evt) { 7901 if (evt.dataTransfer) { 7902 evt.dataTransfer.dropEffect = "move"; 7903 } 7904 evt.preventDefault(); 7905 } 7906 7907 function _on(el, event, fn) { 7908 el.addEventListener(event, fn, false); 7909 } 7910 7911 function _off(el, event, fn) { 7912 el.removeEventListener(event, fn, false); 7913 } 7914 7915 function _toggleClass(el, name, state) { 7916 if (el) { 7917 if (el.classList) { 7918 el.classList[state ? "add" : "remove"](name); 7919 } else { 7920 var className = (" " + el.className + " ") 7921 .replace(RSPACE, " ") 7922 .replace(" " + name + " ", " "); 7923 el.className = (className + (state ? " " + name : "")).replace(RSPACE, " "); 7924 } 7925 } 7926 } 7927 7928 function _css(el, prop, val) { 7929 var style = el && el.style; 7930 7931 if (style) { 7932 if (val === void 0) { 7933 if (document.defaultView && document.defaultView.getComputedStyle) { 7934 val = document.defaultView.getComputedStyle(el, ""); 7935 } else if (el.currentStyle) { 7936 val = el.currentStyle; 7937 } 7938 7939 return prop === void 0 ? val : val[prop]; 7940 } else { 7941 if (!(prop in style)) { 7942 prop = "-webkit-" + prop; 7943 } 7944 7945 style[prop] = val + (typeof val === "string" ? "" : "px"); 7946 } 7947 } 7948 } 7949 7950 function _find(ctx, tagName, iterator) { 7951 if (ctx) { 7952 var list = ctx.getElementsByTagName(tagName), 7953 i = 0, 7954 n = list.length; 7955 7956 if (iterator) { 7957 for (; i < n; i++) { 7958 iterator(list[i], i); 7959 } 7960 } 7961 7962 return list; 7963 } 7964 7965 return []; 7966 } 7967 7968 function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) { 7969 sortable = sortable || rootEl[expando]; 7970 7971 var evt = document.createEvent("Event"),
7972 options = sortable.options, 7973 onName = "on" + name.charAt(0).toUpperCase() + name.substr(1); 7974 7975 evt.initEvent(name, true, true); 7976 7977 evt.to = rootEl; 7978 evt.from = fromEl || rootEl; 7979 evt.item = targetEl || rootEl; 7980 evt.clone = cloneEl; 7981 7982 evt.oldIndex = startIndex; 7983 evt.newIndex = newIndex; 7984 7985 rootEl.dispatchEvent(evt); 7986 7987 if (options[onName]) { 7988 options[onName].call(sortable, evt); 7989 } 7990 } 7991 7992 function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt) { 7993 var evt, 7994 sortable = fromEl[expando], 7995 onMoveFn = sortable.options.onMove, 7996 retVal; 7997 7998 evt = document.createEvent("Event"); 7999 evt.initEvent("move", true, true); 8000 8001 evt.to = toEl; 8002 evt.from = fromEl; 8003 evt.dragged = dragEl; 8004 evt.draggedRect = dragRect; 8005 evt.related = targetEl || toEl; 8006 evt.relatedRect = targetRect || toEl.getBoundingClientRect(); 8007 8008 fromEl.dispatchEvent(evt); 8009 8010 if (onMoveFn) { 8011 retVal = onMoveFn.call(sortable, evt, originalEvt); 8012 } 8013 8014 return retVal; 8015 } 8016 8017 function _disableDraggable(el) { 8018 el.draggable = false; 8019 } 8020 8021 function _unsilent() { 8022 _silent = false; 8023 } 8024 8025 /** @returns {HTMLElement|false} */ 8026 function _ghostIsLast(el, evt) { 8027 var lastEl = el.lastElementChild, 8028 rect = lastEl.getBoundingClientRect(); 8029 8030 // 5 â min delta 8031 // abs â нелÑÐ·Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑÑ, а Ñо глÑки пÑи наведении ÑвеÑÑ Ñ 8032 return ( 8033 (evt.clientY - (rect.top + rect.height) > 5 || 8034 evt.clientX - (rect.right + rect.width) > 5) && 8035 lastEl 8036 ); 8037 } 8038 8039 /** 8040 * Generate id 8041 * @param {HTMLElement} el 8042 * @returns {String} 8043 * @private 8044 */ 8045 function _generateId(el) { 8046 var str = el.tagName + el.className + el.src + el.href + el.textContent, 8047 i = str.length, 8048 sum = 0; 8049 8050 while (i--) { 8051 sum += str.charCodeAt(i); 8052 } 8053 8054 return sum.toString(36); 8055 } 8056 8057 /** 8058 * Returns the index of an element within its parent for a selected set of 8059 * elements 8060 * @param {HTMLElement} el 8061 * @param {selector} selector 8062 * @return {number} 8063 */ 8064 function _index(el, selector) { 8065 var index = 0; 8066 8067 if (!el || !el.parentNode) { 8068 return -1; 8069 } 8070 8071 while (el && (el = el.previousElementSibling)) { 8072 if ( 8073 el.nodeName.toUpperCase() !== "TEMPLATE" && 8074 (selector === ">*" || _matches(el, selector)) 8075 ) { 8076 index++; 8077 } 8078 } 8079 8080 return index; 8081 } 8082 8083 function _matches(/**HTMLElement*/ el, /**String*/ selector) { 8084 if (el) { 8085 selector = selector.split("."); 8086 8087 var tag = selector.shift().toUpperCase(), 8088 re = new RegExp("\\s(" + selector.join("|") + ")(?=\\s)", "g"); 8089 8090 return ( 8091 (tag === "" || el.nodeName.toUpperCase() == tag) && 8092 (!selector.length || 8093 ((" " + el.className + " ").match(re) || []).length == selector.length) 8094 ); 8095 } 8096 8097 return false; 8098 } 8099 8100 function _throttle(callback, ms) { 8101 var args, _this; 8102 8103 return function () { 8104 if (args === void 0) { 8105 args = arguments; 8106 _this = this; 8107 8108 setTimeout(function () { 8109 if (args.length === 1) { 8110 callback.call(_this, args[0]); 8111 } else { 8112 callback.apply(_this, args); 8113 } 8114 8115 args = void 0; 8116 }, ms); 8117 } 8118 }; 8119 } 8120 8121 function _extend(dst, src) { 8122 if (dst && src) { 8123 for (var key in src) { 8124 if (src.hasOwnProperty(key)) { 8125 dst[key] = src[key]; 8126 } 8127 } 8128 } 8129 8130 return dst; 8131 } 8132 8133 function _clone(el) { 8134 return $ 8135 ? $(el).clone(true)[0] 8136 : Polymer && Polymer.dom 8137 ? Polymer.dom(el).cloneNode(true) 8138 : el.cloneNode(true); 8139 } 8140 8141 // Export utils 8142 Sortable.utils = { 8143 on: _on, 8144 off: _off, 8145 css: _css, 8146 find: _find, 8147 is: function (el, selector) { 8148 return !!_closest(el, selector, el); 8149 }, 8150 extend: _extend, 8151 throttle: _throttle, 8152 closest: _closest, 8153 toggleClass: _toggleClass, 8154 clone: _clone, 8155 index: _index, 8156 }; 8157 8158 /** 8159 * Create sortable instance 8160 * @param {HTMLElement} el 8161 * @param {Object} [options] 8162 */ 8163 Sortable.create = function (el, options) { 8164 return new Sortable(el, options); 8165 }; 8166 8167 // Export
8168 Sortable.version = "1.4.2"; 8169 return Sortable; 8170 }); 8171 }); 8172 8173 const $$h = jQuery; 8174 class ImagesFormElement extends FormElement { 8175 constructor(options, formBuilder, external) { 8176 super(options, formBuilder, external); 8177 this.searchType = options.searchType || "fulltext"; 8178 this.mediaUploader = external.mediaUploader; 8179 this.button_text = options.button_text || "Browse..."; 8180 this.db_type = "text"; 8181 this.label = options.label || "Images"; 8182 this.name = options.name || "images"; 8183 this.images = this.value || []; 8184 this.value = JSON.stringify(this.value); 8185 } 8186 init() { 8187 super.init(); 8188 this.redrawImages(); 8189 } 8190 setDomElements() { 8191 super.setDomElements(); 8192 } 8193 getData() { 8194 this.updateData(); 8195 return { name: this.name, value: this.images }; 8196 } 8197 getSchema() { 8198 const schema = super.getSchema(); 8199 schema.button_text = this.button_text; 8200 return schema; 8201 } 8202 updateData() { 8203 const newListOfImages = []; 8204 $$h(this.domElements.main) 8205 .find(".mapsvg-thumbnail-wrap") 8206 .each(function (index, el) { 8207 const imageData = $$h(el).data("image"); 8208 newListOfImages.push(imageData); 8209 }); 8210 this.images = newListOfImages; 8211 this.value = JSON.stringify(this.images); 8212 $$h(this.domElements.main).find("input").val(this.value); 8213 } 8214 setEventHandlers() { 8215 super.setEventHandlers(); 8216 if (this.formBuilder.editMode) { 8217 return; 8218 } 8219 const _this = this; 8220 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 8221 this.external.mediaUploader.on("select", () => { 8222 if (_this.formBuilder.mediaUploaderisOpenedFor !== _this) 8223 return false; 8224 const attachments = _this.external.mediaUploader.state().get("selection").toJSON(); 8225 attachments.forEach(function (img) { 8226 const image = { sizes: {} }; 8227 for (const type in img.sizes) { 8228 image[type] = img.sizes[type].url 8229 .replace("http://", "//") 8230 .replace("https://", "//"); 8231 image.sizes[type] = { 8232 width: img.sizes[type].width, 8233 height: img.sizes[type].height, 8234 }; 8235 } 8236 if (!image.thumbnail) { 8237 image.thumbnail = image.full; 8238 image.sizes.thumbnail = { 8239 width: img.sizes.full.width, 8240 height: img.sizes.full.height, 8241 }; 8242 } 8243 if (!image.medium) { 8244 image.medium = image.full; 8245 image.sizes.medium = { 8246 width: img.sizes.full.width, 8247 height: img.sizes.full.height, 8248 }; 8249 } 8250 image.caption = img.caption; 8251 image.description = img.description; 8252 _this.images.push(image); 8253 }); 8254 this.setValue(this.images); 8255 _this.redrawImages(); 8256 }); 8257 $$h(_this.domElements.main).on("click", ".mapsvg-upload-image", function (e) { 8258 e.preventDefault(); 8259 _this.formBuilder.mediaUploaderisOpenedFor = _this; 8260 _this.external.mediaUploader.open(); 8261 }); 8262 $$h(_this.domElements.main).on("click", ".mapsvg-image-delete", function (e) { 8263 e.preventDefault(); 8264 $$h(this).closest(".mapsvg-thumbnail-wrap").remove(); 8265 _this.updateData(); 8266 }); 8267 _this.sortable = new sortable_min(imageDOM[0], { 8268 animation: 150, 8269 onStart: function () { 8270 $$h(_this.domElements.main).addClass("sorting"); 8271 }, 8272 onEnd: function (evt) { 8273 _this.images = []; 8274 $$h(_this.domElements.main) 8275 .find("img") 8276 .each(function (i, image) { 8277 _this.images.push($$h(image).data("image")); 8278 }); 8279 this.value = JSON.stringify(_this.images); 8280 $$h(_this.domElements.main).find("input").val(this.value); 8281 $$h(_this.domElements.main).removeClass("sorting"); 8282 }, 8283 }); 8284 } 8285 redrawImages() { 8286 const imageDOM = $$h(this.domElements.main).find(".mapsvg-data-images"); 8287 imageDOM.empty(); 8288 this.images &&
8289 this.images.forEach(function (image) { 8290 const img = $$h('<img class="mapsvg-data-thumbnail" />') 8291 .attr("src", image.thumbnail) 8292 .data("image", image); 8293 const imgContainer = $$h('<div class="mapsvg-thumbnail-wrap"></div>').data("image", image); 8294 imgContainer.append(img); 8295 imgContainer.append('<i class="mfa mfa-times mapsvg-image-delete"></i>'); 8296 imageDOM.append(imgContainer); 8297 }); 8298 $$h(this.domElements.main).find("input").val(this.value); 8299 } 8300 destroy() { 8301 super.destroy(); 8302 this.external.mediaUploader.off("select"); 8303 } 8304 } 8305 8306 const $$i = jQuery; 8307 class LocationFormElement extends FormElement { 8308 constructor(options, formBuilder, external) { 8309 super(options, formBuilder, external); 8310 this.label = this.label || (options.label === undefined ? "Location" : options.label); 8311 this.name = "location"; 8312 this.db_type = "text"; 8313 this.languages = [ 8314 { value: "sq", label: "Albanian" }, 8315 { value: "ar", label: "Arabic" }, 8316 { 8317 value: "eu", 8318 label: "Basque", 8319 }, 8320 { value: "be", label: "Belarusian" }, 8321 { value: "bg", label: "Bulgarian" }, 8322 { 8323 value: "my", 8324 label: "Burmese", 8325 }, 8326 { value: "bn", label: "Bengali" }, 8327 { value: "ca", label: "Catalan" }, 8328 { 8329 value: "zh-cn", 8330 label: "Chinese (simplified)", 8331 }, 8332 { value: "zh-tw", label: "Chinese (traditional)" }, 8333 { 8334 value: "hr", 8335 label: "Croatian", 8336 }, 8337 { value: "cs", label: "Czech" }, 8338 { value: "da", label: "Danish" }, 8339 { 8340 value: "nl", 8341 label: "Dutch", 8342 }, 8343 { value: "en", label: "English" }, 8344 { 8345 value: "en-au", 8346 label: "English (australian)", 8347 }, 8348 { value: "en-gb", label: "English (great Britain)" }, 8349 { 8350 value: "fa", 8351 label: "Farsi", 8352 }, 8353 { value: "fi", label: "Finnish" }, 8354 { value: "fil", label: "Filipino" }, 8355 { 8356 value: "fr", 8357 label: "French", 8358 }, 8359 { value: "gl", label: "Galician" }, 8360 { value: "de", label: "German" }, 8361 { 8362 value: "el", 8363 label: "Greek", 8364 }, 8365 { value: "gu", label: "Gujarati" }, 8366 { value: "iw", label: "Hebrew" }, 8367 { 8368 value: "hi", 8369 label: "Hindi", 8370 }, 8371 { value: "hu", label: "Hungarian" }, 8372 { value: "id", label: "Indonesian" }, 8373 { 8374 value: "it", 8375 label: "Italian", 8376 }, 8377 { value: "ja", label: "Japanese" }, 8378 { value: "kn", label: "Kannada" }, 8379 { 8380 value: "kk", 8381 label: "Kazakh", 8382 }, 8383 { value: "ko", label: "Korean" }, 8384 { value: "ky", label: "Kyrgyz" }, 8385 { 8386 value: "lt", 8387 label: "Lithuanian", 8388 }, 8389 { value: "lv", label: "Latvian" }, 8390 { value: "mk", label: "Macedonian" }, 8391 { 8392 value: "ml", 8393 label: "Malayalam", 8394 }, 8395 { value: "mr", label: "Marathi" },
8396 { value: "no", label: "Norwegian" }, 8397 { 8398 value: "pl", 8399 label: "Polish", 8400 }, 8401 { value: "pt", label: "Portuguese" }, 8402 { 8403 value: "pt-br", 8404 label: "Portuguese (brazil)", 8405 }, 8406 { value: "pt-pt", label: "Portuguese (portugal)" }, 8407 { 8408 value: "pa", 8409 label: "Punjabi", 8410 }, 8411 { value: "ro", label: "Romanian" }, 8412 { value: "ru", label: "Russian" }, 8413 { 8414 value: "sr", 8415 label: "Serbian", 8416 }, 8417 { value: "sk", label: "Slovak" }, 8418 { value: "sl", label: "Slovenian" }, 8419 { 8420 value: "es", 8421 label: "Spanish", 8422 }, 8423 { value: "sv", label: "Swedish" }, 8424 { value: "tl", label: "Tagalog" }, 8425 { 8426 value: "ta", 8427 label: "Tamil", 8428 }, 8429 { value: "te", label: "Telugu" }, 8430 { value: "th", label: "Thai" }, 8431 { 8432 value: "tr", 8433 label: "Turkish", 8434 }, 8435 { value: "uk", label: "Ukrainian" }, 8436 { value: "uz", label: "Uzbek" }, 8437 { 8438 value: "vi", 8439 label: "Vietnamese", 8440 }, 8441 ]; 8442 this.language = options.language; 8443 this.markerImages = MapSVG.markerImages; 8444 this.markersByField = options.markersByField; 8445 this.markerField = options.markerField; 8446 this.markersByFieldEnabled = MapSVG.parseBoolean(options.markersByFieldEnabled); 8447 this.defaultMarkerPath = 8448 options.defaultMarkerPath || 8449 this.formBuilder.mapsvg.getData().options.defaultMarkerImage; 8450 this.templates.marker = Handlebars.compile($$i("#mapsvg-data-tmpl-marker").html()); 8451 } 8452 init() { 8453 super.init(); 8454 if (this.value) { 8455 this.renderMarker(); 8456 } 8457 this.renderMarkerSelector(); 8458 } 8459 getSchema() { 8460 const schema = super.getSchema(); 8461 schema.language = this.language; 8462 schema.defaultMarkerPath = this.defaultMarkerPath; 8463 schema.markersByField = this.markersByField; 8464 schema.markerField = this.markerField; 8465 schema.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8466 return schema; 8467 } 8468 getData() { 8469 return { name: this.name, value: this.value }; 8470 } 8471 getDataForTemplate() { 8472 const data = super.getDataForTemplate(); 8473 if (this.formBuilder.admin) { 8474 data.languages = this.languages; 8475 data.markerImages = MapSVG.markerImages; 8476 data.markersByField = this.markersByField; 8477 data.markerField = this.markerField; 8478 data.markersByFieldEnabled = MapSVG.parseBoolean(this.markersByFieldEnabled); 8479 const _this = this; 8480 data.markerImages.forEach(function (m) { 8481 if (m.relativeUrl === _this.defaultMarkerPath) { 8482 m.default = true; 8483 } 8484 else { 8485 m.default = false;
8486 } 8487 }); 8488 } 8489 data.language = this.language; 8490 if (this.value) { 8491 data.location = this.value; 8492 if (data.location.marker) { 8493 data.location.img = 8494 (this.value.marker.src.indexOf(MapSVG.urls.uploads) === 0 ? "uploads/" : "") + 8495 this.value.marker.src.split("/").pop(); 8496 } 8497 } 8498 data.showUploadBtn = data.external.filtersMode; 8499 return data; 8500 } 8501 initEditor() { 8502 super.initEditor(); 8503 this.renderMarkerSelector(); 8504 this.fillMarkersByFieldOptions(this.markerField); 8505 } 8506 setDomElements() { 8507 super.setDomElements(); 8508 this.domElements.markerImageButton = $$i(this.domElements.main).find("img")[0]; 8509 } 8510 setEventHandlers() { 8511 super.setEventHandlers(); 8512 const _this = this; 8513 const server = new Server(); 8514 if (_this.formBuilder.mapsvg.isGeo()) { 8515 const locations = new Bloodhound({ 8516 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("formatted_address"), 8517 queryTokenizer: Bloodhound.tokenizers.whitespace, 8518 remote: { 8519 url: server.getUrl("geocoding") + "?address=%QUERY%&language=" + this.language, 8520 wildcard: "%QUERY%", 8521 transform: function (response) { 8522 if (response.error_message) { 8523 alert(response.error_message); 8524 } 8525 return response.results; 8526 }, 8527 rateLimitWait: 600, 8528 }, 8529 }); 8530 const thContainer = $$i(this.domElements.main).find(".typeahead"); 8531 const tH = thContainer 8532 .typeahead({ minLength: 3 }, { 8533 name: "mapsvg-addresses", 8534 display: "formatted_address", 8535 async: true, 8536 source: (query, sync, async) => { 8537 const preg = new RegExp(/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/); 8538 if (preg.test(query)) { 8539 const latlng = query.split(",").map((item) => item.trim()); 8540 const item = { 8541 formatted_address: latlng.join(","), 8542 address_components: [], 8543 geometry: { 8544 location: { 8545 lat: () => latlng[0], 8546 lng: () => latlng[1], 8547 }, 8548 }, 8549 }; 8550 sync([item]); 8551 return; 8552 } 8553 MapSVG.geocode({ address: query }, async); 8554 }, 8555 }) 8556 .on("typeahead:asyncrequest", function (e) { 8557 $$i(e.target).addClass("tt-loading"); 8558 }) 8559 .on("typeahead:asynccancel typeahead:asyncreceive", function (e) { 8560 $$i(e.target).removeClass("tt-loading"); 8561 }); 8562 thContainer.on("typeahead:select", (ev, item) => { 8563 this.setValue(null, false); 8564 const address = {}; 8565 address.formatted = item.formatted_address; 8566 item.address_components.forEach((addr_item) => { 8567 const type = addr_item.types[0]; 8568 address[type] = addr_item.long_name; 8569 if (addr_item.short_name != addr_item.long_name) { 8570 address[type + "_short"] = addr_item.short_name; 8571 } 8572 }); 8573 const locationData = { 8574 address: address, 8575 geoPoint: new GeoPoint(item.geometry.location.lat(), item.geometry.location.lng()), 8576 img: this.getMarkerImage(this.formBuilder.getData()), 8577 imagePath: this.getMarkerImage(this.formBuilder.getData()), 8578 }; 8579 this.setValue(locationData, false); 8580 thContainer.typeahead("val", ""); 8581 this.triggerChanged(); 8582 }); 8583 } 8584 $$i(this.domElements.main).on("change", ".marker-file-uploader", function () { 8585 _this.markerIconUpload(this); 8586 }); 8587 $$i(this.domElements.main).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8588 e.preventDefault(); 8589 $$i(this).toggleClass("active"); 8590 _this.toggleMarkerSelector(); 8591 }); 8592 $$i(this.domElements.main).on("click", ".mapsvg-marker-delete", function (e) { 8593 e.preventDefault(); 8594 _this.setValue(null); 8595 _this.triggerChanged(); 8596 }); 8597 } 8598 setEditorEventHandlers() { 8599 super.setEditorEventHandlers(); 8600 const _this = this; 8601 $$i(this.domElements.edit).on("change", ".marker-file-uploader", function () { 8602 _this.markerIconUpload(this); 8603 }); 8604 $$i(this.domElements.edit).on("change", 'select[name="markerField"]', function () { 8605 const fieldName = $$i(this).val(); 8606 _this.resetMarkersByField(); 8607 const newOptions = _this.fillMarkersByFieldOptions(fieldName); 8608 _this.setMarkersByField(newOptions); 8609 }); 8610 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-selector button", function (e) { 8611 e.preventDefault(); 8612 const src = $$i(this).find("img").attr("src"); 8613 $$i(this).parent().find("button").removeClass("active"); 8614 $$i(this).addClass("active"); 8615 _this.setDefaultMarkerPath(src); 8616 }); 8617 $$i(this.domElements.edit).on("click", ".mapsvg-marker-image-btn-trigger", function (e) { 8618 $$i(this).toggleClass("active"); 8619 _this.toggleMarkerSelectorInLocationEditor.call(_this, $$i(this), e); 8620 }); 8621 } 8622 markerIconUpload(input) { 8623 const uploadBtn = $$i(input).closest(".btn-file").buttonLoading(true); 8624 for (let i = 0; i < input.files.length; i++) { 8625 const data = new FormData(); 8626 data.append("file", input.files[0]); 8627 const server = new Server(); 8628 server 8629 .ajax("markers", { 8630 type: "POST", 8631 data: data, 8632 processData: false, 8633 contentType: false, 8634 }) 8635 .done((resp) => { 8636 if (resp.error) { 8637 alert(resp.error); 8638 } 8639 else { 8640 const marker = resp.marker; 8641 const newMarker = ` 8642 <button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose active"> 8643 <img src="${marker.relativeUrl}" /> 8644 </button> 8645 </button> 8646 `; 8647 $$i(this.domElements.markerSelector) 8648 .find(".mapsvg-marker-image-btn.active") 8649 .removeClass("active"); 8650 $$i(newMarker).appendTo(this.domElements.markerSelector); 8651 this.setMarkerImage(marker.relativeUrl); 8652 MapSVG.markerImages.push(marker); 8653 } 8654 }) 8655 .always(function () { 8656 uploadBtn.buttonLoading(false); 8657 }); 8658 } 8659 } 8660 mayBeAddDistanceRow() { 8661 const _this = this; 8662 if (!this.domElements.editDistanceRow) { 8663 this.domElements.editDistanceRow = $$i($$i("#mapsvg-edit-distance-row").html())[0]; 8664 } 8665 const z = $$i(this.domElements.edit).find(".mapsvg-edit-distance-row:last-child input"); 8666 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 8667 const newRow = $$i(this.templates.editDistanceRow).clone(); 8668 newRow.insertAfter($$i(_this.domElements.edit).find(".mapsvg-edit-distance-row:last-child")); 8669 } 8670 const rows = $$i(_this.domElements.edit).find(".mapsvg-edit-distance-row"); 8671 const row1 = rows.eq(rows.length - 2); 8672 const row2 = rows.eq(rows.length - 1); 8673 if (row1.length && 8674 row2.length && 8675 !row1.find("input:eq(0)").val().toString().trim() && 8676 !row2.find("input:eq(0)").val().toString().trim()) { 8677 row2.remove(); 8678 } 8679 } 8680 fillMarkersByFieldOptions(fieldName) { 8681 const _this = this; 8682 const field = _this.formBuilder.mapsvg.objectsRepository.getSchema().getField(fieldName); 8683 const options = {}; 8684 if (field) { 8685 const markerImg = _this.formBuilder.mapsvg.options.defaultMarkerImage; 8686 const rows = []; 8687 field.options.forEach(function (option) { 8688 const value = field.type === "region" ? option.id : option.value; 8689 const label = field.type === "region" ? option.title || option.id : option.label; 8690 const img = _this.markersByField && _this.markersByField[value] 8691 ? _this.markersByField[value] 8692 : markerImg; 8693 rows.push('<tr data-option-id="' + 8694 value + 8695 '"><td>' + 8696 label + 8697 '</td><td><button class="btn dropdown-toggle btn-outline-secondary mapsvg-marker-image-btn-trigger mapsvg-marker-image-btn"><img src="' + 8698 img + 8699 '" class="new-marker-img" /><span class="caret"></span></button></td></tr>'); 8700 options[value] = img; 8701 }); 8702 $$i("#markers-by-field").empty().append(rows); 8703 } 8704 return options; 8705 } 8706 renderMarker(marker) { 8707 if (marker && marker.location) { 8708 this.value = marker.location.getData(); 8709 } 8710 this.renderMarkerHtml(); 8711 } 8712 renderMarkerHtml() { 8713 if (!this.value) { 8714 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8715 } 8716 else { 8717 $$i(this.domElements.main) 8718 .find(".mapsvg-new-marker") 8719 .show() 8720 .html(this.templates.marker(this.value)); 8721 } 8722 } 8723 toggleMarkerSelector() { 8724 if (this.domElements.markerSelectorWrap && 8725 $$i(this.domElements.markerSelectorWrap).is(":visible")) { 8726 $$i(this.domElements.markerSelectorWrap).hide(); 8727 return; 8728 } 8729 if (this.domElements.markerSelectorWrap && 8730 $$i(this.domElements.markerSelectorWrap).not(":visible")) { 8731 $$i(this.domElements.markerSelector).find(".active").removeClass("active"); 8732 if (this.value && this.value.markerImagePath) { 8733 $$i(this.domElements.markerSelector) 8734 .find('[src="' + this.value.markerImagePath + '"]') 8735 .parent() 8736 .addClass("active"); 8737 } 8738 $$i(this.domElements.markerSelectorWrap).show(); 8739 return; 8740 } 8741 } 8742 renderMarkerSelector() { 8743 const _this = this; 8744 const view = this.formBuilder.editMode ? this.domElements.edit : this.domElements.main; 8745 if (!view) 8746 return; 8747 const currentImage = this.value ? this.value.markerImagePath : null; 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 this.domElements.markerSelectorWrap = $$i(view).find(".mapsvg-marker-image-selector")[0]; 8756 this.domElements.markerSelector = $$i(this.domElements.markerSelectorWrap).find(".mapsvg-marker-images")[0]; 8757 if (this.domElements.markerSelector) { 8758 $$i(this.domElements.markerSelector).empty(); 8759 } 8760 if (!this.formBuilder.editMode) { 8761 this.domElements.markerSelectorWrap.style.display = "none"; 8762 $$i(this.domElements.markerSelector).on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8763 e.preventDefault(); 8764 const src = $$i(this).find("img").attr("src"); 8765 $$i(_this.domElements.markerSelectorWrap).hide(); 8766 $$i(_this.domElements.markerSelector).find(".active").removeClass("active"); 8767 $$i(this).addClass("active"); 8768 $$i(_this.domElements.main) 8769 .find(".mapsvg-marker-image-btn-trigger") 8770 .toggleClass("active", false); 8771 $$i(_this.domElements.markerImageButton).attr("src", src); 8772 _this.setMarkerImage(src); 8773 }); 8774 } 8775 $$i(this.domElements.markerSelector).html(images.join("")); 8776 } 8777 setMarkerImage(src) { 8778 this.setDefaultMarkerPath(src); 8779 const value = this.value; 8780 if (value) { 8781 value.img = src; 8782 value.imagePath = src; 8783 this.setValue(value); 8784 this.triggerChanged(); 8785 this.renderMarker(); 8786 } 8787 } 8788 toggleMarkerSelectorInLocationEditor(jQueryObj, e) { 8789 e.preventDefault(); 8790 const _this = this; 8791 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").is(":visible")) { 8792 jQueryObj.data("markerSelector").hide(); 8793 return; 8794 } 8795 if (jQueryObj.data("markerSelector") && jQueryObj.data("markerSelector").not(":visible")) { 8796 jQueryObj.data("markerSelector").show(); 8797 return; 8798 } 8799 const markerBtn = $$i(this).closest("td").find(".mapsvg-marker-image-btn-trigger"); 8800 const currentImage = markerBtn.attr("src"); 8801 const images = MapSVG.markerImages.map(function (image) { 8802 return ('<button class="btn btn-outline-secondary mapsvg-marker-image-btn mapsvg-marker-image-btn-choose ' + 8803 (currentImage == image.relativeUrl ? "active" : "") + 8804 '"><img src="' + 8805 image.relativeUrl + 8806 '" /></button>'); 8807 }); 8808 if (!jQueryObj.data("markerSelector")) { 8809 const ms = $$i('<div class="mapsvg-marker-image-selector"></div>'); 8810 jQueryObj.closest("td").append(ms); 8811 jQueryObj.data("markerSelector", ms); 8812 } 8813 else { 8814 jQueryObj.data("markerSelector").empty(); 8815 } 8816 jQueryObj.data("markerSelector").html(images.join("")); 8817 jQueryObj 8818 .data("markerSelector") 8819 .on("click", ".mapsvg-marker-image-btn-choose", function (e) { 8820 e.preventDefault(); 8821 const src = $$i(this).find("img").attr("src"); 8822 jQueryObj.data("markerSelector").hide(); 8823 const td = $$i(this).closest("td"); 8824
8824 const fieldId = $$i(this).closest("tr").data("option-id"); 8825 const btn = td.find(".mapsvg-marker-image-btn-trigger"); 8826 btn.toggleClass("active", false); 8827 btn.find("img").attr("src", src); 8828 _this.setMarkerByField(fieldId, src); 8829 }); 8830 } 8831 setMarkersByField(options) { 8832 this.markersByField = options; 8833 } 8834 resetMarkersByField() { 8835 this.markersByField = {}; 8836 } 8837 setMarkerByField(fieldId, markerImg) { 8838 this.markersByField = this.markersByField || {}; 8839 this.markersByField[fieldId] = markerImg; 8840 } 8841 deleteMarker() { 8842 $$i(this.domElements.main).find(".mapsvg-new-marker").hide(); 8843 $$i(this.domElements.main).find(".mapsvg-marker-id").attr("disabled", "disabled"); 8844 } 8845 destroy() { 8846 if ($$i().mselect2) { 8847 const sel = $$i(this.domElements.main).find(".mapsvg-select2"); 8848 if (sel.length) { 8849 sel.mselect2("destroy"); 8850 } 8851 } 8852 this.domElements.markerSelector && $$i(this.domElements.markerSelector).popover("dispose"); 8853 } 8854 setDefaultMarkerPath(path) { 8855 this.defaultMarkerPath = path; 8856 this.formBuilder.mapsvg.setDefaultMarkerImage(path); 8857 } 8858 getMarkerImage(data) { 8859 let fieldValue; 8860 if (this.markersByFieldEnabled) { 8861 fieldValue = data[this.markerField]; 8862 if (!fieldValue) { 8863 return this.defaultMarkerPath || MapSVG.defaultMarkerImage; 8864 } 8865 else { 8866 if (this.markerField === "regions") { 8867 fieldValue = fieldValue[0] && fieldValue[0].id; 8868 } 8869 else if (typeof fieldValue === "object" && fieldValue.length) { 8870 fieldValue = fieldValue[0].value; 8871 } 8872 if (this.markersByField[fieldValue]) { 8873 return (this.markersByField[fieldValue] || 8874 this.defaultMarkerPath || 8875 MapSVG.defaultMarkerImage); 8876 } 8877 } 8878 } 8879 else { 8880 return this.defaultMarkerPath || MapSVG.defaultMarkerImage; 8881 } 8882 } 8883 setValue(value, updateInput = true) { 8884 this.value = value; 8885 if (this.value) { 8886 if (!this.value.address) { 8887 this.value.address = {}; 8888 } 8889 if (Object.keys(this.value.address).length < 2 && this.value.geoPoint) { 8890 this.value.address.formatted = 8891 this.value.geoPoint.lat + "," + this.value.geoPoint.lng; 8892 } 8893 } 8894 this.renderMarker(); 8895 } 8896 } 8897 8898 const $$j = jQuery; 8899 class ModalFormElement extends FormElement { 8900 constructor(options, formBuilder, external) { 8901 super(options, formBuilder, external); 8902 this.showButtonText = options.showButtonText; 8903 } 8904 getSchema() { 8905 const schema = super.getSchema(); 8906 schema.showButtonText = this.showButtonText; 8907 return schema; 8908 } 8909 } 8910 8911 const $$k = jQuery; 8912 class PostFormElement extends FormElement { 8913 constructor(options, formBuilder, external) { 8914 super(options, formBuilder, external); 8915 if (this.formBuilder.admin) 8916 this.post_types = this.formBuilder.admin.getPostTypes(); 8917 this.post_type = options.post_type || this.post_types[0]; 8918 this.add_fields = MapSVG.parseBoolean(options.add_fields); 8919 this.db_type = "int(11)"; 8920 this.name = "post"; 8921 this.post = options.post; 8922 } 8923 setDomElements() { 8924 super.setDomElements(); 8925 this.inputs.postSelect = ($$k(this.domElements.main).find(".mapsvg-find-post")[0]); 8926 } 8927 getSchema() { 8928 const schema = super.getSchema(); 8929 schema.post_type = this.post_type; 8930 schema.add_fields = this.add_fields; 8931 return schema; 8932 } 8933 destroy() { 8934 if ($$k().mselect2) { 8935 const sel = $$k(this.domElements.main).find(".mapsvg-select2"); 8936 if (sel.length) { 8937 sel.mselect2("destroy"); 8938 } 8939 } 8940 } 8941 getDataForTemplate() { 8942 const data = super.getDataForTemplate(); 8943 if (this.formBuilder.admin) 8944 data.post_types = this.formBuilder.admin.getPostTypes(); 8945 data.post_type = this.post_type; 8946 data.post = this.post; 8947 data.add_fields = this.add_fields || 0; 8948 return data; 8949 } 8950 setEventHandlers() { 8951 super.setEventHandlers(); 8952 const server = new Server(); 8953 $$k(this.inputs.postSelect) 8954 .mselect2({ 8955 placeholder: "Search post by title", 8956 allowClear: true, 8957 disabled: this.readonly, 8958 ajax: { 8959 url: server.getUrl("posts"), 8960 dataType: "json", 8961 delay: 250, 8962 data: (params) => { 8963 return { 8964 filters: { post_type: this.post_type }, 8965 search: params.term, 8966 page: params.page, 8967 }; 8968 }, 8969 processResults: (data, params) => { 8970 params.page = params.page || 1; 8971 return { 8972 results: data.posts ? data.posts : [], 8973 pagination: { 8974 more: false, 8975 }, 8976 }; 8977 }, 8978 cache: true, 8979 }, 8980 escapeMarkup: (markup) => { 8981 return markup; 8982 }, 8983 minimumInputLength: 1, 8984 templateResult: this.formatRepo, 8985 templateSelection: this.formatRepoSelection, 8986 }) 8987 .on("select2:select", (e) => { 8988 const post = e.params.data; 8989 this.setValue(post); 8990 this.setInputValue(post); 8991 this.triggerChanged(); 8992 }) 8993 .on("change", (e) => { 8994 if (e.target.value === "") { 8995 $$k(this.domElements.main).find(".mapsvg-post-id").text(""); 8996 $$k(this.domElements.main).find(".mapsvg-post-url").text(""); 8997 this.setValue(null, false); 8998 this.triggerChanged(); 8999 } 9000 }); 9001 } 9002 formatRepo(repo) { 9003 if (repo.loading) { 9004 return repo.text; 9005 } 9006 else { 9007 return "<div class='select2-result-repository clearfix'>" + repo.post_title + "</div>"; 9008 } 9009 } 9010 formatRepoSelection(repo) { 9011 return repo.post_title || repo.text; 9012 } 9013 setValue(post, updateInput = true) { 9014 this.value = post; 9015 if (updateInput) { 9016 this.setInputValue(post); 9017 } 9018 } 9019 setInputValue(post) { 9020 $$k(this.domElements.main).find(".mapsvg-post-id").text(post.id); 9021 $$k(this.domElements.main).find(".mapsvg-post-url").text(post.url).attr("href", post.url); 9022 } 9023 } 9024 9025 const $$l = jQuery; 9026 class RadioFormElement extends FormElement { 9027 constructor(options, formBuilder, external) { 9028 super(options, formBuilder, external); 9029 this.setOptions(options.options); 9030 } 9031 setDomElements() { 9032 super.setDomElements(); 9033 this.inputs.radios = this.formBuilder.getForm().elements[this.name]; 9034 this.$radios = $$l(this.domElements.main).find('input[type="radio"]'); 9035 } 9036 setEventHandlers() { 9037 super.setEventHandlers(); 9038 this.$radios.on("change", (e) => { 9039 this.setValue(e.target.value, false); 9040 this.triggerChanged(); 9041 }); 9042 } 9043 setInputValue(value) { 9044 if (value === null) { 9045 this.$radios.prop("checked", false); 9046 } 9047 else { 9048 this.inputs.radios.value = value; 9049 } 9050 } 9051 } 9052 9053 const $$m = jQuery; 9054 class RegionsFormElement extends FormElement { 9055 constructor(options, formBuilder, external) { 9056 super(options, formBuilder, external); 9057 this.searchable = MapSVG.parseBoolean(options.searchable); 9058 this.options = this.formBuilder.getRegionsList(); 9059 this.label = options.label === undefined ? "Regions" : options.label;
9060 this.name = "regions"; 9061 this.db_type = "text"; 9062 if (typeof this.value === "undefined") { 9063 this.value = []; 9064 } 9065 this.regionsTableName = this.formBuilder.mapsvg.regionsRepository.getSchema().name; 9066 } 9067 setDomElements() { 9068 super.setDomElements(); 9069 this.inputs.select = $$m(this.domElements.main).find("select")[0]; 9070 } 9071 getData() { 9072 return { name: "regions", value: this.value }; 9073 } 9074 getSchema() { 9075 const schema = super.getSchema(); 9076 if (schema.multiselect) 9077 schema.db_type = "text"; 9078 const opts = $$m.extend(true, {}, { options: this.options }); 9079 schema.options = opts.options; 9080 schema.optionsDict = {}; 9081 schema.options.forEach(function (option) { 9082 schema.optionsDict[option.id] = option.title || option.id; 9083 }); 9084 return schema; 9085 } 9086 getDataForTemplate() { 9087 const data = super.getDataForTemplate(); 9088 data.regionsTableName = this.regionsTableName; 9089 data.regionsFromCurrentTable = this.getRegionsForCurrentTable(); 9090 return data; 9091 } 9092 getRegionsForCurrentTable() { 9093 return this.value 9094 ? this.value.filter((region) => region.tableName === this.regionsTableName) 9095 : []; 9096 } 9097 setEventHandlers() { 9098 super.setEventHandlers(); 9099 $$m(this.inputs.select).on("change", (e) => { 9100 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 9101 const selectedValues = selectedOptions.map((option) => option.value); 9102 this.setValue(selectedValues, false); 9103 this.triggerChanged(); 9104 }); 9105 } 9106 destroy() { 9107 if ($$m().mselect2) { 9108 const sel = $$m(this.domElements.main).find(".mapsvg-select2"); 9109 if (sel.length) { 9110 sel.mselect2("destroy"); 9111 } 9112 } 9113 } 9114 setValue(regionIds, updateInput = true) { 9115 const regionsFromOtherTables = this.value.filter((region) => region.tableName !== this.regionsTableName); 9116 const regions = []; 9117 regionIds.forEach((regionId) => { 9118 const region = this.formBuilder.mapsvg.getRegion(regionId); 9119 regions.push({ id: region.id, title: region.title, tableName: this.regionsTableName }); 9120 }); 9121 this.value = regions.concat(regionsFromOtherTables); 9122 if (updateInput) { 9123 this.setInputValue(regionIds); 9124 } 9125 } 9126 } 9127 9128 const $$n = jQuery; 9129 class SaveFormElement extends FormElement { 9130 constructor(options, formBuilder, external) { 9131 super(options, formBuilder, external); 9132 this.readonly = true; 9133 } 9134 setDomElements() { 9135 super.setDomElements(); 9136 this.inputs.btnSave = $$n(this.domElements.main).find(".btn-save")[0]; 9137 this.inputs.btnClose = $$n(this.domElements.main).find(".mapsvg-close")[0]; 9138 } 9139 setEventHandlers() { 9140 super.setEventHandlers(); 9141 $$n(this.inputs.btnSave).on("click", (e) => { 9142 e.preventDefault(); 9143 this.events.trigger("click.btn.save"); 9144 }); 9145 $$n(this.inputs.btnClose).on("click", (e) => { 9146 e.preventDefault(); 9147 this.events.trigger("click.btn.close"); 9148 }); 9149 } 9150 } 9151 9152 const $$o = jQuery; 9153 class SearchFormElement extends FormElement { 9154 constructor(options, formBuilder, external) { 9155 super(options, formBuilder, external); 9156 this.searchFallback = MapSVG.parseBoolean(options.searchFallback) || false; 9157 this.width = options.width || "100%"; 9158 this.name = "search"; 9159 } 9160 setDomElements() { 9161 super.setDomElements(); 9162 this.inputs.text = $$o(this.domElements.main).find("input")[0]; 9163 } 9164 setEventHandlers() { 9165 super.setEventHandlers(); 9166 $$o(this.inputs.text).on("change keyup paste", (e) => { 9167 this.setValue(e.target.value, false); 9168 this.triggerChanged(); 9169 }); 9170 } 9171 setInputValue(value) { 9172 this.inputs.text.value = value; 9173 } 9174 getSchema() { 9175 const schema = super.getSchema(); 9176 schema.searchFallback = MapSVG.parseBoolean(this.searchFallback); 9177 schema.placeholder = this.placeholder; 9178 schema.width = this.width; 9179 return schema; 9180 } 9181 } 9182 9183 const $$p = jQuery; 9184 class SelectFormElement extends FormElement { 9185 constructor(options, formBuilder, external) { 9186 super(options, formBuilder, external); 9187 this.searchable = MapSVG.parseBoolean(options.searchable); 9188 this.multiselect = MapSVG.parseBoolean(options.multiselect); 9189 this.optionsGrouped = options.optionsGrouped; 9190 this.db_type = this.multiselect ? "text" : "varchar(255)"; 9191 this.setOptions(options.options); 9192 } 9193 setDomElements() { 9194 super.setDomElements(); 9195 this.inputs.select = $$p(this.domElements.main).find("select")[0]; 9196 } 9197 getSchema() { 9198 const schema = super.getSchema(); 9199 schema.multiselect = MapSVG.parseBoolean(this.multiselect); 9200 if (schema.multiselect) 9201 schema.db_type = "text"; 9202 schema.optionsGrouped = this.optionsGrouped; 9203 const opts = $$p.extend(true, {}, { options: this.options }); 9204 schema.options = opts.options || []; 9205 schema.optionsDict = {}; 9206 schema.options.forEach(function (option) { 9207 schema.optionsDict[option.value] = option.label; 9208 }); 9209 return schema; 9210 } 9211 setEventHandlers() { 9212 super.setEventHandlers(); 9213 $$p(this.inputs.select).on("change", (e) => { 9214 if (this.multiselect) { 9215 const selectedOptions = Array.from(this.inputs.select.selectedOptions); 9216 const selectedValues = selectedOptions.map((option) => { 9217 return { label: option.label, value: option.value }; 9218 }); 9219 this.setValue(selectedValues, false); 9220 this.triggerChanged(); 9221 } 9222 else { 9223 this.setValue(this.inputs.select.value, false); 9224 this.triggerChanged(); 9225 } 9226 }); 9227 } 9228 addSelect2() { 9229 if ($$p().mselect2) { 9230 const select2Options = {}; 9231 if (this.formBuilder.filtersMode && this.type == "select") { 9232 select2Options.placeholder = this.placeholder; 9233 if (!this.multiselect) { 9234 select2Options.allowClear = true; 9235 } 9236 } 9237 $$p(this.domElements.main) 9238 .find("select") 9239 .css({ width: "100%", display: "block" }) 9240 .mselect2(select2Options) 9241 .on("select2:focus", function () { 9242 $$p(this).mselect2("open"); 9243 }); 9244 $$p(this.domElements.main) 9245 .find(".select2-selection--multiple .select2-search__field") 9246 .css("width", "100%"); 9247 } 9248 } 9249 setOptions(options) { 9250 if (options) { 9251 this.options = []; 9252 this.optionsDict = {}; 9253 options.forEach((value, key) => { 9254 this.options.push(value); 9255 if (this.optionsGrouped) { 9256 value.options.forEach((value2, key2) => { 9257 this.optionsDict[value2.value] = value2; 9258 }); 9259 } 9260 else { 9261 this.optionsDict[key] = value; 9262 } 9263 }); 9264 return this.options; 9265 } 9266 else { 9267 return this.setOptions([ 9268 { label: "Option one", name: "option_one", value: 1 }, 9269 { label: "Option two", name: "option_two", value: 2 }, 9270 ]); 9271 } 9272 } 9273 setInputValue(value) { 9274 if (this.multiselect) { 9275 if (this.value) { 9276 $$p(this.inputs.select).val(this.value.map((el) => el.value)); 9277 } 9278 else { 9279 $$p(this.inputs.select).val([]); 9280 } 9281 } 9282 else { 9283 this.inputs.select.value = this.value; 9284 } 9285 $$p(this.inputs.select).trigger("change.select2"); 9286 } 9287 } 9288 9289 const $$q = jQuery; 9290 class StatusFormElement extends FormElement { 9291 constructor(options, formBuilder, external) { 9292 super(options, formBuilder, external); 9293 this.label = options.label || "Status"; 9294 this.name = "status"; 9295 this.setOptions(options.options); 9296 } 9297 setDomElements() { 9298 super.setDomElements(); 9299 this.inputs.select = $$q(this.domElements.main).find("select")[0]; 9300 if ($$q().colorpicker) { 9301 $$q(this.domElements.main) 9302 .find(".cpicker") 9303 .colorpicker() 9304 .on("changeColor.colorpicker", function (event) { 9305 const input = $$q(this).find("input"); 9306 if (input.val() == "") 9307 $$q(this).find("i").css({ "background-color": "" }); 9308 }); 9309 this.domElements.edit && 9310 $$q(this.domElements.edit) 9311 .find(".cpicker") 9312 .colorpicker() 9313 .on("changeColor.colorpicker", function (event) { 9314 const input = $$q(this).find("input"); 9315 if (input.val() == "") 9316 $$q(this).find("i").css({ "background-color": "" }); 9317 }); 9318 } 9319 } 9320 destroy() { 9321 if ($$q().mselect2) { 9322 const sel = $$q(this.domElements.main).find(".mapsvg-select2"); 9323 if (sel.length) { 9324 sel.mselect2("destroy"); 9325 } 9326 } 9327 } 9328 setEditorEventHandlers() { 9329 super.setEditorEventHandlers(); 9330 const _this = this; 9331 $$q(this.domElements.edit).on("keyup change paste", ".mapsvg-edit-status-row input", function () { 9332 _this.mayBeAddStatusRow(); 9333 }); 9334 } 9335 initEditor() { 9336 super.initEditor(); 9337 const _this = this; 9338 $$q(_this.domElements.edit) 9339 .find(".cpicker") 9340 .colorpicker() 9341 .on("changeColor.colorpicker", function (event) { 9342 const input = $$q(this).find("input"); 9343 const index = $$q(this).closest("tr").index(); 9344 if (input.val() == "") 9345 $$q(this).find("i").css({ "background-color": "" }); 9346 _this.options[index] = _this.options[index] || { 9347 label: "", 9348 value: "", 9349 color: "", 9350 disabled: false, 9351 }; 9352 _this.options[index]["color"] = input.val(); 9353 }); 9354 _this.mayBeAddStatusRow(); 9355 } 9356 mayBeAddStatusRow() { 9357 const _this = this; 9358 const editStatusRow = $$q($$q("#mapsvg-edit-status-row").html()); 9359 const z = $$q(_this.domElements.edit).find(".mapsvg-edit-status-label:last-child"); 9360 if (z && z.last() && z.last().val() && (z.last().val() + "").trim().length) { 9361 const newRow = editStatusRow.clone(); 9362 newRow.insertAfter($$q(_this.domElements.edit).find(".mapsvg-edit-status-row:last-child")); 9363 newRow 9364 .find(".cpicker") 9365 .colorpicker() 9366 .on("changeColor.colorpicker", function (event) { 9367 const input = $$q(this).find("input"); 9368 const index = $$q(this).closest("tr").index(); 9369 if (input.val() == "") 9370 $$q(this).find("i").css({ "background-color": "" }); 9371 _this.options[index] = _this.options[index] || { 9372 label: "", 9373 value: "", 9374 color: "", 9375 disabled: false, 9376 }; 9377 _this.options[index]["color"] = input.val(); 9378 }); 9379 } 9380 const rows = $$q(_this.domElements.edit).find(".mapsvg-edit-status-row"); 9381 const row1 = rows.eq(rows.length - 2); 9382 const row2 = rows.eq(rows.length - 1); 9383 if (row1.length && 9384 row2.length && 9385 !(row1.find("input:eq(0)").val().toString().trim() || 9386 row1.find("input:eq(1)").val().toString().trim() || 9387 row1.find("input:eq(2)").val().toString().trim()) && 9388 !(row2.find("input:eq(0)").val().toString().trim() || 9389 row2.find("input:eq(1)").val().toString().trim() || 9390 row2.find("input:eq(2)").val().toString().trim())) { 9391 row2.remove(); 9392 } 9393 } 9394 setEventHandlers() { 9395 super.setEventHandlers(); 9396 $$q(this.inputs.select).on("change keyup paste", (e) => { 9397 this.setValue(e.target.value, false); 9398 this.triggerChanged(); 9399 }); 9400 } 9401 getSchema() { 9402 const schema = super.getSchema(); 9403 const opts = $$q.extend(true, {}, { options: this.options }); 9404 schema.options = opts.options; 9405 schema.optionsDict = {}; 9406 schema.options.forEach(function (option, index) { 9407 if (schema.options[index].value === "") { 9408 schema.options.splice(index, 1); 9409 } 9410 else { 9411 schema.options[index].disabled = MapSVG.parseBoolean(schema.options[index].disabled); 9412 schema.optionsDict[option.value] = option; 9413 } 9414 }); 9415 return schema; 9416 } 9417 setInputValue(value) { 9418 this.inputs.select.value = value; 9419 } 9420 } 9421 9422 const $$r = jQuery; 9423 class TextareaFormElement extends FormElement { 9424 constructor(options, formBuilder, external) { 9425 super(options, formBuilder, external); 9426 this.searchType = options.searchType || "fulltext"; 9427 this.searchable = MapSVG.parseBoolean(options.searchable); 9428 this.autobr = options.autobr; 9429 this.html = options.html; 9430 this.db_type = "text"; 9431 } 9432 setDomElements() { 9433 super.setDomElements(); 9434 this.inputs.textarea = $$r(this.domElements.main).find("textarea")[0]; 9435 if (this.html) { 9436 this.editor = CodeMirror.fromTextArea(this.inputs.textarea, { 9437 mode: { name: "handlebars", base: "text/html" }, 9438 matchBrackets: true, 9439 lineNumbers: true, 9440 }); 9441 if (this.formBuilder.admin) { 9442 this.editor.on("change", this.setTextareaValue); 9443 } 9444 } 9445 } 9446 setEventHandlers() { 9447 super.setEventHandlers(); 9448 $$r(this.inputs.textarea).on("change keyup paste", (e) => { 9449 this.setValue(e.target.value, false); 9450 this.triggerChanged(); 9451 }); 9452 } 9453 getSchema() { 9454 const schema = super.getSchema(); 9455 schema.autobr = this.autobr; 9456 schema.html = this.html; 9457 return schema; 9458 } 9459 getDataForTemplate() { 9460 const data = super.getDataForTemplate(); 9461 data.html = this.html; 9462 return data; 9463 } 9464 setTextareaValue(codemir
9464ror, changeobj) { 9465 const handler = codemirror.getValue(); 9466 const textarea = $$r(codemirror.getTextArea()); 9467 textarea.val(handler).trigger("change"); 9468 } 9469 destroy() { 9470 const cm = $$r(this.domElements.main).find(".CodeMirror"); 9471 if (cm.length) { 9472 cm.empty().remove(); 9473 } 9474 } 9475 } 9476 9477 const $$s = jQuery; 9478 class TextFormElement extends FormElement { 9479 constructor(options, formBuilder, external) { 9480 super(options, formBuilder, external); 9481 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9482 this.searchType = options.searchType; 9483 this.width = 9484 this.formBuilder.filtersHide && !this.formBuilder.modal 9485 ? null 9486 : options.width || "100%"; 9487 this.db_type = "varchar(255)"; 9488 } 9489 setDomElements() { 9490 super.setDomElements(); 9491 this.inputs.text = $$s(this.domElements.main).find('input[type="text"]')[0]; 9492 } 9493 getSchema() { 9494 const schema = super.getSchema(); 9495 schema.searchType = this.searchType; 9496 return schema; 9497 } 9498 setEventHandlers() { 9499 super.setEventHandlers(); 9500 $$s(this.inputs.text).on("change keyup paste", (e) => { 9501 this.setValue(e.target.value, false); 9502 this.triggerChanged(); 9503 }); 9504 } 9505 setInputValue(value) { 9506 this.inputs.text.value = value; 9507 } 9508 } 9509 9510 const $$t = jQuery; 9511 class TitleFormElement extends FormElement { 9512 constructor(options, formBuilder, external) { 9513 super(options, formBuilder, external); 9514 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9515 this.width = 9516 this.formBuilder.filtersHide && !this.formBuilder.modal 9517 ? null 9518 : options.width || "100%"; 9519 this.db_type = "varchar(255)"; 9520 } 9521 setDomElements() { 9522 super.setDomElements(); 9523 this.inputs.text = $$t(this.domElements.main).find('input[type="text"]')[0]; 9524 } 9525 getSchema() { 9526 const schema = super.getSchema(); 9527 schema.searchType = this.searchType; 9528 return schema; 9529 } 9530 setEventHandlers() { 9531 super.setEventHandlers(); 9532 $$t(this.inputs.text).on("change keyup paste", (e) => { 9533 this.setValue(e.target.value, false); 9534 this.triggerChanged(); 9535 }); 9536 } 9537 setInputValue(value) { 9538 this.inputs.text.value = value; 9539 } 9540 } 9541 9542 const $$u = jQuery; 9543 class ColorPickerFormElement extends FormElement { 9544 constructor(options, formBuilder, external) { 9545 super(options, formBuilder, external); 9546 this.searchFallback = MapSVG.parseBoolean(options.searchFallback); 9547 this.width = 9548 this.formBuilder.filtersHide && !this.formBuilder.modal 9549 ? null 9550 : options.width || "100%"; 9551 this.db_type = "varchar(255)"; 9552 } 9553 setDomElements() { 9554 super.setDomElements(); 9555 this.inputs.text = $$u(this.domElements.main).find("input.cpicker")[0]; 9556 $$u(this.domElements.main).find(".colorpicker-element").colorpicker(); 9557 } 9558 getSchema() { 9559 const schema = super.getSchema(); 9560 schema.searchType = this.searchType; 9561 return schema; 9562 } 9563 setEventHandlers() { 9564 super.setEventHandlers(); 9565 $$u(this.inputs.text).on("change keyup paste", (e) => { 9566 this.setValue(e.target.value, false); 9567 this.triggerChanged(); 9568 }); 9569 $$u(this.domElements.main).find(".colorpicker-element").colorpicker().on("changeColor.colorpicker", (e) => { 9570 this.setValue(this.inputs.text.value, false); 9571 this.triggerChanged(); 9572 }); 9573 } 9574 setInputValue(value) { 9575 this.inputs.text.value = value; 9576 } 9577 } 9578 9579 const $$v = jQuery; 9580 class FormElementFactory { 9581 constructor(options) { 9582 this.mapsvg = options.mapsvg; 9583 this.editMode = options.editMode; 9584 this.filtersMode = options.filtersMode; 9585 this.namespace = options.namespace; 9586 this.mediaUploader = options.mediaUploader; 9587 this.formBuilder = options.formBuilder; 9588 this.showNames = options.showNames !== false; 9589 } 9590 create(options) { 9591 const types = { 9592 checkbox: CheckboxFormElement, 9593 checkboxes: CheckboxesFormElement, 9594 date: DateFormElement, 9595 distance: DistanceFormElement, 9596 empty: EmptyFormElement, 9597 id: IdFormElement, 9598 image: ImagesFormElement, 9599 location: LocationFormElement, 9600 modal: ModalFormElement, 9601 post: PostFormElement, 9602 radio: RadioFormElement, 9603 region: RegionsFormElement, 9604 save: SaveFormElement, 9605 search: SearchFormElement, 9606 select: SelectFormElement, 9607 status: StatusFormElement, 9608 text: TextFormElement, 9609 textarea: TextareaFormElement, 9610 title: TitleFormElement, 9611 colorpicker: ColorPickerFormElement, 9612 }; 9613 const formElement = new types[options.type](options, this.formBuilder, this.getExtraParams()); 9614 formElement.init(); 9615 return formElement; 9616 } 9617 getExtraParams() { 9618 const databaseFields = []; 9619 const databaseFieldsFilterable = []; 9620 const databaseFieldsFilterableShort = []; 9621 const regionFields = []; 9622 const regionFieldsFilterable = []; 9623 const regions = new ArrayIndexed("id"); 9624 let mapIsGeo = false;
9625 if (this.mapsvg) { 9626 mapIsGeo = this.mapsvg.isGeo(); 9627 const schemaObjects = this.mapsvg.objectsRepository.getSchema(); 9628 if (schemaObjects) { 9629 schemaObjects.getFields().forEach(function (obj) { 9630 if (obj.type == "text" || 9631 obj.type == "region" || 9632 obj.type == "textarea" || 9633 obj.type == "post" || 9634 obj.type == "select" || 9635 obj.type == "radio" || 9636 obj.type == "checkbox") { 9637 if (obj.type == "post") { 9638 databaseFields.push("Object.post.post_title"); 9639 } 9640 else { 9641 databaseFields.push("Object." + obj.name); 9642 } 9643 } 9644 if (obj.type == "region" || obj.type == "select" || obj.type == "radio") { 9645 databaseFieldsFilterable.push("Object." + obj.name); 9646 databaseFieldsFilterableShort.push(obj.name); 9647 } 9648 }); 9649 } 9650 const schemaRegions = this.mapsvg.regionsRepository.getSchema(); 9651 if (schemaRegions) { 9652 schemaRegions.getFieldsAsArray().forEach(function (obj) { 9653 if (obj.type == "status" || 9654 obj.type == "text" || 9655 obj.type == "textarea" || 9656 obj.type == "post" || 9657 obj.type == "select" || 9658 obj.type == "radio" || 9659 obj.type == "checkbox") { 9660 if (obj.type == "post") { 9661 regionFields.push("Region.post.post_title"); 9662 } 9663 else { 9664 regionFields.push("Region." + obj.name); 9665 } 9666 } 9667 if (obj.type == "status" || obj.type == "select" || obj.type == "radio") { 9668 regionFieldsFilterable.push("Region." + obj.name); 9669 } 9670 }); 9671 } 9672 this.mapsvg.regions.forEach((region) => { 9673 regions.push({ id: region.id, title: region.title }); 9674 }); 9675 } 9676 return { 9677 databaseFields: databaseFields, 9678 databaseFieldsFilterable: databaseFieldsFilterable, 9679 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 9680 regionFields: regionFields, 9681 regionFieldsFilterable: regionFieldsFilterable, 9682 regions: regions, 9683 mapIsGeo: mapIsGeo, 9684 mediaUploader: this.mediaUploader, 9685 filtersMode: this.filtersMode, 9686 showNames: this.showNames, 9687 }; 9688 } 9689 } 9690 9691 const $$w = jQuery; 9692 class FormBuilder { 9693 constructor(options) { 9694 const _this = this; 9695 this.events = new Events(); 9696 this.container = options.container; 9697 this.namespace = options.namespace; 9698 this.mediaUploader = options.mediaUploader; 9699 this.schema = options.schema || []; 9700 this.editMode = options.editMode == undefined ? false : options.editMode; 9701 this.filtersMode = options.filtersMode == undefined ? false : options.filtersMode; 9702 this.filtersHide = options.filtersHide == undefined ? false : options.filtersHide; 9703 this.modal = options.modal == undefined ? false : options.modal; 9704 this.admin = options.admin; 9705 this.mapsvg = options.mapsvg; 9706 this.data = options.data || {}; 9707 this.clearButton = options.clearButton || false; 9708 this.clearButtonText = options.clearButtonText || ""; 9709 this.searchButton = options.searchButton || false; 9710 this.searchButtonText = options.searchButtonText || ""; 9711 this.showButtonText = options.showButtonText || ""; 9712 this.scrollable = 9713 typeof options.scrollable !== "undefined" 9714 ? options.scrollable 9715 : !_this.editMode && !_this.filtersMode; 9716 this.showNames = typeof options.showNames !== "undefined" ? options.showNames : true; 9717 this.formElementFactory = new FormElementFactory({ 9718 mapsvg: this.mapsvg, 9719 formBuilder: this, 9720 mediaUploader: this.mediaUploader, 9721 editMode: this.editMode, 9722 filtersMode: this.filtersMode, 9723 namespace: this.namespace, 9724 showNames: this.showNames, 9725 }); 9726 this.events = new Events(this); 9727 if (options.events && Object.keys(options.events).length > 0) { 9728 for (const eventName in options.events) { 9729 this.events.on(eventName, options.events[eventName]); 9730 } 9731 } 9732 this.template = "form-builder"; 9733 this.closeOnSave = options.closeOnSave === true; 9734 this.newRecord = options.newRecord === true; 9735 this.types = options.types || [ 9736 "text", 9737 "textarea", 9738 "checkbox", 9739 "radio", 9740 "select", 9741 "image", 9742 "region", 9743 "location", 9744 "post", 9745 "date", 9746 ]; 9747 this.templates = {}; 9748 this.elements = {}; 9749 this.view = $$w("<div />").addClass("mapsvg-form-builder")[0]; 9750 if (this.editMode) 9751 $$w(this.view).addClass("full-flex"); 9752 if (!this.showNames) { 9753 $$w(this.view).addClass("hide-names"); 9754 } 9755 this.formElements = new ArrayIndexed("name"); 9756 if (!MapSVG.templatesLoaded[this.template]) { 9757 this.loadTemplates(() => this.init()); 9758 } 9759 else { 9760 this.init(); 9761 } 9762 } 9763 loadTemplates(callback) { 9764 $$w.get(MapSVG.urls.root + "dist/" + this.template + ".html?v=" + MapSVG.version, (data) => { 9765 $$w(data).appendTo("body");
9766 MapSVG.templatesLoaded[this.template] = true; 9767 Handlebars.registerPartial("dataMarkerPartial", $$w("#mapsvg-data-tmpl-marker").html()); 9768 if (this.editMode) { 9769 Handlebars.registerPartial("markerByFieldPartial", $$w("#mapsvg-markers-by-field-tmpl-partial").html()); 9770 } 9771 callback(); 9772 }); 9773 } 9774 init() { 9775 const _this = this; 9776 MapSVG.formBuilder = this; 9777 this.form = document.createElement("form"); 9778 this.form.className = "mapsvg-data-form-view"; 9779 if (!this.filtersMode) { 9780 this.form.classList.add("form-horizontal"); 9781 } 9782 if (this.editMode) { 9783 const template = document.getElementById("mapsvg-form-editor-tmpl-ui").innerHTML; 9784 const templateCompiled = Handlebars.compile(template); 9785 this.view.innerHTML = templateCompiled({ types: this.types }); 9786 this.view.classList.add("edit"); 9787 this.form.classList.add("mapsvg-data-flex-full"); 9788 this.form.classList.add("mapsvg-data-container"); 9789 $$w(this.view).find(".mapsvg-data-preview").prepend(this.form); 9790 this.formEditor = $$w(this.view).find("#mapsvg-data-form-edit")[0]; 9791 } 9792 else { 9793 this.view.appendChild(this.form); 9794 } 9795 _this.elements = { 9796 buttons: { 9797 text: $$w(_this.view).find("#mapsvg-data-btn-text")[0], 9798 textarea: $$w(_this.view).find("#mapsvg-data-btn-textarea")[0], 9799 checkbox: $$w(_this.view).find("#mapsvg-data-btn-checkbox")[0], 9800 radio: $$w(_this.view).find("#mapsvg-data-btn-radio")[0], 9801 select: $$w(_this.view).find("#mapsvg-data-btn-select")[0], 9802 image: $$w(_this.view).find("#mapsvg-data-btn-image")[0], 9803 region: $$w(_this.view).find("#mapsvg-data-btn-region")[0], 9804 marker: $$w(_this.view).find("#mapsvg-data-btn-marker")[0], 9805 saveSchema: $$w(_this.view).find("#mapsvg-data-btn-save-schema")[0], 9806 }, 9807 containers: { 9808 buttons_add: $$w(_this.view).find("#mapsvg-data-buttons-add")[0], 9809 }, 9810 }; 9811 _this.redraw(); 9812 } 9813 getForm() { 9814 return this.form; 9815 } 9816 getFormEditor() { 9817 return this.formEditor; 9818 } 9819 viewDidLoad() { } 9820 setEventHandlers() { 9821 const _this = this; 9822 $$w(this.getForm()).on("submit", (e) => { 9823 e.preventDefault(); 9824 }); 9825 if (this.filtersMode && this.clearButton) { 9826 $$w(this.elements.buttons.clearButton).on("click", (e) => { 9827 e.preventDefault(); 9828 this.clearAllFields(); 9829 }); 9830 } 9831 $$w(window) 9832 .off("keydown.form.mapsvg") 9833 .on("keydown.form.mapsvg", function (e) { 9834 if (MapSVG.formBuilder) { 9835 if ((e.metaKey || e.ctrlKey) && e.keyCode == 13) 9836 MapSVG.formBuilder.save(); 9837 else if (e.keyCode == 27) 9838 MapSVG.formBuilder.close(); 9839 } 9840 }); 9841 if (this.editMode) { 9842 $$w(this.view).on("click", "#mapsvg-data-buttons-add button", function (e) { 9843 e.preventDefault(); 9844 const type = $$w(this).data("create"); 9845 const formElement = _this.formElementFactory.create({ type: type }); 9846 _this.addField(formElement); 9847 }); 9848 $$w(this.view).on("click", "#mapsvg-data-btn-save-schema", function (e) { 9849 e.preventDefault(); 9850 const fields = _this.getSchema(); 9851 const counts = {}; 9852 _this.formElements.forEach(function (elem) { 9853 counts[elem.name] = (counts[elem.name] || 0) + 1; 9854 }); 9855 $$w(_this.getForm()).find(".form-group").removeClass("has-error"); 9856 const errors = []; 9857 const reservedFields = [ 9858 "lat", 9859 "lon", 9860 "lng", 9861 "location", 9862 "location_lat", 9863 "location_lon", 9864 "location_lng", 9865 "location_address", 9866 "location_img", 9867 "marker", 9868 "marker_id", 9869 "regions", 9870 "region_id", 9871 "post", 9872 "post_title", 9873 "post_url", 9874 "keywords", 9875 "status", 9876 ]; 9877 const reservedFieldsToTypes = { 9878 regions: "region", 9879 status: "status", 9880 post: "post", 9881 marker: "marker", 9882 location: "location", 9883 }; 9884 let errUnique, errEmpty;
9885 _this.formElements.forEach(function (formElement, index) { 9886 let err = false; 9887 if (!_this.filtersMode) { 9888 if (counts[formElement.name] > 1) { 9889 if (!errUnique) { 9890 errUnique = "Field names should be unique"; 9891 errors.push(errUnique); 9892 err = true; 9893 } 9894 } 9895 else if (formElement.name.length === 0) { 9896 if (!errEmpty) { 9897 errEmpty = "Field name can't be empty"; 9898 errors.push(errEmpty); 9899 err = true; 9900 } 9901 } 9902 else if (reservedFields.indexOf(formElement.name) != -1) { 9903 if (!reservedFieldsToTypes[formElement.name] || 9904 (reservedFieldsToTypes[formElement.name] && 9905 reservedFieldsToTypes[formElement.name] != formElement.type)) { 9906 const msg = 'Field name "' + 9907 formElement.name + 9908 '" is reserved, please set another name'; 9909 errors.push(msg); 9910 err = true; 9911 } 9912 } 9913 } 9914 if (formElement.options && 9915 formElement.type != "region" && 9916 formElement.type != "marker") { 9917 const vals = formElement.options.map(function (obj) { 9918 return obj.value; 9919 }); 9920 const uniq = [...Array.from(new Set(vals).values())]; 9921 if (vals.length != uniq.length) { 9922 errors.push('Check "Options" list - values should not repeat'); 9923 err = true; 9924 } 9925 } 9926 err && $$w(formElement.domElements.main).addClass("has-error"); 9927 }); 9928 if (errors.length === 0) { 9929 _this.events.trigger("saveSchema", _this, [_this, fields]); 9930 } 9931 else { 9932 jQuery.growl.error({ title: "Errors", message: errors.join("<br />") }); 9933 } 9934 }); 9935 setTimeout(function () { 9936 const el = _this.getForm(); 9937 _this.sortable = new Sortable(el, { 9938 animation: 150, 9939 onStart: function () { 9940 $$w(_this.getForm()).addClass("sorting"); 9941 }, 9942 onEnd: function () { 9943 setTimeout(function () { 9944 $$w(_this.getForm()).removeClass("sorting"); 9945 _this.formElements.clear(); 9946 $$w(el) 9947 .find(".form-group") 9948 .each(function (index, elem) { 9949 _this.formElements.push($$w(elem).data("formElement")); 9950 }); 9951 }, 500); 9952 }, 9953 }); 9954 }, 1000); 9955 } 9956 new ResizeSensor(this.view, function () { 9957 _this.scrollApi && _this.scrollApi.reinitialise(); 9958 }); 9959 } 9960 clearAllFields() { 9961 this.formElements.forEach((f) => f.setValue(null)); 9962 this.events.trigger("cleared"); 9963 } 9964 setFormElementEventHandlers(formElement) { 9965 if (this.editMode) { 9966 formElement.events.on("click", (elem) => { 9967 this.edit(elem); 9968 }); 9969 formElement.events.on("delete", (elem) => { 9970 this.deleteField(elem); 9971 }); 9972 } 9973 else { 9974 formElement.events.on("changed", (_formElement) => { 9975 const name = _formElement.name; 9976 const value = _formElement.getValue(); 9977 if (_formElement.type !== "search") { 9978 this.events.trigger("changed.field", _formElement, [_formElement, name, value]); 9979 } 9980 else { 9981 this.events.trigger("changed.search", _formElement, [_formElement, value]); 9982 } 9983 }); 9984 } 9985 } 9986 save() { 9987 const _this = this; 9988 if (_this.markerBackup) { 9989 const marker = _this.mapsvg.getEditingMarker(); 9990 marker.events.off("change"); 9991 _this.markerBackup = marker.getOptions(); 9992 _this.mapsvg.unsetEditingMarker(); 9993 } 9994 const data = _this.getData(); 9995 _this.saved = true; 9996 this.events.trigger("save", _this, [_this, data]); 9997 } 9998 getFormElementByType(type) { 9999 return this.formElements.find((el) => el.type === type); 10000 } 10001 getData() { 10002 const data = {};
10003 this.formElements.forEach((formElement) => { 10004 if (formElement.readonly === false || formElement.type === "id") { 10005 const _formElementData = formElement.getData(); 10006 data[_formElementData.name] = _formElementData.value; 10007 } 10008 }); 10009 return data; 10010 } 10011 reset() { 10012 this.formElements.forEach((formElement) => { 10013 formElement.setValue(null); 10014 }); 10015 } 10016 update(data) { 10017 this.schema.getFields().forEach((field) => { 10018 const formElement = this.formElements.get(field.name); 10019 if (formElement) { 10020 if (typeof data[field.name] !== "undefined") { 10021 if (formElement.getValue() !== data[field.name]) { 10022 formElement.setValue(data[field.name]); 10023 } 10024 } 10025 else { 10026 formElement.setValue(null); 10027 } 10028 } 10029 }); 10030 } 10031 redraw() { 10032 const _this = this; 10033 delete _this.markerBackup; 10034 $$w(this.container).empty(); 10035 $$w(this.getForm()).empty(); 10036 this.formElements.clear(); 10037 this.schema && 10038 this.schema.fields.length > 0 && 10039 this.schema.fields.forEach((fieldSettings) => { 10040 if (this.filtersMode) { 10041 if (fieldSettings.type == "distance") { 10042 fieldSettings.value = this.data.distance 10043 ? this.data.distance 10044 : fieldSettings.value !== undefined 10045 ? fieldSettings.value 10046 : null; 10047 } 10048 else { 10049 fieldSettings.value = this.data[fieldSettings.parameterNameShort]; 10050 } 10051 } 10052 else { 10053 fieldSettings.value = this.data 10054 ? this.data[fieldSettings.name] 10055 : fieldSettings.value !== undefined 10056 ? fieldSettings.value 10057 : null; 10058 } 10059 if (fieldSettings.type == "location" && !this.editMode) { 10060 if (fieldSettings.value && 10061 fieldSettings.value.marker && 10062 fieldSettings.value.marker.id) ; 10063 this.admin && this.admin.setMode && this.admin.setMode("editMarkers"); 10064 this.admin && this.admin.enableMarkersMode(true); 10065 } 10066 else if (fieldSettings.type == "post") { 10067 fieldSettings.post = this.data["post"]; 10068 } 10069 else if (fieldSettings.type === "region") { 10070 fieldSettings.options = new ArrayIndexed("id", this.getRegionsList()); 10071 } 10072 const formElement = this.formElementFactory.create(fieldSettings); 10073 if (this.filtersMode) { 10074 if (!this.filtersHide || 10075 (this.filtersHide && this.modal && fieldSettings.type !== "search") || 10076 (!this.modal && fieldSettings.type === "search")) { 10077 this.addField(formElement); 10078 } 10079 } 10080 else { 10081 this.addField(formElement); 10082 } 10083 }); 10084 if (!_this.editMode) { 10085 if (this.schema.fields.length === 0 && !this.filtersMode) { 10086 const formElement = this.formElementFactory.create({ type: "empty" }); 10087 _this.addField(formElement); 10088 } 10089 else { 10090 if (_this.admin && !_this.admin.isMetabox) { 10091 const formElement = this.formElementFactory.create({ type: "save" }); 10092 formElement.events.on("click.btn.save", () => { 10093 this.save(); 10094 }); 10095 formElement.events.on("click.btn.close", () => { 10096 this.close(); 10097 }); 10098 _this.addField(formElement); 10099 } 10100 } 10101 } 10102 if (_this.filtersMode && _this.filtersHide && !_this.modal) { 10103 const formElement = this.formElementFactory.create({ 10104 type: "modal", 10105 showButtonText: _this.showButtonText, 10106 });
10107 this.showFiltersButton = _this.addField(formElement); 10108 } 10109 if (this.scrollable) { 10110 const nano = $$w('<div class="nano"></div>'); 10111 const nanoContent = $$w('<div class="nano-content"></div>'); 10112 nano.append(nanoContent); 10113 nanoContent.append(this.view); 10114 $$w(_this.container).append(nano); 10115 nano.jScrollPane({ contentWidth: "0px", mouseWheelSpeed: 30 }); 10116 _this.scrollApi = nano.data("jsp"); 10117 } 10118 else { 10119 $$w(_this.container).append(this.view); 10120 } 10121 if (_this.filtersMode && _this.clearButton) { 10122 _this.elements.buttons.clearButton = $$w('<div class="form-group mapsvg-filters-reset-container">' + 10123 '<button type="button" class="btn btn-outline-secondary mapsvg-filters-reset">' + 10124 _this.clearButtonText + 10125 "</button></div>")[0]; 10126 $$w(this.getForm()).append(_this.elements.buttons.clearButton); 10127 } 10128 if (_this.filtersMode && _this.searchButton) { 10129 _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">' + 10130 _this.searchButtonText + 10131 "</button></div>")[0]; 10132 $$w(this.getForm()).append(_this.elements.buttons.searchButton); 10133 } 10134 if (!this.editMode && !_this.filtersMode) 10135 $$w(this.view).find("input:visible,textarea:visible").not(".tt-hint").first().focus(); 10136 const cm = $$w(this.container).find(".CodeMirror"); 10137 cm.each(function (index, el) { 10138 el && el.CodeMirror.refresh(); 10139 }); 10140 _this.setEventHandlers(); 10141 this.events.trigger("init", this, [this, this.getData()]); 10142 this.events.trigger("loaded", this, [this]); 10143 } 10144 updateExtraParamsInFormElements() { 10145 this.formElements.forEach((formElement) => { 10146 formElement.setExternal(this.formElementFactory.getExtraParams()); 10147 if (formElement.type === "location") { 10148 formElement.redraw(); 10149 } 10150 }); 10151 } 10152 deleteField(formElement) { 10153 const _this = this; 10154 _this.formElements.delete(formElement.name); 10155 } 10156 getExtraParams() { 10157 const databaseFields = []; 10158 this.mapsvg.objectsRepository 10159 .getSchema() 10160 .getFields() 10161 .forEach(function (obj) { 10162 if (obj.type == "text" || 10163 obj.type == "region" || 10164 obj.type == "textarea" || 10165 obj.type == "post" || 10166 obj.type == "select" || 10167 obj.type == "radio" || 10168 obj.type == "checkbox") { 10169 if (obj.type == "post") { 10170 databaseFields.push("Object.post.post_title"); 10171 } 10172 else { 10173 databaseFields.push("Object." + obj.name); 10174 } 10175 } 10176 }); 10177 let databaseFieldsFilterableShort = []; 10178 databaseFieldsFilterableShort = this.mapsvg.objectsRepository 10179 .getSchema() 10180 .getFieldsAsArray() 10181 .filter(function (obj) { 10182 return obj.type == "select" || obj.type == "radio" || obj.type == "region"; 10183 }) 10184 .map(function (obj) { 10185 return obj.name; 10186 }); 10187 let markerFieldsShort = []; 10188 markerFieldsShort = databaseFieldsFilterableShort.filter((o) => o.type === "select" || o.type === "radio"); 10189 const regionFields = this.mapsvg.regionsRepository 10190 .getSchema() 10191 .getFieldsAsArray() 10192 .map(function (obj) { 10193 if (obj.type == "status" || 10194 obj.type == "text" || 10195 obj.type == "textarea" || 10196 obj.type == "post" || 10197 obj.type == "select" || 10198 obj.type == "radio" || 10199 obj.type == "checkbox") { 10200 if (obj.type == "post") { 10201 return "Region.post.post_title"; 10202 } 10203 else { 10204 return "Region." + obj.name; 10205 } 10206 } 10207 }); 10208 return { 10209 databaseFields: databaseFields, 10210 databaseFieldsFilterableShort: databaseFieldsFilterableShort, 10211 regionFields: regionFields, 10212 markerFieldsShort: markerFieldsShort, 10213 }; 10214 } 10215 addField(formElement) { 10216 const _this = this; 10217 if (["region", "marker", "post", "status", "distance", "location", "search"].indexOf(formElement.type) != -1) { 10218 let repeat = false;
10219 _this.formElements.forEach(function (control) { 10220 if (control.type == formElement.type) 10221 repeat = true; 10222 }); 10223 if (repeat) { 10224 jQuery.growl.error({ 10225 title: "Error", 10226 message: 'You can add only 1 "' + MapSVG.ucfirst(formElement.type) + '" field', 10227 }); 10228 return; 10229 } 10230 } 10231 _this.formElements.push(formElement); 10232 _this.getForm().append(formElement.domElements.main); 10233 this.setFormElementEventHandlers(formElement); 10234 if (this.editMode) { 10235 if (formElement.protected) { 10236 formElement.hide(); 10237 } 10238 else { 10239 this.edit(formElement); 10240 } 10241 } 10242 return formElement; 10243 } 10244 edit(formElement) { 10245 const _this = this; 10246 _this.currentlyEditing && _this.currentlyEditing.destroyEditor(); 10247 this.getFormEditor().appendChild(formElement.getEditor()); 10248 formElement.initEditor(); 10249 _this.currentlyEditing = formElement; 10250 $$w(_this.getForm()).find(".form-group.active").removeClass("active"); 10251 $$w(formElement.domElements.main).addClass("active"); 10252 } 10253 get() { 10254 } 10255 getSchema() { 10256 return this.formElements.map(function (formElement) { 10257 return formElement.getSchema(); 10258 }); 10259 } 10260 close() { 10261 this.formElements.forEach((formElement) => formElement.destroy()); 10262 this.mediaUploader && this.mediaUploader.off("select"); 10263 MapSVG.formBuilder = null; 10264 this.events.trigger("close", this, [this]); 10265 } 10266 destroy() { 10267 $$w(this.view).empty().remove(); 10268 this.sortable = null; 10269 } 10270 toJSON(addEmpty) { 10271 const obj = {}; 10272 function add(obj, name, value) { 10273 if (!addEmpty && !value) 10274 return false; 10275 if (name.length == 1) { 10276 obj[name[0]] = value; 10277 } 10278 else { 10279 if (obj[name[0]] == null) { 10280 if (name[1] === "") { 10281 obj[name[0]] = []; 10282 } 10283 else { 10284 obj[name[0]] = {}; 10285 } 10286 } 10287 if (obj[name[0]].length !== undefined) { 10288 obj[name[0]].push(value); 10289 } 10290 else { 10291 add(obj[name[0]], name.slice(1), value); 10292 } 10293 } 10294 } 10295 $$w(this.elements.containers.formView) 10296 .find("input, textarea, select") 10297 .each(function () { 10298 if (!$$w(this).data("skip") && 10299 !$$w(this).prop("disabled") && 10300 $$w(this).attr("name") && 10301 !(!addEmpty && 10302 $$w(this).attr("type") == "checkbox" && 10303 $$w(this).attr("checked") == undefined) && 10304 !($$w(this).attr("type") == "radio" && $$w(this).attr("checked") == undefined)) { 10305 let value; 10306 if ($$w(this).attr("type") == "checkbox") { 10307 value = $$w(this).prop("checked"); 10308 } 10309 else { 10310 value = $$w(this).val(); 10311 } 10312 add(obj, $$w(this).attr("name").replace(/]/g, "").split("["), value); 10313 } 10314 }); 10315 return obj; 10316 } 10317 getRegionsList() { 10318 return this.mapsvg.regions.map(function (r) { 10319 return { id: r.id, title: r.title }; 10320 }); 10321 } 10322 getRegionsAsArray() { 10323 return this.mapsvg.regions; 10324 } 10325 setRegions(location) { 10326 const regionsFormElement = this.formElements.get("regions"); 10327 if (this.mapsvg.options.source.indexOf("/geo-calibrated/us
10327a.svg") !== -1) { 10328 regionsFormElement.setValue(["US-" + location.address.state_short]); 10329 } 10330 else if (this.mapsvg.options.source.indexOf("/geo-calibrated/world.svg") !== -1) { 10331 if (location.address.country_short) { 10332 regionsFormElement.setValue([location.address.country_short]); 10333 } 10334 } 10335 else { 10336 if (location.address.administrative_area_level_1) { 10337 this.mapsvg.regions.forEach((_region) => { 10338 if (_region.title === location.address.administrative_area_level_1 || 10339 _region.title === location.address.administrative_area_level_2 || 10340 _region.id === 10341 location.address.country_short + 10342 "-" + 10343 location.address.administrative_area_level_1_short) { 10344 regionsFormElement.setValue([_region.id]); 10345 } 10346 }); 10347 } 10348 } 10349 } 10350 setIsLoading(value) { 10351 this.isLoading = value; 10352 if (this.searchButton) { 10353 if (this.isLoading) { 10354 $$w(this.elements.buttons.searchButton).find("button").attr("disabled", "disabled"); 10355 } 10356 else { 10357 $$w(this.elements.buttons.searchButton).find("button").removeAttr("disabled"); 10358 } 10359 } 10360 } 10361 } 10362 10363 const $$x = jQuery; 10364 class FiltersController extends DetailsController { 10365 constructor(options) { 10366 super(options); 10367 this.showButtonText = options.showButtonText; 10368 this.clearButton = options.clearButton; 10369 this.clearButtonText = options.clearButtonText; 10370 this.searchButton = options.searchButton; 10371 this.searchButtonText = options.searchButtonText; 10372 this.padding = options.padding; 10373 this.schema = options.schema; 10374 this.hideFilters = options.hide; 10375 this.query = options.query; 10376 } 10377 viewDidLoad() { 10378 super.viewDidLoad(); 10379 const _this = this; 10380 this.formBuilder = new FormBuilder({ 10381 container: this.containers.contentView, 10382 filtersMode: true, 10383 schema: this.schema, 10384 modal: this.modal, 10385 filtersHide: this.hideFilters, 10386 showButtonText: this.showButtonText, 10387 clearButton: this.clearButton, 10388 clearButtonText: this.clearButtonText, 10389 searchButton: this.searchButton, 10390 searchButtonText: this.searchButtonText, 10391 editMode: false, 10392 mapsvg: this.mapsvg, 10393 data: {}, 10394 admin: false, 10395 events: { 10396 "changed.field": (formElement, field, value) => { 10397 const filters = {}; 10398 let _value = value; 10399 if (field === "regions") { 10400 _value = {}; 10401 _value.region_ids = value instanceof Array ? value : [value]; 10402 _value.table_name = this.mapsvg.options.database.regionsTableName; 10403 if (_value.region_ids.length === 0 || _value.region_ids[0] === "") { 10404 _value = null; 10405 } 10406 } 10407 filters[field] = _value; 10408 this.query.setFilters(filters); 10409 _this.events.trigger("changed.field", _this, [field, value]); 10410 _this.events.trigger("changed.fields", _this, [field, value]); 10411 }, 10412 "changed.search": (formElement, value) => { 10413 this.query.setSearch(value); 10414 _this.events.trigger("changed.search", _this, [value]); 10415 }, 10416 cleared: (formBuilder) => { 10417 this.query.clearFilters(); 10418 this.events.trigger("cleared", _this, []); 10419 }, 10420 loaded: (formBuilder) => { 10421 $$x(formBuilder.container).find(".mapsvg-form-builder").css({ 10422 padding: _this.padding, 10423 }); 10424 this.updateScroll(); 10425 this.events.trigger("loaded"); 10426 }, 10427 }, 10428 }); 10429 } 10430 reset() { 10431 this.formBuilder && this.formBuilder.reset(); 10432 } 10433 update(query) { 10434 const _query = Object.assign({}, query.filters); 10435 _query.search = query.search; 10436 this.formBuilder && this.formBuilder.update(_query); 10437 } 10438 setFiltersCounter() { 10439 if (this.hideFilters) { 10440 const filtersCounter = Object.keys(this.query.filters).length; 10441 const filtersCounterString = filtersCounter === 0 ? "" : f
10441iltersCounter.toString(); 10442 this.formBuilder && 10443 this.formBuilder.showFiltersButton && 10444 $$x(this.formBuilder.showFiltersButton.domElements.main) 10445 .find("button") 10446 .html(this.showButtonText + " <b>" + filtersCounterString + "</b>"); 10447 } 10448 } 10449 setEventHandlers() { 10450 super.setEventHandlers(); 10451 const _this = this; 10452 $$x(this.containers.view).on("click", ".mapsvg-btn-show-filters", function () { 10453 _this.events.trigger("click.btn.showFilters"); 10454 }); 10455 $$x(this.containers.view).on("click", "#mapsvg-search-container button", function () { 10456 _this.events.trigger("click.btn.searchButton"); 10457 }); 10458 } 10459 } 10460 10461 const $$y = jQuery; 10462 class PopoverController extends Controller { 10463 constructor(options) { 10464 super(options); 10465 this.autoresize = true; 10466 this.point = options.point; 10467 this.yShift = options.yShift; 10468 this.mapObject = options.mapObject; 10469 this.id = this.mapObject.id + "_" + Math.random(); 10470 $$y(this.containers.main).data("popover-id", this.id); 10471 } 10472 setPoint(point) { 10473 this.point = point; 10474 } 10475 getToolbarTemplate() { 10476 if (this.withToolbar) 10477 return '<div class="mapsvg-popover-close"></div>'; 10478 else 10479 return ""; 10480 } 10481 viewDidLoad() { 10482 super.viewDidLoad.call(this); 10483 if (MapSVG.isPhone && 10484 this.mapsvg.options.popovers.mobileFullscreen && 10485 !this.mobileCloseBtn) { 10486 this.mobileCloseBtn = $$y('<button class="mapsvg-mobile-modal-close">' + 10487 this.mapsvg.getData().options.mobileView.labelClose + 10488 "</button>")[0]; 10489 $$y(this.containers.view).append(this.mobileCloseBtn); 10490 } 10491 this.adjustScreenPosition(); 10492 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10493 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10494 this.adjustHeight(); 10495 this.updateScroll(); 10496 this.autoresize && this.resizeSensor.setScroll(); 10497 this.events.trigger("shown", this, [this]); 10498 } 10499 adjustHeight() { 10500 $$y(this.containers.main).height($$y(this.containers.main).find(".mapsvg-auto-height").outerHeight() + 10501 (this.containers.toolbar ? $$y(this.containers.toolbar).outerHeight() : 0)); 10502 } 10503 adjustScreenPosition() { 10504 if (this.point) { 10505 const pos = this.mapsvg.converter.convertSVGToPixel(this.point); 10506 pos.y -= this.yShift; 10507 pos.x = Math.round(pos.x); 10508 pos.y = Math.round(pos.y); 10509 this.setScreenPosition(pos.x, pos.y); 10510 } 10511 } 10512 moveSrceenPositionBy(deltaX, deltaY) { 10513 const oldPos = this.screenPoint, x = oldPos.x - deltaX, y = oldPos.y - deltaY; 10514 this.setScreenPosition(x, y); 10515 } 10516 setScreenPosition(x, y) { 10517 this.screenPoint = new ScreenPoint(x, y); 10518 $$y(this.containers.main).css({ 10519 transform: "translateX(-50%) translate(" + x + "px," + y + "px)", 10520 }); 10521 } 10522 setEventHandlers() { 10523 $$y("body").off(".popover.mapsvg"); 10524 $$y(this.containers.view).on("click touchend", ".mapsvg-popover-close, .mapsvg-mobile-modal-close", (e) => { 10525 e.stopImmediatePropagation(); 10526 this.close(); 10527 }); 10528 $$y("body").on("mouseup.popover.mapsvg touchend.popover.mapsvg", (e) => { 10529 if (this.mapsvg.isScrolling || 10530 $$y(e.target).closest(".mapsvg-directory").length || 10531 $$y(e.target).closest(".mapsvg-popover").length || 10532 $$y(e.target).hasClass("mapsvg-btn-map")) 10533 return; 10534 this.close(); 10535 }); 10536 } 10537 close() { 10538 if ($$y(this.containers.main).data("popover-id") != this.id || 10539 !$$y(this.containers.main).is(":visible")) 10540 return; 10541 this.destroy(); 10542 if (this.mapObject instanceof Region) { 10543 this.mapsvg.deselectRegion(this.mapObject); 10544 } 10545 if (this.mapObject instanceof Marker) { 10546 this.mapsvg.deselectAllMarkers(); 10547 } 10548 this.events.trigger("closed", this, [this]); 10549 } 10550 destroy() { 10551 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", false); 10552 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", false); 10553 super.destroy.call(this); 10554 } 10555 show() { 10556 $$y(this.containers.main).toggleClass("mapsvg-popover-animate", true); 10557 $$y(this.containers.main).toggleClass("mapsvg-popover-visible", true); 10558 } 10559 } 10560 10561 const $$z = jQuery; 10562 class Tooltip extends Controller { 10563 constructor(options) { 10564 super(options); 10565 this.scrollable = false;
10566 this.withToolbar = false; 10567 this.autoresize = false; 10568 this.screenPoint = new ScreenPoint(0, 0); 10569 this.posOriginal = {}; 10570 this.posShifted = {}; 10571 this.posShiftedPrev = {}; 10572 this.mirror = {}; 10573 this.noPadding = true; 10574 this.setPosition(options.position); 10575 this.setSize(options.minWidth, options.maxWidth); 10576 } 10577 setSize(minWidth, maxWidth) { 10578 this.minWidth = minWidth; 10579 this.maxWidth = maxWidth; 10580 this.containers.main.style["min-width"] = this.minWidth + "px"; 10581 this.containers.main.style["max-width"] = this.maxWidth + "px"; 10582 } 10583 setPosition(position) { 10584 const ex = position.split("-"); 10585 if (ex[0].indexOf("top") != -1 || ex[0].indexOf("bottom") != -1) { 10586 this.posOriginal.topbottom = ex[0]; 10587 } 10588 if (ex[0].indexOf("left") != -1 || ex[0].indexOf("right") != -1) { 10589 this.posOriginal.leftright = ex[0]; 10590 } 10591 if (ex[1]) { 10592 this.posOriginal.leftright = ex[1]; 10593 } 10594 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10595 this.containers.main.classList.add("mapsvg-tt-" + position); 10596 } 10597 setScreenPoint(x, y) { 10598 this.screenPoint.x = x; 10599 this.screenPoint.y = y; 10600 } 10601 viewDidLoad() { 10602 super.viewDidLoad.call(this); 10603 } 10604 viewDidAppear() { 10605 super.viewDidAppear(); 10606 this.events.trigger("shown", this, [this]); 10607 } 10608 setScreenPosition(x, y) { 10609 this.setScreenPoint(x, y); 10610 this.containers.main.style.transform = 10611 "translateX(-50%) translate(" + x + "px," + y + "px)"; 10612 } 10613 setEventHandlers() { 10614 const event = "mousemove.tooltip.mapsvg-" + this.mapsvg.id; 10615 $$z("body") 10616 .off(event) 10617 .on(event, (e) => { 10618 MapSVG.mouse = MapSVG.mouseCoords(e); 10619 this.containers.main.style.left = 10620 e.clientX + 10621 $$z(window).scrollLeft() - 10622 $$z(this.mapsvg.containers.map).offset().left + 10623 "px"; 10624 this.containers.main.style.top = 10625 e.clientY + 10626 $$z(window).scrollTop() - 10627 $$z(this.mapsvg.containers.map).offset().top + 10628 "px"; 10629 const m = new ScreenPoint(e.clientX + $$z(window).scrollLeft(), e.clientY + $$z(window).scrollTop()); 10630 const _tbbox = this.containers.main.getBoundingClientRect(); 10631 const _mbbox = this.mapsvg.containers.map.getBoundingClientRect(); 10632 const tbbox = { 10633 top: _tbbox.top + $$z(window).scrollTop(), 10634 bottom: _tbbox.bottom + $$z(window).scrollTop(), 10635 left: _tbbox.left + $$z(window).scrollLeft(), 10636 right: _tbbox.right + $$z(window).scrollLeft(), 10637 width: _tbbox.width, 10638 height: _tbbox.height, 10639 }; 10640 const mbbox = { 10641 top: _mbbox.top + $$z(window).scrollTop(), 10642 bottom: _mbbox.bottom + $$z(window).scrollTop(), 10643 left: _mbbox.left + $$z(window).scrollLeft(), 10644 right: _mbbox.right + $$z(window).scrollLeft(), 10645 width: _mbbox.width, 10646 height: _mbbox.height, 10647 }; 10648 if (m.x > mbbox.right || 10649 m.y > mbbox.bottom || 10650 m.x < mbbox.left || 10651 m.y < mbbox.top) { 10652 return; 10653 } 10654 if (this.mirror.top || this.mirror.bottom) { 10655 if (this.mirror.top && m.y > this.mirror.top) { 10656 this.mirror.top = 0; 10657 delete this.posShifted.topbottom; 10658 } 10659 else if (this.mirror.bottom && m.y < this.mirror.bottom) { 10660 this.mirror.bottom = 0; 10661 delete this.posShifted.topbottom; 10662 } 10663 } 10664 else { 10665 if (tbbox.bottom < mbbox.top + tbbox.height) { 10666 this.posShifted.topbottom = "bottom"; 10667 this.mirror.top = m.y; 10668 } 10669 else if (tbbox.top > mbbox.bottom - tbbox.height) { 10670 this.posShifted.topbottom = "top"; 10671 this.mirror.bottom = m.y; 10672 } 10673 } 10674 if (this.mirror.right || this.mirror.left) { 10675 if (this.mirror.left && m.x > this.mirror.left) { 10676 this.mirror.left = 0; 10677 delete this.posShifted.leftright; 10678 } 10679 else if (this.mirror.right && m.x < this.mirror.right) { 10680 this.mirror.right = 0; 10681 delete this.posShifted.leftright; 10682 } 10683 } 10684 else { 10685 if (tbbox.right < mbbox.left + tbbox.width) { 10686 this.posShifted.leftright = "right"; 10687 this.mirror.left = m.x; 10688 } 10689 else if (tbbox.left > mbbox.right - tbbox.width) { 10690 this.posShifted.leftright = "left"; 10691 this.mirror.right = m.x; 10692 } 10693 } 10694 let pos = $$z.extend({}, this.posOriginal, this.posShifted); 10695 const _pos = []; 10696 pos.topbottom && _pos.push(pos.topbottom); 10697 pos.leftright && _pos.push(pos.leftright); 10698 pos = _pos.join("-"); 10699 if (this.posShifted.topbottom != this.posOriginal.topbottom || 10700 this.posShifted.leftright != this.posOriginal.leftright) { 10701 this.containers.main.className = this.containers.main.className.replace(/(^|\s)mapsvg-tt-\S+/g, ""); 10702 this.containers.main.classList.add("mapsvg-tt-" + pos); 10703 this.posShiftedPrev = pos; 10704 } 10705 }); 10706 } 10707 setContent(template, data) { 10708 this.containers.main.innerHTML = template(data); 10709 return this; 10710 } 10711 show() { 10712 this.containers.main.classList.add("mapsvg-tooltip-visible"); 10713 return this; 10714 } 10715 hide() { 10716 this.containers.main.classList.remove("mapsvg-tooltip-visible"); 10717 return this; 10718 } 10719 } 10720 10721 const $$A = jQuery; 10722 class MapSVGMap { 10723 constructor(containerId, mapParams, externalParams) { 10724 this.markerOptions = { src: MapSVG.urls.root + "markers/pin1_red.png" }; 10725 const options = mapParams.options; 10726 this.updateOutdatedOptions(options); 10727 this.dirtyFields = []; 10728 this.containerId = containerId; 10729 this.options = $$A.extend(true, {}, DefaultOptions, options); 10730 this.options.source = this.urlToRelativePath(this.options.source); 10731 this.editMode = this.options.editMode; 10732 delete this.options.editMode; 10733 this.id = mapParams.id; 10734 this.svgFileLastChanged = mapParams.svgFileLastChanged; 10735 this.regions = new ArrayIndexed("id"); 10736 this.objects = new ArrayIndexed("id"); 10737 this.events = new Events(this); 10738 this.highlightedRegions = []; 10739 this.editRegions = { on: false }; 10740 this.editMarkers = { on: false }; 10741 this.editData = { on: false }; 10742 this.controllers = {}; 10743 this.containers = { 10744 map: document.getElementById(this.containerId), 10745 scrollpane: $$A('<div class="mapsvg-scrollpane"></div>')[0], 10746 scrollpaneWrap: $$A('<div class="mapsvg-scrollpane-wrap"></div>')[0], 10747 layers: $$A('<div class="mapsvg-layers-wrap"></div>')[0], 10748 }; 10749 this.containers.map.appendChild(this.containers.layers); 10750 this.containers.map.appendChild(this.containers.scrollpaneWrap); 10751 this.containers.scrollpaneWrap.appendChild(this.containers.scrollpane); 10752 this.whRatio = 0; 10753 this.isScrolling = false;
10754 this.markerOptions = {}; 10755 this.svgDefault = {}; 10756 this.scale = 1; 10757 this._scale = 1; 10758 this.selected_id = []; 10759 this.regions = new ArrayIndexed("id"); 10760 if (!this.options.database.regionsTableName) { 10761 this.options.database.regionsTableName = "regions_" + this.id; 10762 } 10763 if (!this.options.database.objectsTableName) { 10764 this.options.database.objectsTableName = "objects_" + this.id; 10765 } 10766 this.regionsRepository = new Repository("region", "regions/" + this.options.database.regionsTableName); 10767 this.regionsRepository.query.update({ perpage: 0 }); 10768 this.objectsRepository = new Repository("object", "objects/" + this.options.database.objectsTableName); 10769 if (this.options.database.noFiltersNoLoad) { 10770 this.objectsRepository.setNoFiltersNoLoad(true); 10771 } 10772 this.objectsRepository.query.update({ 10773 perpage: this.options.database.pagination.on 10774 ? this.options.database.pagination.perpage 10775 : 0, 10776 }); 10777 this.schemaRepository = new SchemaRepository(); 10778 this.markers = new ArrayIndexed("id"); 10779 this.markersClusters = new ArrayIndexed("id"); 10780 this._viewBox = new ViewBox(0, 0, 0, 0); 10781 this.viewBox = new ViewBox(0, 0, 0, 0); 10782 this.zoomLevel = 0; 10783 this.scroll = { 10784 tx: 0, 10785 ty: 0, 10786 vxi: 0, 10787 vyi: 0, 10788 x: 0, 10789 y: 0, 10790 dx: 0, 10791 dy: 0, 10792 vx: 0, 10793 vy: 0, 10794 gx: 0, 10795 gy: 0, 10796 touchScrollStart: 0, 10797 }; 10798 this.layers = {}; 10799 this.geoCoordinates = false; 10800 this.geoViewBox = new GeoViewBox(new GeoPoint(0, 0), new GeoPoint(0, 0)); 10801 this.eventsPreventList = {}; 10802 this.googleMaps = { 10803 loaded: false, 10804 initialized: false, 10805 map: null, 10806 zoomLimit: true, 10807 maxZoomService: null, 10808 }; 10809 this.afterLoadBlockers = 1; 10810 this.loaded = false; 10811 if (this.id) { 10812 this.afterLoadBlockers += 2; 10813 } 10814 if (this.options.googleMaps.on) { 10815 this.afterLoadBlockers++; 10816 } 10817 if (this.filtersShouldBeShown()) { 10818 this.afterLoadBlockers++; 10819 } 10820 this.init(); 10821 } 10822 urlToRelativePath(url) { 10823 if (url.indexOf("//") === 0) 10824 url = url.replace(/^\/\/[^/]+/, "").replace("//", "/"); 10825 else 10826 url = url.replace(/^.*:\/\/[^/]+/, "").replace("//", "/"); 10827 return url; 10828 } 10829 setGroups(groups) { 10830 const _this = this; 10831 if (!this.groups) { 10832 _this.groups = new ArrayIndexed("id", _this.options.groups, { 10833 autoId: true, 10834 unique: true, 10835 }); 10836 } 10837 else { 10838 this.options.groups = this.groups; 10839 } 10840 _this.groups.forEach(function (g) { 10841 g.objects && 10842 g.objects.length && 10843 g.objects.forEach(function (obj) { 10844 _this.containers.svg 10845 .querySelector("#" + obj.value) 10846 .classList.toggle("mapsvg-hidden", !g.visible); 10847 }); 10848 }); 10849 } 10850 getGroupSelectOptions() { 10851 const _this = this; 10852 const optionGroups = []; 10853 const options = []; 10854 const options2 = []; 10855 $$A(_this.containers.svg) 10856 .find("g") 10857 .each(function (index) { 10858 const id = $$A(this)[0].getAttribute("id"); 10859 if (id) { 10860 const title = $$A(this)[0].getAttribute("title"); 10861 options.push({ label: title || id, value: id }); 10862 } 10863 }); 10864 optionGroups.push({ title: "SVG Layers / Groups", options: options }); 10865 $$A(_this.containers.svg) 10866 .find("path,ellipse,circle,polyline,polygon,rectangle,img,text") 10867 .each(function (index) { 10868 const id = $$A(this)[0].getAttribute("id"); 10869 if (id) { 10870 const title = $$A(this)[0].getAttribute("title"); 10871 options2.push({ label: title || id, value: id }); 10872 } 10873 }); 10874 optionGroups.push({ title: "Other SVG objects", options: options2 }); 10875 return optionGroups; 10876 } 10877 setLayersControl(options) { 10878 const _this = this; 10879 if (options) 10880 $$A.extend(true, this.options.layersControl, options); 10881 if (this.options.layersControl.on) { 10882 if (!this.containers.layersControl) { 10883 this.containers.layersControl = document.createElement("div"); 10884 this.containers.layersControl.classList.add("mapsvg-layers-control"); 10885 this.containers.layersControlLabel = document.createElement("div"); 10886 this.containers.layersControlLabel.classList.add("mapsvg-layers-label"); 10887 this.containers.layersControl.appendChild(this.containers.layersControlLabel); 10888 const layersControlWrap = document.createElement("div"); 10889 layersControlWrap.classList.add("mapsvg-layers-list-wrap"); 10890 this.containers.layersControl.appendChild(layersControlWrap); 10891 this.containers.layersControlListNano = document.createElement("div"); 10892 this.containers.layersControlListNano.classList.add("nano"); 10893 layersControlWrap.appendChild(this.containers.layersControlListNano); 10894 this.containers.layersControlList = document.createElement("div"); 10895 this.containers.layersControlList.classList.add("mapsvg-layers-list"); 10896 this.containers.layersControlList.classList.add("nano-content"); 10897 this.containers.layersControlListNano.appendChild(this.containers.layersControlList); 10898 this.containers.mapContainer.appendChild(this.containers.layersControl); 10899 } 10900 this.containers.layersControl.style.display = "block"; 10901 this.containers.layersControlLabel.innerHTML = this.options.layersControl.label; 10902 this.containers.layersControlLabel.style.display = "block"; 10903 this.containers.layersControlList.innerHTML = ""; 10904 while (this.containers.layersControlList.firstChild) { 10905 this.containers.layersControlList.removeChild(this.containers.layersControlList.firstChild); 10906 } 10907 this.containers.layersControl.classList.remove("mapsvg-top-left", "mapsvg-top-right", "mapsvg-bottom-left", "mapsvg-bottom-right"); 10908 this.containers.layersControl.classList.add("mapsvg-" + this.options.layersControl.position); 10909 if (this.options.menu.on && 10910 !this.options.menu.customContainer && 10911 this.options.layersControl.position.indexOf("left") !== -1) { 10912 this.containers.layersControl.style.left = this.options.menu.width; 10913 } 10914 this.containers.layersControl.style.maxHeight = this.options.layersControl.maxHeight; 10915 this.options.groups.forEach((g) => { 10916 const item = document.createElement("div"); 10917 item.classList.add("mapsvg-layers-item"); 10918 item.setAttribute("data-group-id", g.id); 10919 item.innerHTML = 10920 '<input type="checkbox" class="ios8-switch ios8-switch-sm" ' + 10921 (g.visible ? "checked" : "") + 10922 " /><label>" + 10923 g.title + 10924 "</label>"; 10925 this.containers.layersControlList.appendChild(item); 10926 }); 10927 $$A(this.containers.layersControlListNano).nanoScroller({ 10928 preventPageScrolling: true, 10929 iOSNativeScrolling: true, 10930 }); 10931 $$A(this.containers.layersControl).off(); 10932 $$A(this.containers.layersControl).on("click", ".mapsvg-layers-item", function () { 10933 const id = $$A(this).data("group-id"); 10934 const input = $$A(this).find("input"); 10935 input.prop("checked", !input.prop("checked")); 10936 _this.groups.forEach(function (g) { 10937 if (g.id === id) 10938 g.visible = !g.visible; 10939 }); 10940 _this.setGroups(); 10941 }); 10942 $$A(this.containers.layersControlLabel).off(); 10943 $$A(this.containers.layersControlLabel).on("click", () => { 10944 $$A(_this.containers.layersControl).toggleClass("closed"); 10945 }); 10946 $$A(this.containers.layersControl).toggleClass("closed", !this.options.layersControl.expanded); 10947 } 10948 else { 10949 if (this.containers.layersControl) { 10950 this.containers.layersControl.style.display = "none"; 10951 } 10952 } 10953 }
10954 loadDataObjects(params) { 10955 return this.objectsRepository.find(params); 10956 } 10957 loadDirectory() { 10958 if (!this.editMode && 10959 this.options.menu.source === "database" && 10960 !this.objectsRepository.loaded) { 10961 return; 10962 } 10963 if (this.options.menu.on) { 10964 this.controllers.directory.loadItemsToDirectory(); 10965 } 10966 this.setPagination(); 10967 } 10968 setPagination() { 10969 const _this = this; 10970 this.containers.pagerMap && $$A(this.containers.pagerMap).empty().remove(); 10971 this.containers.pagerDir && $$A(this.containers.pagerDir).empty().remove(); 10972 if (_this.options.database.pagination.on && 10973 _this.options.database.pagination.perpage !== 0) { 10974 this.containers.directory.classList.toggle("mapsvg-with-pagination", ["directory", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10975 this.containers.map.classList.toggle("mapsvg-with-pagination", ["map", "both"].indexOf(_this.options.database.pagination.showIn) !== -1); 10976 if (_this.options.menu.on) { 10977 this.containers.pagerDir = _this.getPagination(); 10978 _this.controllers.directory.addPagination(this.containers.pagerDir); 10979 } 10980 this.containers.pagerMap = _this.getPagination(); 10981 this.containers.map.appendChild(this.containers.pagerMap); 10982 } 10983 } 10984 getPagination(callback) { 10985 const _this = this; 10986 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="#">← ' + 10987 _this.options.database.pagination.prev + 10988 " " + 10989 _this.options.database.pagination.perpage + 10990 '</a></li><li class="mapsvg-next"><a href="#">' + 10991 _this.options.database.pagination.next + 10992 " " + 10993 _this.options.database.pagination.perpage + 10994 ' →</a></li><!--<li class="mapsvg-last"><a href="#">Last</a></li>--></ul></nav>'); 10995 if (this.objectsRepository.onFirstPage() && this.objectsRepository.onLastPage()) { 10996 pager.hide(); 10997 } 10998 else { 10999 pager.find(".mapsvg-prev").removeClass("disabled"); 11000 pager.find(".mapsvg-first").removeClass("disabled"); 11001 pager.find(".mapsvg-last").removeClass("disabled"); 11002 pager.find(".mapsvg-next").removeClass("disabled"); 11003 this.objectsRepository.onLastPage() && 11004 pager.find(".mapsvg-next").addClass("disabled") && 11005 pager.find(".mapsvg-last").addClass("disabled"); 11006 this.objectsRepository.onFirstPage() && 11007 pager.find(".mapsvg-prev").addClass("disabled") && 11008 pager.find(".mapsvg-first").addClass("disabled"); 11009 } 11010 pager 11011 .on("click", ".mapsvg-next:not(.disabled)", (e) => { 11012 e.preventDefault(); 11013 if (this.objectsRepository.onLastPage()) 11014 return; 11015 const query = new Query({ page: this.objectsRepository.query.page + 1 }); 11016 this.objectsRepository.find(query).done(function () { 11017 callback && callback(); 11018 }); 11019 }) 11020 .on("click", ".mapsvg-prev:not(.disabled)", function (e) { 11021 e.preventDefault(); 11022 if (_this.objectsRepository.onFirstPage()) 11023 return; 11024 const query = new Query({ page: _this.objectsRepository.query.page - 1 }); 11025 _this.objectsRepository.find(query).done(function () { 11026 callback && callback(); 11027 }); 11028 }) 11029 .on("click", ".mapsvg-first:not(.disabled)", function (e) { 11030 e.preventDefault(); 11031 if (_this.objectsRepository.onFirstPage()) 11032 return; 11033 const query = new Query({ page: 1 }); 11034 _this.objectsRepository.find(query).done(function () { 11035 callback && callback(); 11036 }); 11037 }) 11038 .on("click", ".mapsvg-last:not(.disabled)", function (e) { 11039 e.preventDefault(); 11040 if (_this.objectsRepository.onLastPage()) 11041 return; 11042 const query = new Query({ lastpage: true }); 11043 _this.objectsRepository.find(query).done(function () { 11044 callback && callback(); 11045 }); 11046 }); 11047 return pager[0]; 11048 } 11049 deleteMarkers() { 11050 while (this.markers.length) { 11051 this.markerDelete(this.markers[0]); 11052 } 11053 }
11054 deleteClusters() { 11055 if (this.markersClusters) { 11056 this.markersClusters.forEach(function (markerCluster) { 11057 markerCluster.destroy(); 11058 }); 11059 this.markersClusters.clear(); 11060 } 11061 } 11062 addLocations() { 11063 const _this = this; 11064 this.firstDataLoad = this.firstDataLoad === undefined; 11065 let locationField = this.objectsRepository.getSchema().getFieldByType("location"); 11066 if (!locationField) { 11067 return; 11068 } 11069 locationField = locationField.name; 11070 if (locationField) { 11071 if (this.firstDataLoad) { 11072 this.setMarkerImagesDependency(); 11073 } 11074 _this.deleteMarkers(); 11075 _this.deleteClusters(); 11076 _this.clusters = {}; 11077 _this.clustersByZoom = []; 11078 if (this.objectsRepository.getLoaded().length > 0) { 11079 this.objectsRepository.getLoaded().forEach(function (object) { 11080 if (object[locationField]) { 11081 if (object[locationField].img && 11082 (object[locationField].geoPoint || object[locationField].svgPoint)) { 11083 new Marker({ 11084 location: object[locationField], 11085 object: object, 11086 mapsvg: _this, 11087 }); 11088 } 11089 } 11090 }); 11091 if (_this.options.clustering.on) { 11092 _this.startClusterizer(); 11093 } 11094 else { 11095 this.objectsRepository.getLoaded().forEach(function (object) { 11096 if (object.location && object.location.marker) { 11097 _this.markerAdd(object.location.marker); 11098 } 11099 }); 11100 _this.mayBeFitMarkers(); 11101 } 11102 } 11103 } 11104 } 11105 addClustersFromWorker(zoomLevel, clusters) { 11106 const _this = this; 11107 _this.clustersByZoom[zoomLevel] = []; 11108 for (const cell in clusters) { 11109 const markers = clusters[cell].markers.map(function (marker) { 11110 return _this.objectsRepository.objects.findById(marker.id).location.marker; 11111 }); 11112 _this.clustersByZoom[zoomLevel].push(new MarkerCluster({ 11113 markers: markers, 11114 svgPoint: new SVGPoint(clusters[cell].x, clusters[cell].y), 11115 cellX: clusters[cell].cellX, 11116 cellY: clusters[cell].cellY, 11117 }, _this)); 11118 } 11119 if (_this.zoomLevel === zoomLevel) { 11120 _this.clusterizeMarkers(); 11121 } 11122 } 11123 startClusterizer() { 11124 if (!this.objectsRepository || this.objectsRepository.getLoaded().length === 0) { 11125 return; 11126 } 11127 const locationField = this.objectsRepository.getSchema().getFieldByType("location"); 11128 if (!locationField) { 11129 return false; 11130 } 11131 if (!this.clusterizerWorker) { 11132 this.clusterizerWorker = new Worker(MapSVG.urls.root + "js/mapsvg/Core/clustering.js"); 11133 this.clusterizerWorker.onmessage = (evt) => { 11134 if (evt.data.clusters) { 11135 this.addClustersFromWorker(evt.data.zoomLevel, evt.data.clusters); 11136 } 11137 }; 11138 } 11139 const objectsData = []; 11140 this.objectsRepository 11141 .getLoaded() 11142 .filter((o) => { 11143 return o.location && o.location.marker; 11144 }) 11145 .forEach((o) => { 11146 objectsData.push({ 11147 id: o.id, 11148 x: o.location.marker.svgPoint.x, 11149 y: o.location.marker.svgPoint.y, 11150 }); 11151 }); 11152 this.clusterizerWorker.postMessage({ 11153 objects: objectsData, 11154 cellSize: 50, 11155 mapWidth: this.containers.map.clientWidth, 11156 zoomLevels: this.zoomLevels, 11157 zoomLevel: this.zoomLevel, 11158 zoomDelta: this.zoomDelta, 11159 svgViewBox: this.svgDefault.viewBox, 11160 }); 11161 this.events.on("zoom", () => { 11162 this.clusterizerWorker.postMessage({ 11163 message: "zoom", 11164 zoomLevel: this.zoomLevel, 11165 }); 11166 }); 11167 } 11168 clusterizeMarkers(skipFitMarkers) { 11169 $$A(this.layers.markers) 11170 .children() 11171 .each((i, obj) => { 11172 $$A(obj).detach(); 11173 }); 11174 this.markers.clear(); 11175 this.markersClusters.clear();
11176 this.clustersByZoom && 11177 this.clustersByZoom[this.zoomLevel] && 11178 this.clustersByZoom[this.zoomLevel].forEach((cluster) => { 11179 if (this.options.googleMaps.on && 11180 this.googleMaps.map && 11181 this.googleMaps.map.getZoom() >= 17) { 11182 this.markerAdd(cluster.markers[0]); 11183 } 11184 else { 11185 if (cluster.markers.length > 1) { 11186 this.markersClusterAdd(cluster); 11187 } 11188 else { 11189 this.markerAdd(cluster.markers[0]); 11190 } 11191 } 11192 }); 11193 if (this.editingMarker) { 11194 this.markerAdd(this.editingMarker); 11195 } 11196 if (!skipFitMarkers) { 11197 this.mayBeFitMarkers(); 11198 } 11199 if (this.options.labelsMarkers.on) { 11200 this.setLabelsMarkers(); 11201 } 11202 } 11203 getCssUrl() { 11204 return MapSVG.urls.root + "css/mapsvg.css"; 11205 } 11206 isGeo() { 11207 return this.mapIsGeo; 11208 } 11209 functionFromString(string) { 11210 let func; 11211 let error; 11212 const fn = string.trim(); 11213 if (fn.indexOf("{") == -1 || fn.indexOf("function") !== 0 || fn.indexOf("(") == -1) { 11214 return new SyntaxError("MapSVG user function error: no function body."); 11215 } 11216 const fnBody = fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")); 11217 const params = fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")); 11218 try { 11219 func = new Function(params, fnBody); 11220 } 11221 catch (err) { 11222 error = err; 11223 } 11224 if (!error) 11225 return func; 11226 else 11227 return error; 11228 } 11229 getOptions(forTemplate, forWeb) { 11230 const options = $$A.extend(true, {}, this.options); 11231 function clearEmpties(o) { 11232 for (const k in o) { 11233 if (!o[k] || typeof o[k] !== "object") { 11234 continue; 11235 } 11236 clearEmpties(o[k]); 11237 if (Object.keys(o[k]).length === 0) { 11238 delete o[k]; 11239 } 11240 } 11241 } 11242 clearEmpties(options.regions); 11243 $$A.extend(true, options, this.optionsDelta); 11244 options.viewBox = this._viewBox.toArray(); 11245 options.filtersSchema = this.filtersSchema.getFieldsAsArray(); 11246 if (options.filtersSchema.length > 0) { 11247 options.filtersSchema.forEach((field) => { 11248 if (field.type === "distance") { 11249 field.value = ""; 11250 } 11251 }); 11252 } 11253 delete options.markers; 11254 if (forTemplate) { 11255 options.svgFilename = options.source.split("/").pop(); 11256 options.svgFiles = MapSVG.svgFiles; 11257 } 11258 if (forWeb) 11259 $$A.each(options, (key, val) => { 11260 if (JSON.stringify(val) == JSON.stringify(this.defaults[key])) 11261 delete options[key]; 11262 }); 11263 delete options.backend; 11264 return options; 11265 } 11266 restoreDeltaOptions() { 11267 this.update(this.optionsDelta); 11268 this.optionsDelta = {}; 11269 } 11270 setEvents(functions) { 11271 let compiledFunction; 11272 for (const eventName in functions) { 11273 if (typeof functions[eventName] === "string") { 11274 compiledFunction = 11275 functions[eventName] != "" 11276 ? this.functionFromString(functions[eventName]) 11277 : null; 11278 if (!compiledFunction || 11279 compiledFunction.error || 11280 compiledFunction instanceof TypeError || 11281 compiledFunction instanceof SyntaxError) { 11282 continue; 11283 } 11284 } 11285 else if (typeof functions[eventName] === "function") { 11286 compiledFunction = functions[eventName]; 11287 } 11288 this.events.off(eventName); 11289 this.events.on(eventName, compiledFunction); 11290 if (eventName.indexOf("directory") !== -1) { 11291 const event = eventName.split(".")[0]; 11292 if (this.controllers && this.controllers.directory) { 11293 this.controllers.directory.events.off(event); 11294 this.controllers.directory.events.on(event, compiledFunction); 11295 } 11296 } 11297 } 11298 $$A.extend(true, this.options.events, functions); 11299 }
11300 setActions(options) { 11301 $$A.extend(true, this.options.actions, options); 11302 } 11303 setDetailsView(options) { 11304 options = options || this.options.detailsView || {}; 11305 $$A.extend(true, this.options.detailsView, options); 11306 if (this.options.detailsView.location === "top" && this.options.menu.position === "left") { 11307 this.options.detailsView.location = "leftSidebar"; 11308 } 11309 else if (this.options.detailsView.location === "top" && 11310 this.options.menu.position === "right") { 11311 this.options.detailsView.location = "rightSidebar"; 11312 } 11313 if (this.options.detailsView.location === "near" || 11314 this.options.detailsView.location === "mapContainer") { 11315 this.options.detailsView.location = "map"; 11316 } 11317 if (!this.containers.detailsView) { 11318 this.containers.detailsView = $$A('<div class="mapsvg-details-container"></div>')[0]; 11319 } 11320 $$A(this.containers.detailsView).toggleClass("mapsvg-details-container-relative", !(MapSVG.isPhone && this.options.detailsView.mobileFullscreen) && 11321 !this.shouldBeScrollable(this.options.detailsView.location)); 11322 if (this.options.detailsView.location === "custom") { 11323 $$A("#" + this.options.detailsView.containerId).append($$A(this.containers.detailsView)); 11324 } 11325 else { 11326 if (MapSVG.isPhone && this.options.detailsView.mobileFullscreen) { 11327 $$A("body").append($$A(this.containers.detailsView)); 11328 $$A(this.containers.detailsView).addClass("mapsvg-container-fullscreen"); 11329 } 11330 else { 11331 this.containers[this.options.detailsView.location].append(this.containers.detailsView); 11332 } 11333 if (this.options.detailsView.margin) { 11334 $$A(this.containers.detailsView).css("margin", this.options.detailsView.margin); 11335 } 11336 $$A(this.containers.detailsView).css("width", this.options.detailsView.width); 11337 } 11338 } 11339 setMobileView(options) { 11340 $$A.extend(true, this.options.mobileView, options); 11341 } 11342 attachDataToRegions(object) { 11343 this.regions.forEach(function (region) { 11344 region.objects = []; 11345 }); 11346 this.objectsRepository.getLoaded().forEach((obj, index) => { 11347 const regions = obj.getRegionsForTable(this.options.database.regionsTableName); 11348 if (regions && regions.length) { 11349 regions.forEach((region) => { 11350 const r = this.getRegion(region.id); 11351 if (r) 11352 r.objects.push(obj); 11353 }); 11354 } 11355 }); 11356 } 11357 setTemplates(templates) { 11358 this.templates = this.templates || {}; 11359 for (let name in templates) { 11360 if (name != undefined) { 11361 this.options.templates[name] = templates[name]; 11362 let t = this.options.templates[name]; 11363 if (name == "directoryItem" || name == "directoryCategoryItem") { 11364 const dirItemTemplate = this.options.templates.directoryItem; 11365 t = 11366 '{{#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}}">' + 11367 dirItemTemplate + 11368 "</div>{{/each}}"; 11369 if (this.options.menu.categories && 11370 this.options.menu.categories.on && 11371 this.options.menu.categories.groupBy) { 11372 const t2 = this.options.templates["directoryCategoryItem"]; 11373 t = 11374 '{{#each items}}{{#with category}}<div id="mapsvg-category-item-{{value}}" class="mapsvg-category-item" data-category-value="{{value}}">' + 11375 t2 + 11376 '</div><div class="mapsvg-category-block" data-category-id="{{value}}">{{/with}}' + 11377 t + 11378 "</div>{{/each}}"; 11379 } 11380 name = "directory"; 11381 } 11382 try { 11383 this.options.templates[name] = t; 11384 this.templates[name] = Handlebars.compile(t, { strict: false }); 11385 } 11386 catch (err) { 11387 console.error(err); 11388 this.templates[name] = Handlebars.compile("", { strict: false }); 11389 } 11390 if (this.editMode && 11391 (name == "directory" || name == "directoryCategoryItem") && 11392 this.controllers && 11393 this.controllers.directory) { 11394 this.controllers.directory.templates.main = this.templates[name]; 11395 this.loadDirectory(); 11396 } 11397 } 11398 } 11399 } 11400 update(options) { 11401 for (const key in options) { 11402 if (key == "regions") { 11403 for (const id in options.regions) { 11404 const region = this.getRegion(id); 11405 region && region.update(options.regions[id]); 11406 if (options.regions[id].disabled != undefined) { 11407 this.deselectRegion(region); 11408 this.options.regions[id] = this.options.regions[id] || {}; 11409 this.options.regions[id].disabled = region.disabled; 11410 } 11411 } 11412 } 11413 else { 11414 const setter = "set" + MapSVG.ucfirst(key); 11415 if (typeof this[setter] == "function") 11416 this[setter](options[key]); 11417 else { 11418 this.options[key] = options[key]; 11419 } 11420 } 11421 } 11422 } 11423 getDirtyFields() { 11424 return this.getData(); 11425 } 11426 clearDirtyFields() { 11427 this.dirtyFields = []; 11428 } 11429 setTitle(title) { 11430 title && (this.options.title = title); 11431 } 11432 setExtension(extension) { 11433 if (extension) { 11434 this.options.extension = extension; 11435 } 11436 else { 11437 delete this.options.extension; 11438 } 11439 } 11440 setDisableLinks(on) { 11441 on = MapSVG.parseBoolean(on); 11442 if (on) { 11443 $$A(this.containers.map).on("click.a.mapsvg", "a", function (e) { 11444 e.preventDefault(); 11445 }); 11446 } 11447 else { 11448 $$A(this.containers.map).off("click.a.mapsvg"); 11449 } 11450 this.disableLinks = on; 11451 }
11452 setLoadingText(val) { 11453 this.options.loadingText = val; 11454 } 11455 setLockAspectRatio(onoff) { 11456 this.options.lockAspectRatio = MapSVG.parseBoolean(onoff); 11457 } 11458 setMarkerEditHandler(handler) { 11459 this.markerEditHandler = handler; 11460 } 11461 setChoroplethSourceField(field) { 11462 this.options.choropleth.sourceField = field; 11463 this.redrawChoropleth(); 11464 } 11465 setRegionEditHandler(handler) { 11466 this.regionEditHandler = handler; 11467 } 11468 setDisableAll(on) { 11469 on = MapSVG.parseBoolean(on); 11470 $$A.extend(true, this.options, { disableAll: on }); 11471 $$A(this.containers.map).toggleClass("mapsvg-disabled-regions", on); 11472 } 11473 setRegionStatuses(_statuses) { 11474 this.options.regionStatuses = {}; 11475 const colors = {}; 11476 _statuses.forEach((statusOptions) => { 11477 this.options.regionStatuses[statusOptions.value] = statusOptions; 11478 colors[statusOptions.value] = statusOptions.color.length 11479 ? statusOptions.color 11480 : undefined; 11481 }); 11482 this.setColors({ status: colors }); 11483 } 11484 setColorsIgnore(val) { 11485 this.options.colorsIgnore = MapSVG.parseBoolean(val); 11486 this.regionsRedrawColors(); 11487 } 11488 setColors(colors) { 11489 for (const i in colors) { 11490 if (i === "status") { 11491 for (const s in colors[i]) { 11492 MapSVG.fixColorHash(colors[i][s]); 11493 } 11494 } 11495 else { 11496 if (typeof colors[i] == "string") { 11497 MapSVG.fixColorHash(colors[i]); 11498 } 11499 } 11500 } 11501 $$A.extend(true, this.options, { colors: colors }); 11502 if (colors && colors.status) 11503 this.options.colors.status = colors.status; 11504 if (this.options.colors.markers) { 11505 for (const z in this.options.colors.markers) { 11506 for (const x in this.options.colors.markers[z]) { 11507 this.options.colors.markers[z][x] = parseInt(this.options.colors.markers[z][x]); 11508 } 11509 } 11510 } 11511 if (this.options.colors.background) 11512 $$A(this.containers.map).css({ background: this.options.colors.background }); 11513 if (this.options.colors.hover) { 11514 this.options.colors.hover = !isNaN(this.options.colors.hover) 11515 ? parseInt(this.options.colors.hover + "") 11516 : this.options.colors.hover; 11517 } 11518 if (this.options.colors.selected) { 11519 this.options.colors.selected = !isNaN(this.options.colors.selected) 11520 ? parseInt(this.options.colors.selected + "") 11521 : this.options.colors.selected; 11522 } 11523 $$A(this.containers.leftSidebar).css({ 11524 "background-color": this.options.colors.leftSidebar, 11525 }); 11526 $$A(this.containers.rightSidebar).css({ 11527 "background-color": this.options.colors.rightSidebar, 11528 }); 11529 $$A(this.containers.header).css({ "background-color": this.options.colors.header }); 11530 $$A(this.containers.footer).css({ "background-color": this.options.colors.footer }); 11531 if ($$A(this.containers.detailsView) && this.options.colors.detailsView !== undefined) { 11532 $$A(this.containers.detailsView).css({ 11533 "background-color": this.options.colors.detailsView, 11534 }); 11535 } 11536 if ($$A(this.containers.directory) && this.options.colors.directory !== undefined) { 11537 $$A(this.containers.directory).css({ 11538 "background-color": this.options.colors.directory, 11539 }); 11540 } 11541 if ($$A(this.containers.filtersModal) && this.options.colors.modalFilters !== undefined) { 11542 $$A(this.containers.filtersModal).css({ 11543 "background-color": this.options.colors.modalFilters, 11544 }); 11545 } 11546 if ($$A(this.containers.filters) && this.options.colors.directorySearch) { 11547 $$A(this.containers.filters).css({ 11548 "background-color": this.options.colors.directorySearch, 11549 }); 11550 } 11551 else if ($$A(this.containers.filters)) { 11552 $$A(this.containers.filters).css({ 11553 "background-color": "", 11554 }); 11555 }
11556 if (!this.containers.clustersCss) { 11557 this.containers.clustersCss = ($$A("<style></style>").appendTo("body")[0]); 11558 } 11559 let css = ""; 11560 if (this.options.colors.clusters) { 11561 css += "background-color: " + this.options.colors.clusters + ";"; 11562 } 11563 if (this.options.colors.clustersBorders) { 11564 css += "border-color: " + this.options.colors.clustersBorders + ";"; 11565 } 11566 if (this.options.colors.clustersText) { 11567 css += "color: " + this.options.colors.clustersText + ";"; 11568 } 11569 $$A(this.containers.clustersCss).html(".mapsvg-marker-cluster {" + css + "}"); 11570 if (!this.containers.clustersHoverCss) { 11571 this.containers.clustersHoverCss = ($$A("<style></style>").appendTo("body")[0]); 11572 } 11573 let cssHover = ""; 11574 if (this.options.colors.clustersHover) { 11575 cssHover += "background-color: " + this.options.colors.clustersHover + ";"; 11576 } 11577 if (this.options.colors.clustersHoverBorders) { 11578 cssHover += "border-color: " + this.options.colors.clustersHoverBorders + ";"; 11579 } 11580 if (this.options.colors.clustersHoverText) { 11581 cssHover += "color: " + this.options.colors.clustersHoverText + ";"; 11582 } 11583 $$A(this.containers.clustersHoverCss).html(".mapsvg-marker-cluster:hover {" + cssHover + "}"); 11584 if (!this.containers.markersCss) { 11585 this.containers.markersCss = $$A("<style></style>").appendTo("head")[0]; 11586 } 11587 const markerCssText = ".mapsvg-with-marker-active .mapsvg-marker {\n" + 11588 " opacity: " + 11589 this.options.colors.markers.inactive.opacity / 100 + 11590 ";\n" + 11591 " -webkit-filter: grayscale(" + 11592 (100 - this.options.colors.markers.inactive.saturation) + 11593 "%);\n" + 11594 " filter: grayscale(" + 11595 (100 - this.options.colors.markers.inactive.saturation) + 11596 "%);\n" + 11597 "}\n" + 11598 ".mapsvg-with-marker-active .mapsvg-marker-active {\n" + 11599 " opacity: " + 11600 this.options.colors.markers.active.opacity / 100 + 11601 ";\n" + 11602 " -webkit-filter: grayscale(" + 11603 (100 - this.options.colors.markers.active.saturation) + 11604 "%);\n" + 11605 " filter: grayscale(" + 11606 (100 - this.options.colors.markers.active.saturation) + 11607 "%);\n" + 11608 "}\n" + 11609 ".mapsvg-with-marker-hover .mapsvg-marker {\n" + 11610 " opacity: " + 11611 this.options.colors.markers.unhovered.opacity / 100 + 11612 ";\n" + 11613 " -webkit-filter: grayscale(" + 11614 (100 - this.options.colors.markers.unhovered.saturation) + 11615 "%);\n" + 11616 " filter: grayscale(" + 11617 (100 - this.options.colors.markers.unhovered.saturation) + 11618 "%);\n" + 11619 "}\n" + 11620 ".mapsvg-with-marker-hover .mapsvg-marker-hover {\n" + 11621 " opacity: " + 11622 this.options.colors.markers.hovered.opacity / 100 + 11623 ";\n" + 11624 " -webkit-filter: grayscale(" + 11625 (100 - this.options.colors.markers.hovered.saturation) + 11626 "%);\n" + 11627 " filter: grayscale(" + 11628 (100 - this.options.colors.markers.hovered.saturation) + 11629 "%);\n" + 11630 "}\n"; 11631 $$A(this.containers.markersCss).html(markerCssText); 11632 $$A.each(this.options.colors, (key, color) => { 11633 if (color === null || color == "") 11634 delete this.options.colors[key]; 11635 }); 11636 this.regionsRedrawColors(); 11637 } 11638 setTooltips(options) { 11639 if (options.on !== undefined) 11640 options.on = MapSVG.parseBoolean(options.on); 11641 $$A.extend(true, this.options, { tooltips: options }); 11642 if (!this.containers.tooltip) { 11643 this.containers.tooltip = $$A("<div />").addClass("mapsvg-tooltip")[0]; 11644 $$A(this.containers.map).append(this.containers.tooltip); 11645 this.controllers.tooltip = new Tooltip({ 11646 mapsvg: this, 11647 container: this.containers.tooltip, 11648 position: this.options.tooltips.position, 11649 maxWidth: this.options.tooltips.maxWidth, 11650 minWidth: this.options.tooltips.minWidth, 11651 }); 11652 this.controllers.tooltip._init(); 11653 } 11654 if (typeof this.options.tooltips.position !== "undefined") { 11655 this.controllers.tooltip.setPosition(this.options.tooltips.position); 11656 } 11657 if (typeof this.options.tooltips.maxWidth !== "undefined" || 11658 typeof this.options.tooltips.minWidth !== "undefined") { 11659 this.controllers.tooltip.setSize(this.options.tooltips.minWidth, this.options.tooltips.maxWidth); 11660 } 11661 } 11662 setPopovers(options) { 11663 if (options.on !== undefined) 11664 options.on = MapSVG.parseBoolean(options.on); 11665 $$A.extend(this.options.popovers, options); 11666 if (!this.containers.popover) { 11667 this.containers.popover = $$A("<div />").addClass("mapsvg-popover")[0]; 11668 this.layers.popovers.append(this.containers.popover); 11669 } 11670 $$A(this.containers.popover).css({ 11671 width: this.options.popovers.width + (this.options.popovers.width == "auto" ? "" : "px"), 11672 "max-width": this.options.popovers.maxWidth + "%", 11673 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 100 + 11674 "px", 11675 }); 11676 if (this.options.popovers.mobileFullscreen && MapSVG.
11676isPhone) { 11677 $$A("body").toggleClass("mapsvg-fullscreen-popovers", true); 11678 $$A(this.containers.popover).appendTo("body"); 11679 } 11680 } 11681 setRegionPrefix(prefix) { 11682 this.options.regionPrefix = prefix; 11683 } 11684 setInitialViewBox(v) { 11685 if (typeof v == "string") 11686 v = v 11687 .trim() 11688 .split(" ") 11689 .map(function (v) { 11690 return parseFloat(v); 11691 }); 11692 this._viewBox.update(new ViewBox(v)); 11693 if (this.options.googleMaps.on) { 11694 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 11695 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 11696 } 11697 this.zoomLevel = 0; 11698 this.setZoomLevels(); 11699 } 11700 setViewBoxOnStart() { 11701 this.viewBoxFull = this.svgDefault.viewBox; 11702 this.viewBoxFake = this.viewBox; 11703 this.whRatioFull = this.viewBoxFull.width / this.viewBox.width; 11704 this.containers.svg.setAttribute("viewBox", this.viewBoxFull.toString()); 11705 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11706 this.iosDownscaleFactor = this.svgDefault.viewBox.width > 9999 ? 100 : 10; 11707 this.containers.svg.style.width = 11708 (this.svgDefault.viewBox.width / this.iosDownscaleFactor).toString() + "px"; 11709 } 11710 else { 11711 this.containers.svg.style.width = this.svgDefault.viewBox.width + "px"; 11712 } 11713 this.vbStart = true; 11714 } 11715 setViewBox(viewBox, adjustGoogleMap = true) { 11716 let initial = false; 11717 if (typeof viewBox === "undefined" || (viewBox.width === 0 && viewBox.height === 0)) {
11718 viewBox = this.svgDefault.viewBox; 11719 initial = true; 11720 } 11721 const isZooming = viewBox.width != this.viewBox.width || viewBox.height != this.viewBox.height; 11722 this.viewBox.update(viewBox); 11723 this.whRatio = this.viewBox.width / this.viewBox.height; 11724 !this.vbStart && this.setViewBoxOnStart(); 11725 if (initial) { 11726 if (this._viewBox.width === 0 && this._viewBox.height === 0) { 11727 this._viewBox.update(this.viewBox); 11728 } 11729 this._scale = 1; 11730 } 11731 this.scale = this.getScale(); 11732 this.superScale = (this.whRatioFull * this.svgDefault.viewBox.width) / this.viewBox.width; 11733 const w = this.svgDefault.viewBox.width / this.containers.map.clientWidth; 11734 this.superScale = this.superScale / w; 11735 if ((MapSVG.device.ios || MapSVG.device.android) && this.svgDefault.viewBox.width > 1500) { 11736 this.superScale *= this.iosDownscaleFactor; 11737 } 11738 this.scroll.tx = Math.round((this.svgDefault.viewBox.x - this.viewBox.x) * this.scale); 11739 this.scroll.ty = Math.round((this.svgDefault.viewBox.y - this.viewBox.y) * this.scale); 11740 if (this.googleMaps.map && adjustGoogleMap !== false) { 11741 const googlePrevZoom = this.googleMaps.map.getZoom(); 11742 this.googleMaps.map.setCenter(this.getCenterGeoPoint()); 11743 this.googleMaps.map.setZoom(this.getZoomForGoogle()); 11744 } 11745 else { 11746 this.containers.scrollpane.style.transform = 11747 "translate(" + this.scroll.tx + "px," + this.scroll.ty + "px)"; 11748 this.containers.svg.style.transform = "scale(" + this.superScale + ")"; 11749 this.syncZoomLevelWithGoogle(); 11750 } 11751 this.movingItemsAdjustScreenPosition(); 11752 if (isZooming) { 11753 this.adjustStrokes(); 11754 this.toggleSvgLayerOnZoom(); 11755 if (this.options.clustering.on) { 11756 this.throttle(this.clusterizeOnZoom, 400, this); 11757 } 11758 else { 11759 this.events.trigger("zoom"); 11760 } 11761 } 11762 return true; 11763 } 11764 syncZoomLevelWithGoogle() { 11765 if (this.googleMaps.map && 11766 this.googleMaps.map.getZoom() !== this.getZoomForGoogle() && 11767 typeof this.zoomDelta !== "undefined") { 11768 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11769 } 11770 } 11771 getCenterGeoPoint() { 11772 return this.converter.convertSVGToGeo(this.getCenterSvgPoint()); 11773 } 11774 getCenterSvgPoint() { 11775 return new SVGPoint(this.viewBox.x + this.viewBox.width / 2, this.viewBox.y + this.viewBox.height / 2); 11776 } 11777 getZoomForGoogle() { 11778 if (typeof this.zoomLevel === "string") { 11779 this.zoomLevel = parseInt(this.zoomLevel); 11780 } 11781 return this.zoomLevel + this.zoomDelta; 11782 } 11783 getZoomRange() { 11784 const range = { min: 0, max: 0 }; 11785 if (this.options.googleMaps.on) { 11786 range.min = Math.max(0, this.options.zoom.limit[0] + this.zoomDelta) - this.zoomDelta; 11787 range.max = Math.min(22, this.options.zoom.limit[1] + this.zoomDelta) - this.zoomDelta; 11788 } 11789 else { 11790 range.min = this.options.zoom.limit[0]; 11791 range.max = this.options.zoom.limit[1]; 11792 } 11793 return range; 11794 } 11795 enableMovingElementsAnimation() { 11796 $$A(this.containers.map).removeClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11797 } 11798 disableMovingElementsAnimation() { 11799 $$A(this.containers.map).addClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11800 } 11801 clusterizeOnZoom() { 11802 if (this.options.googleMaps.on && this.googleMaps.map && this.zoomDelta) { 11803 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11804 } 11805 this.events.trigger("zoom"); 11806 this.clusterizeMarkers(true); 11807 } 11808 throttle(method, delay, scope, params) { 11809 clearTimeout(method._tId); 11810 method._tId = setTimeout(function () { 11811 method.apply(scope, params); 11812 }, delay); 11813 }
11814 setViewBoxByGoogleMapBounds() { 11815 const googleMapBounds = this.googleMaps.map.getBounds(); 11816 if (!googleMapBounds) 11817 return; 11818 const googleMapBoundsJSON = googleMapBounds.toJSON(); 11819 if (googleMapBoundsJSON.west == -180 && googleMapBoundsJSON.east == 180) { 11820 const center = this.googleMaps.map.getCenter().toJSON(); 11821 } 11822 const ne = new GeoPoint(googleMapBounds.getNorthEast().lat(), googleMapBounds.getNorthEast().lng()); 11823 const sw = new GeoPoint(googleMapBounds.getSouthWest().lat(), googleMapBounds.getSouthWest().lng()); 11824 const xyNE = this.converter.convertGeoToSVG(ne); 11825 const xySW = this.converter.convertGeoToSVG(sw); 11826 if (xyNE.x < xySW.y) { 11827 const mapPointsWidth = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 360; 11828 xySW.x = -(mapPointsWidth - xySW.y); 11829 } 11830 const width = xyNE.x - xySW.x; 11831 const height = xySW.y - xyNE.y; 11832 const viewBox = new ViewBox(xySW.x, xyNE.y, width, height); 11833 this.setViewBox(viewBox); 11834 } 11835 redraw() { 11836 this.disableAnimation(); 11837 if (MapSVG.browser.ie) { 11838 $$A(this.containers.svg).css({ height: this.svgDefault.viewBox.height }); 11839 } 11840 if (this.options.googleMaps.on && this.googleMaps.map) { 11841 google.maps.event.trigger(this.googleMaps.map, "resize"); 11842 } 11843 else { 11844 this.setViewBox(this.viewBox); 11845 } 11846 $$A(this.containers.popover) && 11847 $$A(this.containers.popover).css({ 11848 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 11849 100 + 11850 "px", 11851 }); 11852 if (this.controllers && this.controllers.directory) { 11853 this.controllers.directory.updateTopShift(); 11854 this.controllers.directory.updateScroll(); 11855 } 11856 this.movingItemsAdjustScreenPosition(); 11857 this.adjustStrokes(); 11858 this.enableAnimation(); 11859 } 11860 setSize(width, height, responsive) { 11861 this.options.width = width; 11862 this.options.height = height; 11863 this.options.responsive = 11864 responsive != null && responsive != undefined 11865 ? MapSVG.parseBoolean(responsive) 11866 : this.options.responsive; 11867 if (!this.options.width && !this.options.height) { 11868 this.options.width = this.svgDefault.width; 11869 this.options.height = this.svgDefault.height; 11870 } 11871 else if (!this.options.width && this.options.height) { 11872 this.options.width = 11873 (this.options.height * this.svgDefault.width) / this.svgDefault.height; 11874 } 11875 else if (this.options.width && !this.options.height) { 11876 this.options.height = 11877 (this.options.width * this.svgDefault.height) / this.svgDefault.width; 11878 } 11879 this.whRatio = this.options.width / this.options.height; 11880 this.scale = this.getScale(); 11881 this.setResponsive(responsive); 11882 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 11883 this.redrawBubbles(); 11884 } 11885 this.movingItemsAdjustScreenPosition(); 11886 } 11887 setResponsive(on) { 11888 on = on != undefined ? MapSVG.parseBoolean(on) : this.options.responsive; 11889 $$A(this.containers.map).css({ 11890 width: "100%", 11891 height: "0", 11892 "padding-bottom": (this.viewBox.height * 100) / this.viewBox.width + "%", 11893 }); 11894 if (on) { 11895 $$A(this.containers.wrap).css({ 11896 width: "100%", 11897 height: "auto", 11898 }); 11899 } 11900 else { 11901 $$A(this.containers.wrap).css({ 11902 width: this.options.width + "px", 11903 height: this.options.height + "px", 11904 }); 11905 } 11906 $$A.extend(true, this.options, { responsive: on }); 11907 if (!this.resizeSensor) { 11908 this.resizeSensor = new ResizeSensor(this.containers.map, () => { 11909 this.redraw(); 11910 }); 11911 } 11912 this.redraw(); 11913 } 11914 setScroll(options, skipEvents) { 11915 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11916 options.limit != undefined && (options.limit = MapSVG.parseBoolean(options.limit)); 11917 $$A.extend(true, this.options, { scroll: options }); 11918 !skipEvents && this.setEventHandlers(); 11919 } 11920 setZoom(options) { 11921 options = options || {}; 11922 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11923 options.fingers != undefined && (options.fingers = MapSVG.parseBoolean(options.fingers)); 11924 options.mousewheel != undefined && 11925 (options.mousewheel = MapSVG.parseBoolean(options.mousewheel)); 11926 options.delta = 2; 11927 if (options.limit) { 11928 if (typeof options.limit == "string") 11929 options.limit = options.limit.split(";"); 11930 options.limit = [parseInt(options.limit[0]), parseInt(options.limit[1])]; 11931 } 11932 if (!this.zoomLevels) { 11933 this.setZoomLevels(); 11934 } 11935 $$A.extend(true, this.options, { zoom: options }); 11936 $$A(this.containers.scrollpaneWrap).off("wheel.mapsvg"); 11937 if (this.options.zoom.mousewheel) { 11938 if (MapSVG.browser.firefox) { 11939 this.firefoxScroll = { insideIframe: false, scrollX: 0, scrollY: 0 }; 11940 $$A(this.containers.scrollpaneWrap) 11941 .on("mouseenter", () => { 11942 this.firefoxScroll.insideIframe = true; 11943 this.firefoxScroll.scrollX = window.scrollX; 11944 this.firefoxScroll.scrollY = window.scrollY; 11945 }) 11946 .on("mouseleave", () => { 11947 this.firefoxScroll.insideIframe = false;
11948 }); 11949 $$A(document).scroll(() => { 11950 if (this.firefoxScroll.insideIframe) 11951 window.scrollTo(this.firefoxScroll.scrollX, this.firefoxScroll.scrollY); 11952 }); 11953 } 11954 $$A(this.containers.scrollpaneWrap).on("wheel.mapsvg", (event) => { 11955 event.preventDefault(); 11956 this.mouseWheelZoom(event); 11957 return false; 11958 }); 11959 $$A(this.layers.markers).on("wheel.mapsvg", (event) => { 11960 event.preventDefault(); 11961 this.mouseWheelZoom(event); 11962 return false; 11963 }); 11964 } 11965 this.canZoom = true; 11966 } 11967 mouseWheelZoom(event) { 11968 event.preventDefault(); 11969 const d = Math.sign(-event.originalEvent.deltaY); 11970 const center = this.getSvgPointAtClick(event.originalEvent); 11971 d > 0 ? this.zoomIn(center) : this.zoomOut(center); 11972 } 11973 setControls(options) { 11974 options = options || {}; 11975 $$A.extend(true, this.options, { controls: options }); 11976 this.options.controls.zoom = MapSVG.parseBoolean(this.options.controls.zoom); 11977 this.options.controls.zoomReset = MapSVG.parseBoolean(this.options.controls.zoomReset); 11978 this.options.controls.userLocation = MapSVG.parseBoolean(this.options.controls.userLocation); 11979 this.options.controls.previousMap = MapSVG.parseBoolean(this.options.controls.previousMap); 11980 const loc = this.options.controls.location || "right"; 11981 if (!this.containers.controls) { 11982 const buttons = $$A("<div />").addClass("mapsvg-buttons"); 11983 const zoomGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11984 const zoomIn = $$A("<div />").addClass("mapsvg-btn-map mapsvg-in"); 11985 zoomIn.on("touchend click", (e) => { 11986 if (e.cancelable) { 11987 e.preventDefault(); 11988 } 11989 e.stopPropagation(); 11990 this.zoomIn(); 11991 }); 11992 const zoomOut = $$A("<div />").addClass("mapsvg-btn-map mapsvg-out"); 11993 zoomOut.on("touchend click", (e) => { 11994 if (e.cancelable) { 11995 e.preventDefault(); 11996 } 11997 e.stopPropagation(); 11998 this.zoomOut(); 11999 }); 12000 zoomGroup.append(zoomIn).append(zoomOut); 12001 const location = $$A("<div />").addClass("mapsvg-btn-map mapsvg-btn-location"); 12002 location.on("touchend click", (e) => { 12003 if (e.cancelable) { 12004 e.preventDefault(); 12005 } 12006 e.stopPropagation(); 12007 this.showUserLocation((location) => { 12008 if (this.options.scroll.on) { 12009 this.centerOn(location.marker); 12010 } 12011 }); 12012 }); 12013 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>'; 12014 location.html(userLocationIcon); 12015 const locationGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12016 locationGroup.append(location); 12017 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>'; 12018 const zoomResetButton = $$A("<div />") 12019 .html(zoomResetIcon) 12020 .addClass("mapsvg-btn-map mapsvg-btn-zoom-reset"); 12021 zoomResetButton.on("touchend click", (e) => { 12022 if (e.cancelable) { 12023 e.preventDefault(); 12024 } 12025 e.stopPropagation(); 12026 this.viewBoxReset(true); 12027 }); 12028 const zoomResetGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12029 zoomResetGroup.append(zoomResetButton); 12030 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="">' + 12031 '<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)">' + 12032 '<g id="g4">
12032<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" ' + 12033 'id="path8" inkscape:connector-curvature="0" /></g></g></svg>'; 12034 const previousMapButton = $$A("<div />") 12035 .html(previousMapIcon) 12036 .addClass("mapsvg-btn-map mapsvg-btn-previous-map"); 12037 previousMapButton.on("touchend click", (e) => { 12038 if (e.cancelable) { 12039 e.preventDefault(); 12040 } 12041 e.stopPropagation(); 12042 this.loadPreviousMap(); 12043 }); 12044 const previousMapGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12045 previousMapGroup.append(previousMapButton); 12046 this.containers.controls = buttons[0]; 12047 this.controls = { 12048 zoom: zoomGroup[0], 12049 userLocation: locationGroup[0], 12050 zoomReset: zoomResetGroup[0], 12051 previousMap: previousMapGroup[0], 12052 }; 12053 $$A(this.containers.map).append($$A(this.containers.controls)); 12054 } 12055 $$A(this.controls.zoom).toggle(this.options.controls.zoom); 12056 $$A(this.controls.userLocation).toggle(this.options.controls.userLocation); 12057 $$A(this.controls.zoomReset).toggle(this.options.controls.zoomReset); 12058 $$A(this.controls.previousMap).toggle(this.options.controls.previousMap && this.options.previousMapsIds.length > 0); 12059 $$A(this.containers.controls).removeClass("left"); 12060 $$A(this.containers.controls).removeClass("right"); 12061 (loc == "right" && $$A(this.containers.controls).addClass("right")) || 12062 (loc == "left" && $$A(this.containers.controls).addClass("left")); 12063 } 12064 setZoomLevels() { 12065 if (!this.zoomLevels) { 12066 this.zoomLevels = new ArrayIndexed("zoomLevel"); 12067 } 12068 else { 12069 this.zoomLevels.clear(); 12070 } 12071 for (let i = -20; i < 0; i++) { 12072 const _scale = 1 / Math.pow(this.options.zoom.delta, Math.abs(i)); 12073 this.zoomLevels.push({ 12074 zoomLevel: i, 12075 _scale: _scale,
12076 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12077 }); 12078 } 12079 for (let z = 0; z <= 20; z++) { 12080 const _scale = Math.pow(this.options.zoom.delta, Math.abs(z)); 12081 this.zoomLevels.push({ 12082 zoomLevel: z, 12083 _scale: _scale, 12084 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12085 }); 12086 } 12087 } 12088 setCursor(type) { 12089 type = type == "pointer" ? "pointer" : "default"; 12090 this.options.cursor = type; 12091 if (type == "pointer") 12092 $$A(this.containers.map).addClass("mapsvg-cursor-pointer"); 12093 else 12094 $$A(this.containers.map).removeClass("mapsvg-cursor-pointer"); 12095 } 12096 setMultiSelect(on, deselect) { 12097 this.options.multiSelect = MapSVG.parseBoolean(on); 12098 if (deselect !== false) 12099 this.deselectAllRegions(); 12100 } 12101 _new_setChoropleth(options) { 12102 options = options || this.options.choropleth; 12103 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12104 if (typeof options.coloring === "undefined" || 12105 typeof options.coloring.palette === "undefined" || 12106 typeof options.coloring.palette.colors === "undefined") { 12107 if (typeof options.sourceFieldSelect === "undefined" || 12108 typeof options.sourceFieldSelect.variants === "undefined") { 12109 $$A.extend(true, this.options.choropleth, options); 12110 } 12111 else { 12112 this.options.choropleth.sourceFieldSelect.variants = 12113 options.sourceFieldSelect.variants; 12114 } 12115 } 12116 else { 12117 const paletteColorsIndexes = Object.keys(options.coloring.palette.colors); 12118 if (paletteColorsIndexes.length > 1 || 12119 (paletteColorsIndexes[0] == "0" && 12120 Object.keys(options.coloring.palette.colors[0]).length > 1)) { 12121 this.options.choropleth.coloring.palette.colors = options.coloring.palette.colors; 12122 } 12123 else { 12124 const paletteColorIndex = Object.keys(options.coloring.palette.colors)[0]; 12125 $$A.extend(true, this.options.choropleth.coloring.palette.colors[paletteColorIndex], options.coloring.palette.colors[paletteColorIndex]); 12126 } 12127 } 12128 this.updateChoroplethMinMax(); 12129 if (this.options.choropleth.on && 12130 this.options.choropleth.sourceFieldSelect.on && 12131 this.options.choropleth.sourceFieldSelect.variants) { 12132 if (!this.containers.choroplethSourceSelect) { 12133 const sourceSelectOptions = []; 12134 this.options.choropleth.sourceFieldSelect.variants.forEac
12134h((variant) => { 12135 sourceSelectOptions.push($$A('<option value="' + 12136 variant + 12137 '" ' + 12138 (variant === this.options.choropleth.sourceField 12139 ? "selected" 12140 : "") + 12141 ">" + 12142 variant + 12143 "</option>")); 12144 }); 12145 this.containers.choroplethSourceSelect = { 12146 container: $$A('<div class="mapsvg-choropleth-source-field"></div>')[0], 12147 select: $$A('<select id="mapsvg-choropleth-source-field-select" class="mapsvg-select2"></select>')[0], 12148 options: sourceSelectOptions, 12149 }; 12150 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12151 $$A(this.containers.choroplethSourceSelect.container).append($$A(this.containers.choroplethSourceSelect.select)); 12152 $$A(this.containers.map).append($$A(this.containers.choroplethSourceSelect.container)); 12153 $$A(this.containers.choroplethSourceSelect.select).mselect2(); 12154 $$A(this.containers.choroplethSourceSelect.select) 12155 .mselect2() 12156 .on("select2:select select2:unselecting", (e) => { 12157 if (e.cancelable) { 12158 e.preventDefault(); 12159 } 12160 e.stopPropagation(); 12161 this.setChoropleth({ sourceField: $$A(e.target).mselect2().val() }); 12162 }); 12163 } 12164 else { 12165 $$A(this.containers.choroplethSourceSelect.select).mselect2("destroy"); 12166 $$A(this.containers.choroplethSourceSelect.select).find("option").remove(); 12167 this.containers.choroplethSourceSelect.options = []; 12168 this.options.choropleth.sourceFieldSelect.variants.forEac
12168h((variant) => { 12169 this.containers.choroplethSourceSelect.options.push($$A('<option value="' + 12170 variant + 12171 '" ' + 12172 (variant === this.options.choropleth.sourceField 12173 ? "selected" 12174 : "") + 12175 ">" + 12176 variant + 12177 "</option>")[0]); 12178 }); 12179 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12180 $$A(this.containers.choroplethSourceSelect.select).mselect2({ width: "100%" }); 12181 } 12182 } 12183 if ((!this.options.choropleth.on || !this.options.choropleth.sourceFieldSelect.on) && 12184 this.containers.choroplethSourceSelect && 12185 $$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12186 $$A(this.containers.choroplethSourceSelect.container).hide(); 12187 } 12188 else if (this.options.choropleth.on && 12189 this.options.choropleth.sourceFieldSelect.on && 12190 this.containers.choroplethSourceSelect && 12191 !$$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12192 $$A(this.containers.choroplethSourceSelect.container).show(); 12193 } 12194 $$A(this.containers.map).find(".mapsvg-choropleth-legend").remove(); 12195 if (this.options.choropleth.on && this.options.choropleth.coloring.legend.on) { 12196 const legend = this.options.choropleth.coloring.legend; 12197 let coloring = ""; 12198 if (this.options.choropleth.coloring.mode === "gradient") { 12199 coloring += 12200 '<div class="mapsvg-choropleth-legend-gradient-no-data">' + 12201 this.options.choropleth.coloring.noData.description + 12202 "</div>"; 12203 let legendGradient = ""; 12204 for (let chunkIdx = 1; chunkIdx < 5; chunkIdx++) { 12205 legendGradient += 12206 '<div class="mapsvg-choropleth-legend-gradient-chunk">' + 12207 ((this.options.choropleth.coloring.gradient.values.maxAdjusted * chunkIdx) / 12208 5 + 12209 this.options.choropleth.coloring.gradient.values.min) + 12210 "</div>"; 12211 } 12212 coloring += 12213 '<div class="mapsvg-choropleth-legend-gradient-colors">' + 12214 legendGradient + 12215 "</div>"; 12216 } 12217 else { 12218 coloring += 12219 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="no-data">' + 12220 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12221 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12222 this.options.choropleth.coloring.noData.description + 12223 "</div>" + 12224 "</div>"; 12225 coloring += 12226 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="out-of-range">' + 12227 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12228 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12229 this.options.choropleth.coloring.palette.outOfRange.description + 12230 "</div>" + 12231 "</div>"; 12232 const paletteColors = this.options.choropleth.coloring.palette.colors; 12233 paletteColors.forEach((paletteColor, idx) => { 12234 let paletteColorElementText = ""; 12235 if (paletteColor.description) { 12236 paletteColorElementText = paletteColor.description; 12237 } 12238 else { 12239 if (idx === 0 && !paletteColor.valueFrom && paletteColor.valueFrom !== 0) { 12240 if (legend.layout === "vertical") { 12241 paletteColorElementText = "Less then " + paletteColor.valueTo; 12242 } 12243 else { 12244 paletteColorElementText = "< " + paletteColor.valueTo; 12245 } 12246 } 12247 else if (idx === paletteColors.length - 1 && !paletteColor.valueTo) { 12248 if (legend.layout === "vertical") { 12249 paletteColorElementText = paletteColor.valueFrom + " or more"; 12250 } 12251 else { 12252 paletteColorElementText = paletteColor.valueFrom + " <"; 12253 } 12254 } 12255 else { 12256 paletteColorElementText = 12257 paletteColor.valueFrom + " ≤ " + paletteColor.valueTo; 12258 } 12259 } 12260 coloring += 12261 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="' + 12262 idx + 12263 '">' + 12264 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12265 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12266 paletteColorElementText + 12267 "</div>" + 12268 "</div>"; 12269 }); 12270 } 12271 this.containers.legend = { 12272 title: $$A('<div class="mapsvg-choropleth-legend-title">' + legend.title + "</div>")[0], 12273 text: $$A('<div class="mapsvg-choropleth-legend-text">' + legend.text + "</div>")[0], 12274 coloring: $$A('<div class="mapsvg-choropleth-legend-' + 12275 this.options.choropleth.coloring.mode + 12276 '">' + 12277 coloring + 12278 "</div>")[0], 12279 description: $$A('<div class="mapsvg-choropleth-legend-description">' + 12280 legend.description + 12281 "</div>")[0], 12282 container: $$A("<div />").addClass("mapsvg-choropleth-legend mapsvg-choropleth-legend-" + 12283 legend.layout + 12284 " mapsvg-choropleth-legend-container-" + 12285 legend.container)[0], 12286 }; 12287 $$A(this.containers.legend.container) 12288 .append(this.containers.legend.title) 12289 .append(this.containers.legend.text) 12290 .append(this.containers.legend.coloring) 12291 .append(this.containers.legend.description); 12292 $$A(this.containers.map).append(this.containers.legend.container); 12293 this.setChoroplethLegendCSS(); 12294 this.regionsRepository.events.on("updated", () => { 12295 this.redrawChoropleth(); 12296 }); 12297 this.objectsRepository.events.on("updated", () => { 12298 this.redrawChoropleth(); 12299 }); 12300 } 12301 if (this.options.choropleth.on && this.options.choropleth.coloring.mode === "gradient") { 12302 const colors = this.options.choropleth.coloring.gradient.colors; 12303 if (colors) { 12304 colors.lowRGB = tinycolor(colors.low).toRgb(); 12305 colors.highRGB = tinycolor(colors.high).toRgb(); 12306 colors.diffRGB = { 12307 r: colors.highRGB.r - colors.lowRGB.r, 12308 g: colors.highRGB.g - colors.lowRGB.g, 12309 b: colors.highRGB.b - colors.lowRGB.b, 12310 a: colors.highRGB.a - colors.lowRGB.a, 12311 }; 12312 this.containers.legend && this.setChoroplethLegendCSS(); 12313 } 12314 } 12315 this.redrawChoropleth(); 12316 } 12317 redrawChoropleth() { 12318 this.updateChoroplethMinMax(); 12319 this.redrawBubbles(); 12320 this.regionsRedrawColors(); 12321 } 12322 updateChoroplethMinMax() { 12323 if (this.options.choropleth.on) { 12324 const gradient = this.options.choropleth.coloring.gradient, values = []; 12325 gradient.values.min = 0; 12326 gradient.values.max = null; 12327 if (this.options.choropleth.source === "regions") { 12328 this.regions.forEach((region) => { 12329 const choropleth = region.data && region.data[this.options.choropleth.sourceField]; 12330 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12331 }); 12332 } 12333 else {
12334 this.objectsRepository.objects.forEach((object) => { 12335 const choropleth = object[this.options.choropleth.sourceField]; 12336 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12337 }); 12338 } 12339 if (values.length > 0) { 12340 gradient.values.min = Math.min.apply(null, values); 12341 gradient.values.max = Math.max.apply(null, values); 12342 gradient.values.maxAdjusted = gradient.values.max - gradient.values.min; 12343 } 12344 } 12345 } 12346 setChoroplethLegendCSS() { 12347 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; 12348 $$A(".mapsvg-choropleth-legend").css({ 12349 width: legend.width, 12350 height: legend.height, 12351 }); 12352 if (this.options.choropleth.coloring.mode === "gradient") { 12353 if (legend.layout === "horizontal") { 12354 $$A(".mapsvg-choropleth-legend-horizontal .mapsvg-choropleth-legend-gradient-colors").css({ 12355 background: "linear-gradient(to right," + 12356 gradient.colors.low + 12357 " 1%," + 12358 gradient.colors.high + 12359 " 100%)", 12360 }); 12361 } 12362 else { 12363 $$A(".mapsvg-choropleth-legend-vertical .mapsvg-choropleth-legend-gradient-colors").css({ 12364 background: "linear-gradient(to bottom," + 12365 gradient.colors.low + 12366 " 1%," + 12367 gradient.colors.high + 12368 " 100%)", 12369 }); 12370 } 12371 $$A(".mapsvg-choropleth-legend-gradient-no-data").css({ 12372 "background-color": noData.color, 12373 }); 12374 } 12375 else { 12376 const paletteColors = this.options.choropleth.coloring.palette.colors; 12377 paletteColors.forEach(function (paletteColor, idx) { 12378 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="' + 12379 idx + 12380 '"] .mapsvg-choropleth-legend-palette-color').css({ 12381 "background-color": paletteColor.color, 12382 }); 12383 }); 12384 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="no-data"] .mapsvg-choropleth-legend-palette-color').css({ 12385 "background-color": noData.color, 12386 }); 12387 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="out-of-range"] .mapsvg-choropleth-legend-palette-color').css({ 12388 "background-color": outOfRange.color, 12389 }); 12390 } 12391 } 12392 setCss(css) { 12393 this.options.css = 12394 css || (this.options.css ? this.options.css.replace(/%id%/g, "" + this.id) : ""); 12395 this.liveCss = this.liveCss || $$A("<style></style>").appendTo("head")[0]; 12396 $$A(this.liveCss).html(this.options.css); 12397 } 12398 setFilters(options) { 12399 options = options || this.options.filters; 12400 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12401 options.hide != undefined && (options.hide = MapSVG.parseBoolean(options.hide)); 12402 $$A.extend(true, this.options, { filters: options }); 12403 if (!MapSVG.googleMapsApiLoaded && 12404 this.options.filters.on && 12405 this.filtersSchema.getField("distance")) { 12406 this.loadGoogleMapsAPI(() => { 12407 return 1; 12408 }, () => { 12409 return 1; 12410 }); 12411 } 12412 if (["leftSidebar", "rightSidebar", "header", "footer", "custom", "map"].indexOf(this.options.filters.location) === -1) { 12413 this.options.filters.location = "leftSidebar"; 12414 } 12415 if (this.options.filters.on) { 12416 if (this.formBuilder) { 12417 this.formBuilder.destroy(); 12418 } 12419 if (!this.containers.filters) { 12420 this.containers.filters = $$A('<div class="mapsvg-filters-wrap"></div>')[0]; 12421 } 12422 else { 12423 $$A(this.containers.filters).empty(); 12424 $$A(this.containers.filters).show(); 12425 } 12426 $$A(this.containers.filters).css({ 12427 "background-color": this.options.colors.directorySearch, 12428 }); 12429 if ($$A(this.containers.filtersModal)) { 12430 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 12431 } 12432 if (this.options.filters.location === "custom") { 12433 $$A(this.containers.filters) 12434 .removeClass("mapsvg-filter-container-custom") 12435 .addClass("mapsvg-filter-container-custom"); 12436 if ($$A("#" + this.options.filters.containerId).length) { 12437 $$A("#" + this.options.filters.containerId).append(this.containers.filters); 12438 } 12439 else { 12440 $$A(this.containers.filters).hide(); 12441 console.error("MapSVG: filter container #" + 12442 this.options.filters.containerId + 12443 " does not exists"); 12444 } 12445 } 12446 else { 12447 if (MapSVG.isPhone) { 12448 $$A(this.containers.header).append($$A(this.containers.filters)); 12449 this.setContainers({ header: { on: true } }); 12450 } 12451 else { 12452 const location = MapSVG.isPhone ? "header" : this.options.filters.location; 12453 if (this.options.menu.on && 12454 this.controllers.directory && 12455 this.options.menu.location === this.options.filters.location) { 12456 $$A(this.controllers.directory.containers.view) 12457 .find(".mapsvg-directory-filter-wrap") 12458 .append($$A(this.containers.filters)); 12459 this.controllers.directory.updateTopShift(); 12460 } 12461 else { 12462 $$A(this.containers[location]).append($$A(this.containers.filters)); 12463 this.controllers.directory && this.controllers.directory.updateTopShift(); 12464 } 12465 } 12466 } 12467 this.loadFiltersController(this.containers.filters, false); 12468 this.updateFiltersState(); 12469 } 12470 else { 12471 if ($$A(this.containers.filters)) { 12472 $$A(this.containers.filters).empty(); 12473 $$A(this.containers.filters).hide(); 12474 } 12475 } 12476 if (this.options.menu.on && 12477 this.controllers.directory && 12478 this.options.menu.location === this.options.filters.location) { 12479 this.controllers.directory.updateTopShift(); 12480 } 12481 } 12482 updateFiltersState() { 12483 if (this.options.filters && this.options.filters.on && this.controllers.filters) { 12484 this.controllers.filters.update(this.objectsRepository.query); 12485 this.updateFilterTags(); 12486 } 12487 } 12488 setGlobalDistanceFilter() { 12489 if (this.objectsRepository && 12490 this.objectsRepository.query.filters && 12491 this.objectsRepository.query.filters.distance) { 12492 const dist = this.objectsRepository.query.filters.distance; 12493 MapSVG.distanceSearch = this.objectsRepository.query.filters.distance; 12494 } 12495 else { 12496 MapSVG.distanceSearch = null; 12497 } 12498 } 12499 updateFilterTags() { 12500 $$A(this.containers.filterTags) && $$A(this.containers.filterTags).empty(); 12501 for (const field_name in this.objectsRepository.query.filters) { 12502 let field_value = this.objectsRepository.query.filters[field_name]; 12503 let _field_name = field_name; 12504 const filterField = this.filtersSchema.getField(_field_name); 12505 if (field_name == "regions") { 12506 _field_name = ""; 12507 field_value = field_value.region_ids.map((id) => this.getRegion(id).title); 12508 } 12509 else { 12510 _field_name = filterField && filterField.label; 12511 } 12512 if (field_name !== "distance") { 12513 if (!this.containers.filterTags) { 12514 this.containers.filterTags = $$A('<div class="mapsvg-filter-tags"></div>')[0]; 12515 if ($$A(this.containers.filters)) ; 12516 else { 12517 if (this.options.menu.on && this.controllers.directory) { 12518 $$A(this.controllers.directory.containers.toolbar).append(this.containers.filterTags); 12519 this.controllers.directory.updateTopShift(); 12520 } 12521 else { 12522 $$A(this.containers.map).append(this.containers.filterTags); 12523 if (this.options.zoom.buttons.on) { 12524 if (this.options.layersControl.on) { 12525 if (this.options.layersControl.position == "top-left") { 12526 $$A(this.containers.filterTags).css({ 12527 right: 0, 12528 bottom: 0, 12529 }); 12530 } 12531 else { 12532 $$A(this.containers.filterTags).css({ 12533 bottom: 0, 12534 }); 12535 } 12536 } 12537 else { 12538 if (this.options.zoom.buttons.location == "left") { 12539 $$A(this.containers.filterTags).css({ 12540 right: 0, 12541 }); 12542 } 12543 } 12544 } 12545 } 12546 } 12547 $$A(this.containers.filterTags).on("click", ".mapsvg-filter-delete", (e) => { 12548 const filterField = $$A(e.target).data("filter"); 12549 $$A(e.target).parent().remove(); 12550 this.objectsRepository.query.removeFilter(filterField); 12551 this.deselectAllRegions(); 12552 this.loadDataObjects(); 12553 }); 12554 } 12555 $$A(this.containers.filterTags).append('<div class="mapsvg-filter-tag">' + 12556 (_field_name ? _field_name + ": " : "") + 12557 field_value + 12558 ' <span class="mapsvg-filter-delete" data-filter="' + 12559 field_name + 12560 '">
12560Ã</span></div>'); 12561 } 12562 } 12563 } 12564 setContainers(options) { 12565 const _this = this; 12566 if (!this.containersCreated) { 12567 this.containers.wrapAll = document.createElement("div"); 12568 this.containers.wrapAll.classList.add("mapsvg-wrap-all"); 12569 this.containers.wrapAll.id = "mapsvg-map-" + this.id; 12570 this.containers.wrapAll.setAttribute("data-map-id", this.id ? this.id.toString() : ""); 12571 this.containers.wrap = document.createElement("div"); 12572 this.containers.wrap.classList.add("mapsvg-wrap"); 12573 this.containers.mapContainer = document.createElement("div"); 12574 this.containers.mapContainer.classList.add("mapsvg-map-container"); 12575 this.containers.leftSidebar = document.createElement("div"); 12576 this.containers.leftSidebar.className = 12577 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"; 12578 this.containers.rightSidebar = document.createElement("div"); 12579 this.containers.rightSidebar.className = 12580 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"; 12581 this.containers.header = document.createElement("div"); 12582 this.containers.header.className = "mapsvg-header mapsvg-top-container"; 12583 this.containers.footer = document.createElement("div"); 12584 this.containers.footer.className = "mapsvg-footer mapsvg-top-container"; 12585 _this.containers.wrapAll = $$A('<div class="mapsvg-wrap-all"></div>') 12586 .attr("id", "mapsvg-map-" + this.id) 12587 .attr("data-map-id", this.id)[0]; 12588 _this.containers.wrap = $$A('<div class="mapsvg-wrap"></div>')[0]; 12589 _this.containers.mapContainer = $$A('<div class="mapsvg-map-container"></div>')[0]; 12590 _this.containers.leftSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"></div>')[0]; 12591 _this.containers.rightSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"></div>')[0]; 12592 _this.containers.header = $$A('<div class="mapsvg-header mapsvg-top-container"></div>')[0]; 12593 _this.containers.footer = $$A('<div class="mapsvg-footer mapsvg-top-container"></div>')[0]; 12594 $$A(_this.containers.wrapAll).insertBefore(_this.containers.map); 12595 $$A(_this.containers.wrapAll).append(_this.containers.header); 12596 $$A(_this.containers.wrapAll).append(_this.containers.wrap); 12597 $$A(_this.containers.wrapAll).append(_this.containers.footer); 12598 $$A(_this.containers.mapContainer).append(_this.containers.map); 12599 $$A(_this.containers.wrap).append(_this.containers.leftSidebar); 12600 $$A(_this.containers.wrap).append(_this.containers.mapContainer); 12601 $$A(_this.containers.wrap).append(_this.containers.rightSidebar); 12602 _this.containersCreated = true; 12603 } 12604 options = options || _this.options.containers || {}; 12605 for (const contName in options) { 12606 if (options[contName].on !== undefined) { 12607 options[contName].on = MapSVG.parseBoolean(options[contName].on); 12608 } 12609 if (options[contName].width) { 12610 if (typeof options[contName].width != "string" || 12611 (options[contName].width.indexOf("px") === -1 && 12612 options[contName].width.indexOf("%") === -1 && 12613 options[contName].width !== "auto")) { 12614 options[contName].width = options[contName].width + "px"; 12615 } 12616 $$A(_this.containers[contName]).css({ "flex-basis": options[contName].width }); 12617 } 12618 if (options[contName].height) { 12619 if (typeof options[contName].height != "string" || 12620 (options[contName].height.indexOf("px") === -1 && 12621 options[contName].height.indexOf("%") === -1 && 12622 options[contName].height !== "auto")) { 12623 options[contName].height = options[contName].height + "px"; 12624 } 12625 $$A(_this.containers[contName]).css({ 12626 "flex-basis": options[contName].height, 12627 height: options[contName].height, 12628 }); 12629 } 12630 $$A.extend(true, _this.options, { containers: options }); 12631 let on = _this.options.containers[contName].on; 12632 if (MapSVG.isPhone && 12633 _this.options.menu.hideOnMobile && 12634 _this.options.menu.location === contName && 12635 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12636 on = false;
12637 } 12638 else if (MapSVG.isPhone && 12639 _this.options.menu.location === "custom" && 12640 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12641 on = false; 12642 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12643 } 12644 else if (MapSVG.isPhone && 12645 !_this.options.menu.hideOnMobile && 12646 _this.options.menu.location === contName && 12647 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12648 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12649 $$A(_this.containers.wrapAll).addClass("mapsvg-directory-visible"); 12650 } 12651 $$A(_this.containers[contName]).toggle(on); 12652 } 12653 _this.setDetailsView(); 12654 } 12655 shouldBeScrollable(container) { 12656 const _this = this; 12657 switch (container) { 12658 case "map": 12659 case "leftSidebar": 12660 case "rightSidebar": 12661 return true; 12662 case "custom": 12663 return false; 12664 case "header": 12665 case "footer": 12666 if (_this.options.containers[container].height && 12667 _this.options.containers[container].height !== "auto" && 12668 _this.options.containers[container].height !== "100%") { 12669 return true; 12670 } 12671 else { 12672 return false; 12673 } 12674 default: 12675 return false; 12676 } 12677 } 12678 setDirectory(options) { 12679 return this.setMenu(options); 12680 } 12681 setMenu(options) { 12682 options = options || this.options.menu; 12683 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12684 options.search != undefined && (options.search = MapSVG.parseBoolean(options.search)); 12685 options.showMapOnClick != undefined && 12686 (options.showMapOnClick = MapSVG.parseBoolean(options.showMapOnClick)); 12687 options.searchFallback != undefined && 12688 (options.searchFallback = MapSVG.parseBoolean(options.searchFallback)); 12689 options.customContainer != undefined && 12690 (options.customContainer = MapSVG.parseBoolean(options.customContainer)); 12691 $$A.extend(true, this.options, { menu: options }); 12692 this.controllers = this.controllers || {}; 12693 if (!this.containers.directory) { 12694 this.containers.directory = $$A('<div class="mapsvg-directory"></div>')[0]; 12695 } 12696 $$A(this.containers.directory).toggleClass("flex", this.shouldBeScrollable(this.options.menu.location)); 12697 if (this.options.menu.on) { 12698 if (!this.controllers.directory) { 12699 this.controllers.directory = new DirectoryController({ 12700 container: this.containers.directory, 12701 template: this.options.templates.directory, 12702 mapsvg: this, 12703 repository: this.options.menu.source === "regions" 12704 ? this.regionsRepository 12705 : this.objectsRepository, 12706 scrollable: this.shouldBeScrollable(this.options.menu.location), 12707 events: { 12708 click: (e, regionOrObject, mapsvg) => { 12709 this.events.trigger("click.directoryItem", this, [ 12710 e, 12711 regionOrObject, 12712 mapsvg, 12713 ]); 12714 }, 12715 mouseover: (e, regionOrObject, mapsvg) => { 12716 this.events.trigger("mouseover.directoryItem", this, [ 12717 e, 12718 regionOrObject, 12719 mapsvg, 12720 ]); 12721 }, 12722 mouseout: (e, regionOrObject, mapsvg) => { 12723 this.events.trigger("mouseout.directoryItem", this, [ 12724 e, 12725 regionOrObject, 12726 mapsvg, 12727 ]); 12728 }, 12729 }, 12730 }); 12731 this.controllers.directory._init(); 12732 } 12733 if (options.source) { 12734 this.controllers.directory.repository = 12735 this.options.menu.source === "regions" 12736 ? this.regionsRepository 12737 : this.objectsRepository; 12738 } 12739 if (options.sortBy || options.sortDirection) { 12740 this.controllers.directory.repository.query.update({ 12741 sort: [ 12742 { 12743 field: this.options.menu.sortBy, 12744 order: this.options.menu.sortDirection, 12745 }, 12746 ], 12747 }); 12748 } 12749 this.setFilterOut(); 12750 if (options.location) { 12751 this.controllers.directory.scrollable = this.shouldBeScrollable(this.options.menu.location); 12752 } 12753 let $container; 12754 if (MapSVG.isPhone && this.options.menu.hideOnMobile) { 12755 $container = $$A(this.containers.leftSidebar); 12756 } 12757 else { 12758 $container = 12759 this.options.menu.location !== "custom" 12760 ? $$A(this.containers[this.options.menu.location]) 12761 : $$A("#" + this.options.menu.containerId); 12762 } 12763 $container.append(this.containers.directory); 12764 if (this.options.colors.directory) { 12765 $$A(this.containers.directory).css({ 12766 "background-color": this.options.colors.directory, 12767 }); 12768 } 12769 this.setFilters(); 12770 this.setTemplates({ directoryItem: this.options.templates.directoryItem }); 12771 if ((this.options.menu.source === "regions" && this.regionsRepository.loaded) || 12772 (this.options.menu.source === "database" && this.objectsRepository.loaded)) { 12773 if (this.editMode && 12774 (options.sortBy || options.sortDirection || options.filterout)) { 12775 this.controllers.directory.repository.reload(); 12776 } 12777 this.loadDirectory(); 12778 } 12779 } 12780 else { 12781 this.controllers.directory && this.controllers.directory.destroy(); 12782 this.controllers.directory = null; 12783 } 12784 } 12785 setDatabase(options) { 12786 options = options || this.options.database; 12787 if (options.pagination) { 12788 if (options.pagination.on != undefined) { 12789 options.pagination.on = MapSVG.parseBoolean(options.pagination.on); 12790 } 12791 if (options.pagination.perpage != undefined) { 12792 options.pagination.perpage = parseInt(options.pagination.perpage); 12793 } 12794 } 12795 $$A.extend(true, this.options, { database: options }); 12796 if (options.pagination) { 12797 if (options.pagination.on !== undefined || options.pagination.perpage) { 12798 const query = new Query({ 12799 perpage: this.options.database.pagination.on 12800 ? this.options.database.pagination.perpage 12801 : 0, 12802 }); 12803 this.objectsRepository.find(query); 12804 } 12805 else { 12806 this.setPagination(); 12807 } 12808 } 12809 } 12810 updateGoogleMapsMaxZoom(geoPoint) { 12811 this.googleMaps.maxZoomService.getMaxZoomAtLatLng(geoPoint, (result) => { 12812 if (result.status === "OK") { 12813 this.googleMaps.currentMaxZoom = result.zoom; 12814 } 12815 }); 12816 } 12817 setGoogleMaps(options) { 12818 options = options || this.options.googleMaps; 12819 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12820 if (!this.googleMaps) { 12821 this.googleMaps = { loaded: false, initialized: false, map: null, overlay: null }; 12822 } 12823 $$A.extend(true, this.options, { googleMaps: options }); 12824 if (this.options.googleMaps.on) { 12825 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12826 if (!MapSVG.googleMapsApiLoaded) { 12827 this.loadGoogleMapsAPI(() => { 12828 this.setGoogleMaps(); 12829 }, () => { 12830 this.setGoogleMaps({ on: false }); 12831 }); 12832 } 12833 else { 12834 if (!this.googleMaps.map) { 12835 this.containers.googleMaps = $$A('<div class="mapsvg-layer mapsvg-layer-gm" id="mapsvg-google-maps-' + 12836 this.id + 12837 '"></div>').prependTo(this.containers.map)[0]; 12838 $$A(this.containers.googleMaps).css({ 12839 position: "absolute", 12840 top: 0, 12841 left: 0, 12842 bottom: 0, 12843 right: 0, 12844 "z-index": "0", 12845 }); 12846 this.googleMaps.map = new google.maps.Map(this.containers.googleMaps, { 12847 mapTypeId: options.type, 12848 fullscreenControl: false, 12849 keyboardShortcuts: false, 12850 mapTypeControl: false, 12851 scaleControl: false, 12852 scrollwheel: false, 12853 streetViewControl: false, 12854 zoomControl: false, 12855 styles: options.styleJSON, 12856 tilt: 0, 12857 }); 12858 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 12859 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 12860 const bounds = new google.maps.LatLngBounds(southWest, northEast);
12861 this.googleMaps.overlay = this.createGoogleMapOverlay(bounds, this.googleMaps.map); 12862 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 12863 this.googleMaps.map.fitBounds(bounds, 0); 12864 } 12865 else { 12866 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 12867 this.googleMaps.map.setCenter(this.options.googleMaps.center); 12868 } 12869 this.googleMaps.initialized = true; 12870 this.googleMaps.maxZoomService = new google.maps.MaxZoomService(); 12871 this.googleMaps.map.addListener("idle", () => { 12872 this.isZooming = false; 12873 }); 12874 google.maps.event.addListenerOnce(this.googleMaps.map, "idle", () => { 12875 setTimeout(() => { 12876 $$A(this.containers.map).addClass("mapsvg-fade-in"); 12877 setTimeout(() => { 12878 $$A(this.containers.map).removeClass("mapsvg-google-map-loading"); 12879 $$A(this.containers.map).removeClass("mapsvg-fade-in"); 12880 if (!this.options.googleMaps.center || 12881 !this.options.googleMaps.zoom) { 12882 this.options.googleMaps.center = this.googleMaps.map 12883 .getCenter() 12884 .toJSON(); 12885 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 12886 } 12887 this.zoomDelta = this.options.googleMaps.zoom - this.zoomLevel; 12888 this.updateGoogleMapsMaxZoom(this.options.googleMaps.center); 12889 this.setInitialViewBox(this.viewBox); 12890 this.toggleSvgLayerOnZoom(); 12891 this.events.trigger("googleMapsLoaded"); 12892 this.afterLoadBlockers--; 12893 this.finalizeMapLoading(); 12894 }, 300); 12895 }, 1); 12896 }); 12897 this.events.on("googleMapsBoundsChanged", (bounds) => { 12898 this.setViewBoxByGoogleMapsOverlay(); 12899 }); 12900 } 12901 else { 12902 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12903 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).show(); 12904 if (options.type) { 12905 this.googleMaps.map.setMapTypeId(options.type); 12906 } 12907 this.setViewBoxByGoogleMapsOverlay(); 12908 } 12909 } 12910 } 12911 else { 12912 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", false); 12913 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).hide(); 12914 this.googleMaps.initialized = false; 12915 } 12916 if (this.converter) { 12917 this.converter.setWorldShift(this.options.googleMaps.on); 12918 } 12919 } 12920 createGoogleMapOverlay(bounds, map) { 12921 class GoogleMapsOverlay extends google.maps.OverlayView { 12922 constructor(bounds, googleMapInstance, mapsvg) { 12923 super(); 12924 this.bounds_ = bounds; 12925 this.map_ = googleMapInstance; 12926 this.mapsvg = mapsvg; 12927 this.setMap(googleMapInstance); 12928 this.prevCoords = { 12929 sw: { x: 0, y: 0 }, 12930 sw2: { x: 0, y: 0 }, 12931 ne: { x: 0, y: 0 }, 12932 ne2: { x: 0, y: 0 }, 12933 }; 12934 } 12935 draw() { 12936 this.mapsvg.events.trigger("googleMapsBoundsChanged", this.map_, [ 12937 this.getPixelBounds(), 12938 this.map_, 12939 ]); 12940 } 12941 onAdd() { 12942 this.element = document.createElement("div"); 12943 this.element.style.borderStyle = "none"; 12944 this.element.style.borderWidth = "0px"; 12945 this.element.style.position = "absolute"; 12946 const panes = this.getPanes(); 12947 panes.overlayLayer.appendChild(this.element); 12948 } 12949 getPixelBounds() { 12950 const overlayProjection = this.getProjection(); 12951 if (!overlayProjection) 12952 return;
12953 const geoSW = this.bounds_.getSouthWest(); 12954 const geoNE = this.bounds_.getNorthEast(); 12955 const coords = { 12956 sw: overlayProjection.fromLatLngToDivPixel(geoSW), 12957 ne: overlayProjection.fromLatLngToDivPixel(geoNE), 12958 sw2: overlayProjection.fromLatLngToContainerPixel(geoSW), 12959 ne2: overlayProjection.fromLatLngToContainerPixel(geoNE), 12960 }; 12961 const ww = overlayProjection.getWorldWidth(); 12962 if (this.prevCoords.sw) { 12963 if (coords.ne.x < coords.sw.x) { 12964 if (Math.abs(this.prevCoords.sw.x - coords.sw.x) > 12965 Math.abs(this.prevCoords.ne.x - coords.ne.x)) { 12966 coords.sw.x = coords.sw.x - ww; 12967 } 12968 else { 12969 coords.ne.x = coords.ne.x + ww; 12970 } 12971 if (Math.abs(this.prevCoords.sw2.x - coords.sw2.x) > 12972 Math.abs(this.prevCoords.ne2.x - coords.ne2.x)) { 12973 coords.sw2.x = coords.sw2.x - ww; 12974 } 12975 else { 12976 coords.ne2.x = coords.ne2.x + ww; 12977 } 12978 } 12979 } 12980 this.prevCoords = coords; 12981 return { sw: coords.sw2, ne: coords.ne2 }; 12982 } 12983 } 12984 return new GoogleMapsOverlay(bounds, map, this); 12985 } 12986 loadGoogleMapsAPI(callback, fail) { 12987 if (!this.options.googleMaps.apiKey) { 12988 console.error("MapSVG: can't load Google API because no API key has been provided"); 12989 return; 12990 } 12991 if (window.google !== undefined && google.maps) { 12992 MapSVG.googleMapsApiLoaded = true; 12993 } 12994 if (MapSVG.googleMapsApiLoaded) { 12995 if (typeof callback == "function") { 12996 callback(); 12997 } 12998 return; 12999 } 13000 MapSVG.googleMapsLoadCallbacks = MapSVG.googleMapsLoadCallbacks || []; 13001 if (typeof callback == "function") { 13002 MapSVG.googleMapsLoadCallbacks.push(callback); 13003 } 13004 if (MapSVG.googleMapsApiIsLoading) { 13005 return; 13006 } 13007 MapSVG.googleMapsApiIsLoading = true; 13008 window.gm_authFailure = () => { 13009 if (MapSVG.GoogleMapBadApiKey) { 13010 MapSVG.GoogleMapBadApiKey(); 13011 } 13012 else { 13013 if (this.editMode) { 13014 alert("Google maps API key is incorrect."); 13015 } 13016 else { 13017 console.error("MapSVG: Google maps API key is incorrect."); 13018 } 13019 } 13020 }; 13021 this.googleMapsScript = document.createElement("script"); 13022 this.googleMapsScript.onload = () => { 13023 MapSVG.googleMapsApiLoaded = true; 13024 MapSVG.googleMapsLoadCallbacks.forEach((_callback) => { 13025 if (typeof callback == "function") 13026 _callback(); 13027 }); 13028 }; 13029 const gmLibraries = []; 13030 if (this.options.googleMaps.drawingTools) { 13031 gmLibraries.push("drawing"); 13032 } 13033 if (this.options.googleMaps.geometry) { 13034 gmLibraries.push("geometry"); 13035 } 13036 let libraries = ""; 13037 if (gmLibraries.length > 0) { 13038 libraries = "&libraries=" + gmLibraries.join(","); 13039 } 13040 this.googleMapsScript.src = 13041 "https://maps.googleapis.com/maps/api/js?language=" + 13042 this.options.googleMaps.language + 13043 "&key=" + 13044 this.options.googleMaps.apiKey + 13045 libraries; 13046 document.head.appendChild(this.googleMapsScript); 13047 } 13048 loadDetailsView(obj) { 13049 this.controllers.popover && this.controllers.popover.close(); 13050 if (this.controllers.detailsView) 13051 this.controllers.detailsView.destroy(); 13052 this.controllers.detailsView = new DetailsController({ 13053 autoresize: MapSVG.isPhone && 13054 this.options.detailsView.mobileFullscreen && 13055 this.options.detailsView.location !== "custom" 13056 ? false 13057 : this.options.detailsView.autoresize, 13058 container: this.containers.detailsView, 13059 template: obj instanceof Region 13060 ? this.options.templates.detailsViewRegion 13061 : this.options.templates.detailsView, 13062 mapsvg: this, 13063 data: obj.getData(), 13064 modal: MapSVG.isPhone && 13065 this.options.detailsView.mobileFullscreen && 13066 this.options.detailsView.location !== "custom", 13067 scrollable: (MapSVG.isPhone && 13068 this.options.detailsView.mobileFullscreen && 13069 this.options.detailsView.location !== "custom") || 13070 this.shouldBeScrollable(this.options.detailsView.location), 13071 withToolbar: !(MapSVG.isPhone && 13072 this.options.detailsView.mobileFullscreen && 13073 this.options.detailsView.location !== "custom") && this.shouldBeScrollable(this.options.detailsView.location), 13074 events: { 13075 shown: (detailsController) => { 13076 this.events.trigger("shown.detailsView", this, [this, detailsController]); 13077 $$A(window).trigger("shown.detailsView", [this, detailsController]); 13078 }, 13079 closed: (detailsController) => { 13080 this.deselectAllRegions(); 13081 this.deselectAllMarkers(); 13082 this.controllers && 13083 this.controllers.directory && 13084 this.controllers.directory.deselectItems(); 13085 this.events.trigger("closed.detailsView", [this, detailsController]); 13086 }, 13087 }, 13088 }); 13089 this.controllers.detailsView._init(); 13090 } 13091 loadFiltersModal() { 13092 if (this.options.filters.modalLocation != "custom") { 13093 if (!this.containers.filtersModal) { 13094 this.containers.filtersModal = $$A('<div class="mapsvg-details-container mapsvg-filters-wrap"></div>')[0]; 13095 } 13096 this.setColors(); 13097 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 13098 if (MapSVG.isPhone) { 13099 $$A("body").append($$A(this.containers.filtersModal)); 13100 $$A(this.containers.filtersModal).css({ width: "" }); 13101 } 13102 else { 13103 $$A(this.containers[this.options.filters.modalLocation]).append($$A(this.containers.filtersModal)); 13104 } 13105 } 13106 else { 13107 this.containers.filtersModal = $$A("#" + this.options.filters.containerId)[0]; 13108 $$A(this.containers.filtersModal).css({ width: "" }); 13109 } 13110 this.loadFiltersController(this.containers.filtersModal, true); 13111 } 13112 loadFiltersController(container, modal = false) { 13113 if (!this.filtersShouldBeShown()) { 13114 return; 13115 } 13116 let filtersInDirectory, filtersHide; 13117 if (MapSVG.isPhone) { 13118 filtersInDirectory = true; 13119 filtersHide = this.options.filters.hideOnMobile; 13120 } 13121 else { 13122 filtersInDirectory = 13123 this.options.menu.on && 13124 this.controllers.directory && 13125 this.options.menu.location === this.options.filters.location; 13126 filtersHide = this.options.filters.hide; 13127 } 13128 const scrollable = modal || 13129 (!filtersInDirectory && 13130 ["leftSidebar", "rightSidebar"].indexOf(this.options.filters.location) !== -1); 13131 this.filtersRepository = 13132 this.options.filters.source === "regions" 13133 ? this.regionsRepository 13134 : this.objectsRepository; 13135 if (this.options.filters.searchButton) { 13136 this.changedFields = null; 13137 this.changedSearch = null; 13138 } 13139 else { 13140 this.changedSearch = () => { 13141 this.filtersRepository.query.searchFallback = this.filtersSchema.getFieldByType("search").searchFallback; 13142 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13143 }; 13144 this.changedFields = () => { 13145 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13146 }; 13147 } 13148 this.controllers.filters = new FiltersController({ 13149 container: container, 13150 query: this.filtersRepository.query, 13151 mapsvg: this, 13152 schema: this.filtersSchema, 13153 template: '<div class="mapsvg-filters-container"></div>', 13154 scrollable: scrollable, 13155 modal: modal, 13156 withToolbar: MapSVG.isPhone ? false : modal, 13157 width: $$A(container).hasClass("mapsvg-map-container") 13158 ? this.options.filters.width 13159 : "100%", 13160 hide: this.options.filters.hide, 13161 hideOnMobile: this.options.filters.hideOnMobile, 13162 showButtonText: this.options.filters.showButtonText, 13163 clearButton: this.options.filters.clearButton, 13164 clearButtonText: this.options.filters.clearButtonText, 13165 searchButton: this.options.filters.searchButton, 13166 searchButtonText: this.options.filters.searchButtonText, 13167 padding: this.options.filters.padding, 13168 events: { 13169 cleared: () => { 13170 this.deselectAllRegions(); 13171 this.filtersRepository.reload(); 13172 }, 13173 "changed.fields": this.changedFields, 13174 "changed.search": this.changedSearch, 13175 "click.btn.searchButton": () => { 13176 this.filtersRepository.reload(); 13177 }, 13178 loaded: () => { 13179 this.controllers.directory && this.controllers.directory.updateTopShift(); 13180 this.afterLoadBlockers--; 13181 this.finalizeMapLoading(); 13182 }, 13183 "click.btn.showFilters": () => { 13184 this.loadFiltersModal(); 13185 }, 13186 }, 13187 }); 13188 this.controllers.filters._init(); 13189 } 13190 filtersShouldBeShown() { 13191 return (this.options.filters.on && 13192 this.options.filtersSchema && 13193 this.options.filtersSchema.length > 0); 13194 } 13195 textSearch(text, fallback = false) { 13196 const query = new Query({ 13197 filters: { search: text }, 13198 searchFallback: fallback, 13199 }); 13200 this.filtersRepository.find(query); 13201 } 13202 getRegion(id) { 13203 return this.regions.findById(id); 13204 } 13205 getRegions() { 13206 return this.regions; 13207 } 13208 getMarker(id) { 13209 return this.markers.findById(id); 13210 } 13211 checkId(id) { 13212 if (this.getRegion(id)) 13213 return { canUse: false, error: "This ID is already being used by a Region" }; 13214 else if (this.getMarker(id)) 13215 return { canUse: false, error: "This ID is already being used by another Marker" }; 13216 else 13217 return { canUse: true, error: "" }; 13218 } 13219 regionsRedrawColors() { 13220 this.regions.forEach((region) => { 13221 region.setFill(); 13222 }); 13223 } 13224 redrawBubbles() { 13225 $$A(this.containers.map).removeClass("bubbles-regions-on bubbles-database-on"); 13226 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 13227 $$A(this.containers.map).addClass("bubbles-" + this.options.choropleth.source + "-on"); 13228 } 13229 this.regions.forEach(function (region) { 13230 region.drawBubble(); 13231 }); 13232 const markersBubbleMode = this.options.choropleth.on && 13233 this.options.choropleth.source == "database" && 13234 this.options.choropleth.bubbleMode;
13235 this.markers.forEach(function (marker) { 13236 marker.setBubbleMode(markersBubbleMode); 13237 }); 13238 } 13239 destroy() { 13240 if (this.controllers && this.controllers.directory) { 13241 this.controllers.directory.mobileButtons.remove(); 13242 } 13243 $$A(this.containers.map) 13244 .empty() 13245 .insertBefore($$A(this.containers.wrapAll)) 13246 .attr("style", "") 13247 .removeClass("mapsvg mapsvg-responsive"); 13248 this.controllers.popover && this.controllers.popover.close(); 13249 if (this.controllers.detailsView) 13250 this.controllers.detailsView.destroy(); 13251 $$A(this.containers.detailsView).remove(); 13252 $$A(this.containers.popover).remove(); 13253 $$A(this.containers.tooltip).remove(); 13254 $$A(this.containers.wrapAll).remove(); 13255 } 13256 getData() { 13257 return { 13258 id: this.id, 13259 title: this.options.title, 13260 options: this.getOptions(false, false), 13261 }; 13262 } 13263 mayBeFitMarkers() { 13264 if (!this.lastTimeFitWas) { 13265 this.lastTimeFitWas = Date.now() - 99999; 13266 } 13267 this.fitDelta = Date.now() - this.lastTimeFitWas; 13268 if (this.fitDelta > 1000 && 13269 !this.firstDataLoad && 13270 !this.fitOnDataLoadDone && 13271 this.options.fitMarkers) { 13272 this.fitMarkers(); 13273 this.fitOnDataLoadDone = true; 13274 } 13275 if (this.firstDataLoad && 13276 (this.options.fitMarkersOnStart || 13277 (this.options.fitMarkers && this.options.database.loadOnStart === false))) { 13278 this.firstDataLoad = false; 13279 if (this.options.googleMaps.on && !this.googleMaps.map) { 13280 this.events.on("googleMapsLoaded", () => { 13281 this.fitMarkers(); 13282 }); 13283 } 13284 else { 13285 this.fitMarkers(); 13286 } 13287 } 13288 this.lastTimeFitWas = Date.now(); 13289 } 13290 fitMarkers() { 13291 const dbObjects = this.objectsRepository.getLoaded(); 13292 if (!dbObjects || dbObjects.length === 0) { 13293 return; 13294 } 13295 if (this.options.googleMaps.on && typeof google !== "undefined") { 13296 const lats = []; 13297 const lngs = []; 13298 if (dbObjects.length > 1) { 13299 dbObjects.forEach((object) => { 13300 if (object.location && object.location.geoPoint) { 13301 lats.push(object.location.geoPoint.lat); 13302 lngs.push(object.location.geoPoint.lng); 13303 } 13304 }); 13305 const minlat = Math.min.apply(null, lats), maxlat = Math.max.apply(null, lats); 13306 const minlng = Math.min.apply(null, lngs), maxlng = Math.max.apply(null, lngs); 13307 const bbox = new google.maps.LatLngBounds({ lat: minlat, lng: minlng }, { lat: maxlat, lng: maxlng }); 13308 this.googleMaps.map.fitBounds(bbox, 0); 13309 } 13310 else { 13311 if (dbObjects[0].location && 13312 dbObjects[0].location.geoPoint.lat && 13313 dbObjects[0].location.geoPoint.lng) { 13314 const coords = { 13315 lat: dbObjects[0].location.geoPoint.lat, 13316 lng: dbObjects[0].location.geoPoint.lng, 13317 }; 13318 if (this.googleMaps.map) { 13319 this.googleMaps.map.setCenter(coords); 13320 this.googleMaps.map.setZoom(this.options.fitSingleMarkerZoom); 13321 } 13322 } 13323 } 13324 } 13325 else { 13326 if (this.options.clustering.on) { 13327 const arr = [];
13328 this.markersClusters.forEach((c) => { 13329 arr.push(c); 13330 }); 13331 this.markers.forEach((m) => { 13332 arr.push(m); 13333 }); 13334 this.zoomTo(arr); 13335 return; 13336 } 13337 else { 13338 this.zoomTo(this.markers); 13339 return; 13340 } 13341 } 13342 } 13343 setFitSingleMarkerZoom(zoom) { 13344 this.options.fitSingleMarkerZoom = parseInt(zoom); 13345 } 13346 showUserLocation(callback) { 13347 this.getUserLocation((geoPoint) => { 13348 this.userLocation = null; 13349 this.userLocation = new Location({ 13350 geoPoint: geoPoint, 13351 img: MapSVG.urls.root + "/markers/user-location.svg", 13352 }); 13353 this.userLocationMarker && this.userLocationMarker.delete(); 13354 this.userLocationMarker = new Marker({ 13355 location: this.userLocation, 13356 mapsvg: this, 13357 width: 15, 13358 height: 15, 13359 }); 13360 $$A(this.userLocationMarker.element).addClass("mapsvg-user-location"); 13361 this.userLocationMarker.centered = true; 13362 this.getLayer("markers").append(this.userLocationMarker.element); 13363 this.userLocationMarker.adjustScreenPosition(); 13364 callback && callback(this.userLocation); 13365 }); 13366 } 13367 getUserLocation(callback) { 13368 if (navigator.geolocation) { 13369 navigator.geolocation.getCurrentPosition(function (position) { 13370 const pos = new GeoPoint(position.coords.latitude, position.coords.longitude); 13371 callback && callback(pos); 13372 }); 13373 } 13374 else { 13375 return false; 13376 } 13377 } 13378 getScale() { 13379 const scale2 = this.containers.map.clientWidth / this.viewBox.width; 13380 return scale2 || 1; 13381 } 13382 getViewBox() { 13383 return this.viewBox; 13384 }
13385 viewBoxSetBySize(width, height) { 13386 this.setSize(width, height); 13387 this._viewBox.update(this.viewBoxGetBySize(width, height)); 13388 this.setViewBox(this._viewBox); 13389 $$A(window).trigger("resize"); 13390 this.setSize(width, height); 13391 this.setZoomLevels(); 13392 return this.viewBox; 13393 } 13394 viewBoxGetBySize(width, height) { 13395 const new_ratio = width / height; 13396 const old_ratio = this.svgDefault.viewBox.width / this.svgDefault.viewBox.height; 13397 const vb = this.svgDefault.viewBox.clone(); 13398 if (new_ratio != old_ratio) { 13399 if (new_ratio > old_ratio) { 13400 vb.width = this.svgDefault.viewBox.height * new_ratio; 13401 vb.x = this.svgDefault.viewBox.x - (vb.width - this.svgDefault.viewBox.width) / 2; 13402 } 13403 else { 13404 vb.height = this.svgDefault.viewBox.width / new_ratio; 13405 vb.y = this.svgDefault.viewBox.y - (vb.height - this.svgDefault.viewBox.height) / 2; 13406 } 13407 } 13408 return vb; 13409 }
13410 viewBoxReset(toInitial) { 13411 if (this.options.googleMaps.on && this.googleMaps.map) { 13412 if (!toInitial) { 13413 this.options.googleMaps.center = null; 13414 this.options.googleMaps.zoom = null; 13415 } 13416 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 13417 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 13418 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 13419 const bounds = new google.maps.LatLngBounds(southWest, northEast); 13420 this.googleMaps.map.fitBounds(bounds, 0); 13421 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 13422 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 13423 } 13424 else { 13425 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 13426 this.googleMaps.map.setCenter(this.options.googleMaps.center); 13427 } 13428 } 13429 else { 13430 if (toInitial) { 13431 const v = this._viewBox || this.svgDefault.viewBox; 13432 this.zoomLevel = 0; 13433 this._scale = 1; 13434 this.setViewBox(v); 13435 } 13436 else { 13437 this.setViewBox(); 13438 } 13439 } 13440 return this.viewBox; 13441 } 13442 getGeoViewBox() { 13443 const v = this.viewBox; 13444 const p1 = new SVGPoint(v.x, v.y); 13445 const p2 = new SVGPoint(v.x + v.width, v.y); 13446 const p3 = new SVGPoint(v.x, v.y); 13447 const p4 = new SVGPoint(v.x, v.y + v.height); 13448 const leftLon = this.converter.convertSVGToGeo(p1).lng; 13449 const rightLon = this.converter.convertSVGToGeo(p2).lng; 13450 const topLat = this.converter.convertSVGToGeo(p3).lat; 13451 const bottomLat = this.converter.convertSVGToGeo(p4).lat; 13452 return [leftLon, topLat, rightLon, bottomLat]; 13453 } 13454 setStrokes() { 13455 $$A(this.containers.svg) 13456 .find("path, polygon, circle, ellipse, rect, line, polyline") 13457 .each((index, elem) => { 13458 const width = MapObject.getComputedStyle("stroke-width", elem); 13459 if (width) { 13460 $$A(elem).attr("data-stroke-width", width.replace("px", "")); 13461 } 13462 }); 13463 } 13464 adjustStrokes() { 13465 $$A(this.containers.svg) 13466 .find("path, polygon, circle, ellipse, rect, line, polyline") 13467 .each((index, elem) => { 13468 const width = elem.getAttribute("data-stroke-width"); 13469 if (width) { 13470 $$A(elem).css("stroke-width", Number(width) / this.scale); 13471 } 13472 }); 13473 } 13474 zoomIn(center) { 13475 if (this.canZoom) { 13476 this.isZooming = true; 13477 this.canZoom = false;
13478 setTimeout(() => { 13479 this.isZooming = false; 13480 this.canZoom = true; 13481 }, 700); 13482 this.zoom(1, center); 13483 } 13484 } 13485 zoomOut(center) { 13486 if (this.canZoom) { 13487 this.isZooming = true; 13488 this.canZoom = false; 13489 setTimeout(() => { 13490 this.isZooming = false; 13491 this.canZoom = true; 13492 }, 700); 13493 this.zoom(-1, center); 13494 } 13495 } 13496 zoomTo(mapObjects, zoomToLevel) { 13497 if (mapObjects instanceof Marker || mapObjects instanceof MarkerCluster) { 13498 return this.zoomToMarkerOrCluster(mapObjects, zoomToLevel); 13499 } 13500 else { 13501 const convertedObjects = !Array.isArray(mapObjects) ? [mapObjects] : mapObjects; 13502 const bbox = this.getGroupBBox(convertedObjects); 13503 return this.fitViewBox(bbox, zoomToLevel); 13504 } 13505 } 13506 zoomToMarkerOrCluster(mapObject, zoomToLevel) { 13507 this.zoomLevel = zoomToLevel || 1; 13508 const foundZoomLevel = this.zoomLevels.get(this.zoomLevel); 13509 if (!foundZoomLevel) { 13510 return false; 13511 } 13512 const vb = foundZoomLevel.viewBox; 13513 if (this.canZoom) { 13514 this.isZooming = true; 13515 this.canZoom = false;
13516 setTimeout(() => { 13517 this.isZooming = false; 13518 this.canZoom = true; 13519 }, 700); 13520 const vbNew = new ViewBox(mapObject.svgPoint.x - vb.width / 2, mapObject.svgPoint.y - vb.height / 2, vb.width, vb.height); 13521 this.setViewBox(vbNew); 13522 this._scale = foundZoomLevel._scale; 13523 return true; 13524 } 13525 return false; 13526 } 13527 getGroupBBox(mapObjects) { 13528 let _bbox; 13529 const xmax = []; 13530 const ymax = []; 13531 const xmin = []; 13532 const ymin = []; 13533 for (let i = 0; i < mapObjects.length; i++) { 13534 _bbox = mapObjects[i].getBBox(); 13535 xmin.push(_bbox.x); 13536 ymin.push(_bbox.y); 13537 const _w = _bbox.x + _bbox.width; 13538 const _h = _bbox.y + _bbox.height; 13539 xmax.push(_w); 13540 ymax.push(_h); 13541 } 13542 const _xmin = Math.min(...xmin); 13543 const _ymin = Math.min(...ymin); 13544 const width = Math.max(...xmax) - _xmin; 13545 const height = Math.max(...ymax) - _ymin; 13546 let padding = 10; 13547 const point1 = new ScreenPoint(padding, 0); 13548 const point2 = new ScreenPoint(0, 0); 13549 padding = 13550 this.converter.convertPixelToSVG(point1).x - this.converter.convertPixelToSVG(point2).x; 13551 return new ViewBox(_xmin - padding, _ymin - padding, width + padding * 2, height + padding * 2); 13552 } 13553 fitViewBox(fitViewBox, forceZoomLevel) { 13554 let viewBoxPrev; 13555 let foundZoomLevelNumber = 0; 13556 let foundZoomLevel; 13557 let newViewBox;
13558 this.zoomLevels.forEach((zoomLevel) => { 13559 if (viewBoxPrev && viewBoxPrev.x !== undefined) { 13560 if (fitViewBox.fitsInViewBox(viewBoxPrev) && 13561 zoomLevel.viewBox.fitsInViewBox(fitViewBox, true)) { 13562 foundZoomLevelNumber = forceZoomLevel ? forceZoomLevel : zoomLevel.zoomLevel; 13563 foundZoomLevel = this.zoomLevels.get(foundZoomLevelNumber); 13564 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); 13565 } 13566 } 13567 viewBoxPrev = zoomLevel && zoomLevel.viewBox; 13568 }); 13569 if (foundZoomLevel) { 13570 if (this.canZoom) { 13571 this.isZooming = true; 13572 this.canZoom = false; 13573 setTimeout(() => { 13574 this.isZooming = false; 13575 this.canZoom = true; 13576 }, 700); 13577 this.zoomLevel = foundZoomLevelNumber; 13578 this._scale = foundZoomLevel._scale; 13579 this.setViewBox(newViewBox); 13580 return true; 13581 } 13582 } 13583 else { 13584 return false; 13585 } 13586 } 13587 zoomToRegion(region, zoomToLevel) { 13588 this.fitViewBox(region.getBBox(), zoomToLevel); 13589 return true; 13590 } 13591 centerOn(region, yShift) { 13592 if (this.options.googleMaps.on) { 13593 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13594 $$A(this.containers.map).addClass("scrolling"); 13595 const latLng = region.getCenterLatLng(yShift); 13596 this.googleMaps.map.panTo(latLng); 13597 setTimeout(() => { 13598 $$A(this.containers.map).removeClass("scrolling"); 13599 }, 100); 13600 } 13601 else { 13602 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13603 const bbox = region.getBBox(); 13604 const vb = this.viewBox; 13605 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); 13606 this.setViewBox(newViewBox); 13607 } 13608 } 13609 zoom(delta, center) { 13610 let newViewBox = new ViewBox(0, 0, 0, 0); 13611 const d = delta > 0 ? 1 : -1; 13612 if (!this.zoomLevels.get(this.zoomLevel + d)) 13613 return;
13614 const newZoomLevel = this.zoomLevel + d; 13615 const zoomIn = d > 0; 13616 const zoomOut = d < 0; 13617 const zoomRange = this.getZoomRange(); 13618 const isInZoomRange = this.zoomLevel >= zoomRange.min && this.zoomLevel <= zoomRange.max; 13619 const goingOutOfZoomRange = isInZoomRange && (newZoomLevel > zoomRange.max || newZoomLevel < zoomRange.min); 13620 const outOfRangeAndMovingAway = !isInZoomRange && 13621 ((zoomIn && newZoomLevel > zoomRange.max) || (zoomOut && newZoomLevel < zoomRange.min)); 13622 if (goingOutOfZoomRange || outOfRangeAndMovingAway) { 13623 return; 13624 } 13625 this.zoomLevel = newZoomLevel; 13626 const z = this.zoomLevels.get(this.zoomLevel); 13627 this._scale = z._scale; 13628 newViewBox = z.viewBox; 13629 let shift = []; 13630 if (center) { 13631 const koef = zoomIn ? 0.5 : -1; 13632 newViewBox.x = this.viewBox.x + (center.x - this.viewBox.x) * koef; 13633 newViewBox.y = this.viewBox.y + (center.y - this.viewBox.y) * koef; 13634 } 13635 else { 13636 shift = [ 13637 (this.viewBox.width - newViewBox.width) / 2, 13638 (this.viewBox.height - newViewBox.height) / 2, 13639 ]; 13640 newViewBox.x = this.viewBox.x + shift[0]; 13641 newViewBox.y = this.viewBox.y + shift[1]; 13642 } 13643 this.shiftViewBoxToScrollBoundaries(newViewBox); 13644 this.setViewBox(newViewBox); 13645 } 13646 toggleSvgLayerOnZoom() { 13647 if (this.options.googleMaps.on && 13648 this.googleMaps.map && 13649 this.options.zoom.hideSvg && 13650 this.googleMaps.map.getZoom() >= this.options.zoom.hideSvgZoomLevel) { 13651 if (!$$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13652 $$A(this.containers.svg).animate({ opacity: 0 }, 400, "linear", () => { 13653 $$A(this.containers.svg).addClass("mapsvg-invisible"); 13654 }); 13655 } 13656 } 13657 else { 13658 if ($$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13659 $$A(this.containers.svg).animate({ opacity: 1 }, 400, "linear", () => { 13660 $$A(this.containers.svg).removeClass("mapsvg-invisible"); 13661 }); 13662 } 13663 } 13664 } 13665 shiftViewBoxToScrollBoundaries(newViewBox) { 13666 if (this.options.scroll.limit) { 13667 if (newViewBox.x < this.svgDefault.viewBox.x) 13668 newViewBox.x = this.svgDefault.viewBox.x; 13669 else if (newViewBox.x + newViewBox.width > 13670 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13671 newViewBox.x = 13672 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - newViewBox.width; 13673 if (newViewBox.y < this.svgDefault.viewBox.y) 13674 newViewBox.y = this.svgDefault.viewBox.y; 13675 else if (newViewBox.y + newViewBox.height > 13676 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13677 newViewBox.y = 13678 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height - newViewBox.height; 13679 } 13680 return newViewBox; 13681 } 13682 markerDelete(marker) { 13683 if (this.editingMarker && this.editingMarker.id == marker.id) { 13684 this.unsetEditingMarker(); 13685 } 13686 if (this.markers.findById(marker.id)) { 13687 this.markers.delete(marker.id); 13688 } 13689 marker.delete(); 13690 marker = null; 13691 if (this.markers.length === 0) 13692 this.options.markerLastID = 0; 13693 } 13694 markersClusterAdd(markersCluster) { 13695 this.layers.markers.append(markersCluster.elem); 13696 this.markersClusters.push(markersCluster); 13697 markersCluster.adjustScreenPosition(); 13698 } 13699 markerAdd(marker) { 13700 $$A(marker.element).hide(); 13701 marker.adjustScreenPosition(); 13702 this.layers.markers.append(marker.element); 13703 this.markers.push(marker); 13704 marker.mapped = true; 13705 setTimeout(function () { 13706 $$A(marker.element).show(); 13707 }, 100); 13708 } 13709 markerRemove(marker) { 13710 if (this.editingMarker && this.editingMarker.id == marker.id) { 13711 this.editingMarker = null; 13712 delete this.editingMarker; 13713 } 13714 if (this.markers.findById(marker.id)) { 13715 this.markers.findById(marker.id).element.remove(); 13716 this.markers.delete(marker.id); 13717 marker = null; 13718 } 13719 if (this.markers.length === 0) 13720 this.options.markerLastID = 0; 13721 } 13722 markerId() { 13723 this.options.markerLastID = this.options.markerLastID + 1; 13724 const id = "marker_" + this.options.markerLastID; 13725 if (this.getMarker(id)) 13726 return this.markerId(); 13727 else 13728 return id; 13729 } 13730 movingItemsAdjustScreenPosition() { 13731 this.markersAdjustScreenPosition(); 13732 this.popoverAdjustScreenPosition(); 13733 this.bubblesRegionsAdjustScreenPosition(); 13734 this.labelsRegionsAdjustScreenPosition(); 13735 } 13736 movingItemsMoveScreenPositionBy(deltaX, deltaY) { 13737 this.markersMoveScreenPositionBy(deltaX, deltaY); 13738 this.popoverMoveScreenPositionBy(deltaX, deltaY); 13739 this.bubblesRegionsMoveScreenPositionBy(deltaX, deltaY); 13740 this.labelsRegionsMoveScreenPositionBy(deltaX, deltaY); 13741 } 13742 labelsRegionsAdjustScreenPosition() { 13743 if ($$A(this.containers.map).is(":visible")) { 13744 this.regions.forEach(function (region) { 13745 region.adjustLabelScreenPosition(); 13746 }); 13747 } 13748 } 13749 bubblesRegionsAdjustScreenPosition() { 13750 if ($$A(this.containers.map).is(":visible")) { 13751 this.regions.forEach(function (region) { 13752 region.adjustBubbleScreenPosition(); 13753 }); 13754 } 13755 } 13756 labelsRegionsMoveScreenPositionBy(deltaX, deltaY) { 13757 if ($$A(this.containers.map).is(":visible")) { 13758 this.regions.forEach(function (region) { 13759 region.moveLabelScreenPositionBy(deltaX, deltaY); 13760 }); 13761 } 13762 } 13763 bubblesRegionsMoveScreenPositionBy(deltaX, deltaY) { 13764 if ($$A(this.containers.map).is(":visible")) { 13765 this.regions.forEach((region) => { 13766 region.moveBubbleScreenPositionBy(deltaX, deltaY); 13767 }); 13768 } 13769 } 13770 markersAdjustScreenPosition() {
13771 this.markers.forEach((marker) => { 13772 marker.adjustScreenPosition(); 13773 }); 13774 this.markersClusters.forEach((cluster) => { 13775 cluster.adjustScreenPosition(); 13776 }); 13777 if (this.userLocationMarker) { 13778 this.userLocationMarker.adjustScreenPosition(); 13779 } 13780 } 13781 markersMoveScreenPositionBy(deltaX, deltaY) { 13782 this.markers.forEach((marker) => { 13783 marker.moveSrceenPositionBy(deltaX, deltaY); 13784 }); 13785 this.markersClusters.forEach((cluster) => { 13786 cluster.moveSrceenPositionBy(deltaX, deltaY); 13787 }); 13788 if (this.userLocationMarker) { 13789 this.userLocationMarker.moveSrceenPositionBy(deltaX, deltaY); 13790 } 13791 } 13792 setEditingMarker(marker) { 13793 this.editingMarker = marker; 13794 if (!this.editingMarker.mapped) { 13795 this.editingMarker.needToRemove = true; 13796 this.markerAdd(this.editingMarker); 13797 } 13798 } 13799 unsetEditingMarker() { 13800 if (this.editingMarker && this.editingMarker.needToRemove) { 13801 this.markerRemove(this.editingMarker); 13802 } 13803 this.editingMarker = null; 13804 } 13805 getEditingMarker() { 13806 return this.editingMarker; 13807 } 13808 scrollStart(e, mapsvg) { 13809 if ($$A(e.target).hasClass("mapsvg-btn-map") || 13810 $$A(e.target).closest(".mapsvg-choropleth").length) 13811 return; 13812 if (this.editMarkers.on && $$A(e.target).hasClass("mapsvg-marker")) 13813 return; 13814 e.preventDefault(); 13815 $$A(this.containers.map).addClass("no-transitions"); 13816 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13817 ? e.originalEvent.touches[0] 13818 : e; 13819 this.scrollStarted = true; 13820 this.scroll = { 13821 tx: this.scroll.tx || 0, 13822 ty: this.scroll.ty || 0, 13823 vxi: this.viewBox.x, 13824 vyi: this.viewBox.y, 13825 x: ce.clientX, 13826 y: ce.clientY, 13827 dx: 0, 13828 dy: 0, 13829 vx: 0, 13830 vy: 0, 13831 gx: ce.clientX, 13832 gy: ce.clientY, 13833 touchScrollStart: 0, 13834 }; 13835 if (e.type.indexOf("mouse") === 0) { 13836 $$A(document).on("mousemove.scroll.mapsvg", (e) => { 13837 this.scrollMove(e); 13838 }); 13839 if (this.options.scroll.spacebar) { 13840 $$A(document).on("keyup.scroll.mapsvg", (e) => { 13841 if (e.keyCode == 32) { 13842 this.scrollEnd(e, mapsvg); 13843 } 13844 }); 13845 } 13846 else { 13847 $$A(document).on("mouseup.scroll.mapsvg", (e) => { 13848 this.scrollEnd(e, mapsvg); 13849 }); 13850 } 13851 } 13852 } 13853 scrollMove(e) { 13854 e.preventDefault(); 13855 if (!this.isScrolling) { 13856 this.isScrolling = true; 13857 $$A(this.containers.map).addClass("scrolling"); 13858 } 13859 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13860 ? e.originalEvent.touches[0] 13861 : e; 13862 this.panBy(this.scroll.gx - ce.clientX, this.scroll.gy - ce.clientY); 13863 this.scroll.gx = ce.clientX; 13864 this.scroll.gy = ce.clientY; 13865 this.scroll.dx = this.scroll.x - ce.clientX; 13866 this.scroll.dy = this.scroll.y - ce.clientY; 13867 let vx = this.scroll.vxi + this.scroll.dx / this.scale; 13868 let vy = this.scroll.vyi + this.scroll.dy / this.scale; 13869 if (this.options.scroll.limit) { 13870 if (vx < this.svgDefault.viewBox.x) 13871 vx = this.svgDefault.viewBox.x; 13872 else if (this.viewBox.width + vx > 13873 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13874 vx = this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - this.viewBox.width; 13875 if (vy < this.svgDefault.viewBox.y) 13876 vy = this.svgDefault.viewBox.y; 13877 else if (this.viewBox.height + vy > 13878 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13879 vy = 13880 this.svgDefault.viewBox.y + 13881 this.svgDefault.viewBox.height - 13882 this.viewBox.height; 13883 } 13884 this.scroll.vx = vx; 13885 this.scroll.vy = vy; 13886 } 13887 scrollEnd(e, mapsvg, noClick) { 13888 setTimeout(() => { 13889 this.enableAnimation(); 13890 this.scrollStarted = false;
13891 this.isScrolling = false; 13892 }, 100); 13893 if (this.googleMaps && this.googleMaps.overlay) { 13894 this.googleMaps.overlay.draw(); 13895 } 13896 $$A(this.containers.map).removeClass("scrolling"); 13897 $$A(document).off("keyup.scroll.mapsvg"); 13898 $$A(document).off("mousemove.scroll.mapsvg"); 13899 $$A(document).off("mouseup.scroll.mapsvg"); 13900 if (noClick !== true && Math.abs(this.scroll.dx) < 5 && Math.abs(this.scroll.dy) < 5) { 13901 if (this.editMarkers.on) 13902 this.clickAddsMarker && this.markerAddClickHandler(e); 13903 else if (this.objectClickedBeforeScroll) 13904 if (this.objectClickedBeforeScroll instanceof Marker) { 13905 this.markerClickHandler(e, this.objectClickedBeforeScroll); 13906 } 13907 else if (this.objectClickedBeforeScroll instanceof Region) { 13908 this.regionClickHandler(e, this.objectClickedBeforeScroll); 13909 } 13910 else if (this.objectClickedBeforeScroll instanceof MarkerCluster) { 13911 this.markerClusterClickHandler(e, this.objectClickedBeforeScroll); 13912 } 13913 } 13914 this.viewBox.x = this.scroll.vx || this.viewBox.x; 13915 this.viewBox.y = this.scroll.vy || this.viewBox.y; 13916 } 13917 setViewBoxByGoogleMapsOverlay() { 13918 const bounds = this.googleMaps.overlay.getPixelBounds(); 13919 const scale = (bounds.ne.x - bounds.sw.x) / this.svgDefault.viewBox.width; 13920 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); 13921 this.setViewBox(vb, false); 13922 } 13923 panBy(x, y) { 13924 let tx = this.scroll.tx - x; 13925 let ty = this.scroll.ty - y; 13926 const scrolled = { x: true, y: true }; 13927 if (this.options.scroll.limit) { 13928 const svg = $$A(this.containers.svg)[0].getBoundingClientRect(); 13929 const bounds = $$A(this.containers.map)[0].getBoundingClientRect(); 13930 if ((svg.left - x > bounds.left && x < 0) || (svg.right - x < bounds.right && x > 0)) { 13931 tx = this.scroll.tx; 13932 scrolled.x = false; 13933 } 13934 if ((svg.top - y > bounds.top && y < 0) || (svg.bottom - y < bounds.bottom && y > 0)) { 13935 ty = this.scroll.ty; 13936 scrolled.y = false; 13937 } 13938 } 13939 $$A(this.containers.scrollpane).css({ 13940 transform: "translate(" + tx + "px," + ty + "px)", 13941 }); 13942 this.scroll.tx = tx; 13943 this.scroll.ty = ty; 13944 if (scrolled.x || scrolled.y) { 13945 const moveX = scrolled.x ? x : 0; 13946 const moveY = scrolled.y ? y : 0; 13947 this.movingItemsMoveScreenPositionBy(moveX, moveY); 13948 if (this.googleMaps.map) { 13949 let point = this.googleMaps.map.getCenter(); 13950 const projection = this.googleMaps.overlay.getProjection(); 13951 const pixelpoint = projection.fromLatLngToDivPixel(point); 13952 pixelpoint.x += moveX; 13953 pixelpoint.y += moveY; 13954 point = projection.fromDivPixelToLatLng(pixelpoint); 13955 this.googleMaps.map.setCenter(point); 13956 } 13957 } 13958 return scrolled; 13959 } 13960 setObjectClickedBeforeScroll(object) { 13961 this.objectClickedBeforeScroll = object; 13962 } 13963 touchStart(_e, mapsvg) { 13964 _e.preventDefault(); 13965 if (this.scrollStarted) { 13966 this.scrollEnd(_e, mapsvg, true); 13967 } 13968 const e = _e.originalEvent; 13969 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13970 this.touchZoomStart = true; 13971 this.scaleDistStart = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY); 13972 } 13973 else if (e.touches && e.touches.length == 1) { 13974 this.scrollStart(_e, mapsvg); 13975 } 13976 $$A(document) 13977 .on("touchmove.scroll.mapsvg", (e) => { 13978 e.preventDefault(); 13979 this.touchMove(e, this); 13980 }) 13981 .on("touchend.scroll.mapsvg", (e) => { 13982 e.preventDefault(); 13983 this.touchEnd(e, this); 13984 }); 13985 } 13986 touchMove(_e, mapsvg) { 13987 _e.preventDefault(); 13988 const e = _e.originalEvent; 13989 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13990 if (!MapSVG.ios) { 13991 e.scale = 13992 Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY) / this.scaleDistStart; 13993 } 13994 if (e.scale != 1 && this.canZoom) { 13995 const d = e.scale > 1 ? 1 : -1; 13996 const cx = e.touches[0].pageX >= e.touches[1].pageX 13997 ? e.touches[0].pageX - 13998 (e.touches[0].pageX - e.touches[1].pageX) / 2 - 13999 $$A(this.containers.map).offset().left 14000 : e.touches[1].pageX - 14001 (e.touches[1].pageX - e.touches[0].pageX) / 2 - 14002 $$A(this.containers.map).offset().left; 14003 const cy = e.touches[0].pageY >= e.touches[1].pageY 14004 ? e.touches[0].pageY - 14005 (e.touches[0].pageY - e.touches[1].pageY) - 14006 $$A(this.containers.map).offset().top 14007 : e.touches[1].pageY - 14008 (e.touches[1].pageY - e.touches[0].pageY) - 14009 $$A(this.containers.map).offset().top; 14010 const center = this.converter.convertPixelToSVG(new ScreenPoint(cx, cy)); 14011 if (d > 0) 14012 this.zoomIn(center); 14013 else 14014 this.zoomOut(center); 14015 } 14016 } 14017 else if (e.touches && e.touches.length == 1) { 14018 this.scrollMove(_e); 14019 } 14020 } 14021 touchEnd(_e, mapsvg) { 14022 _e.preventDefault(); 14023 const e = _e.originalEvent; 14024 if (this.touchZoomStart) { 14025 this.touchZoomStart = false;
14026 } 14027 else if (this.scrollStarted) { 14028 this.scrollEnd(_e, mapsvg); 14029 } 14030 $$A(document).off("touchmove.scroll.mapsvg"); 14031 $$A(document).off("touchend.scroll.mapsvg"); 14032 } 14033 getSelected() { 14034 return this.selected_id; 14035 } 14036 selectRegion(id, skipDirectorySelection) { 14037 let region; 14038 if (typeof id == "string") { 14039 region = this.getRegion(id); 14040 } 14041 else { 14042 region = id; 14043 } 14044 if (!region) 14045 return; 14046 let ids; 14047 if (this.options.multiSelect && !this.editRegions.on) { 14048 if (region.selected) { 14049 this.deselectRegion(region); 14050 if (!skipDirectorySelection && this.options.menu.on) { 14051 if (this.options.menu.source == "database") { 14052 if (region.objects && region.objects.length) { 14053 ids = region.objects.map((obj) => { 14054 return obj.id.toString(); 14055 }); 14056 } 14057 } 14058 else { 14059 ids = [region.id]; 14060 } 14061 this.controllers.directory.deselectItems(); 14062 } 14063 return; 14064 } 14065 } 14066 else if (this.selected_id.length > 0) { 14067 this.deselectAllRegions(); 14068 if (!skipDirectorySelection && this.options.menu.on) { 14069 if (this.options.menu.source == "database") { 14070 if (region.objects && region.objects.length) { 14071 ids = region.objects.map((obj) => { 14072 return obj.id.toString(); 14073 }); 14074 } 14075 } 14076 else { 14077 ids = [region.id]; 14078 } 14079 this.controllers.directory.deselectItems(); 14080 } 14081 } 14082 this.selected_id.push(region.id); 14083 region.select(); 14084 const skip = this.options.actions.region.click.filterDirectory; 14085 if (!skip && 14086 !skipDirectorySelection && 14087 this.options.menu.on && 14088 this.controllers && 14089 this.controllers.directory) { 14090 if (this.options.menu.source == "database") { 14091 if (region.objects && region.objects.length) { 14092 ids = region.objects.map((obj) => { 14093 return obj.id.toString(); 14094 }); 14095 } 14096 else { 14097 ids = [region.id]; 14098 } 14099 } 14100 else { 14101 ids = [region.id]; 14102 } 14103 this.controllers.directory.selectItems(ids); 14104 } 14105 if (this.options.actions.region.click.addIdToUrl && 14106 !this.options.actions.region.click.showAnotherMap) { 14107 window.location.hash = "/m/" + region.id; 14108 } 14109 } 14110 deselectAllRegions() { 14111 $$A.each(this.selected_id, (index, id) => { 14112 this.deselectRegion(this.getRegion(id)); 14113 }); 14114 } 14115 deselectRegion(region) { 14116 if (!region) 14117 region = this.getRegion(this.selected_id[0]); 14118 if (region) { 14119 region.deselect(); 14120 const i = $$A.inArray(region.id, this.selected_id); 14121 this.selected_id.splice(i, 1); 14122 } 14123 if (this.options.actions.region.click.addIdToUrl) { 14124 if (window.location.hash.indexOf(region.id) !== -1) { 14125 history.replaceState(null, null, " "); 14126 } 14127 } 14128 } 14129 highlightRegions(regions) { 14130 regions.forEach((region) => { 14131 if (region && !region.selected && !region.disabled) { 14132 this.highlightedRegions.push(region); 14133 region.highlight(); 14134 } 14135 }); 14136 } 14137 unhighlightRegions() { 14138 this.highlightedRegions.forEach((region) => { 14139 if (region && !region.selected && !region.disabled) 14140 region.unhighlight(); 14141 }); 14142 this.highlightedRegions = []; 14143 } 14144 selectMarker(marker) { 14145 if (!(marker instanceof Marker)) 14146 return; 14147 this.deselectAllMarkers(); 14148 marker.select(); 14149 this.selected_marker = marker; 14150 $$A(this.layers.markers).addClass("mapsvg-with-marker-active"); 14151 if (this.options.menu.on && this.options.menu.source == "database") { 14152 this.controllers.directory.deselectItems(); 14153 this.controllers.directory.selectItems(marker.object.id); 14154 } 14155 } 14156 deselectAllMarkers() { 14157 this.selected_marker && this.selected_marker.deselect(); 14158 $$A(this.layers.markers).removeClass("mapsvg-with-marker-active"); 14159 } 14160 deselectMarker(marker) { 14161 if (marker) { 14162 marker.deselect(); 14163 } 14164 } 14165 highlightMarker(marker) { 14166 $$A(this.layers.markers).addClass("mapsvg-with-marker-hover"); 14167 marker.highlight(); 14168 this.highlighted_marker = marker; 14169 } 14170 unhighlightMarker() { 14171 $$A(this.layers.markers).removeClass("mapsvg-with-marker-hover"); 14172 this.highlighted_marker && this.highlighted_marker.unhighlight(); 14173 } 14174 convertMouseToSVG(e) { 14175 const mc = MapSVG.mouseCoords(e); 14176 const x = mc.x - $$A(this.containers.map).offset().left; 14177 const y = mc.y - $$A(this.containers.map).offset().top; 14178 const screenPoint = new ScreenPoint(x, y); 14179 return this.converter.convertPixelToSVG(screenPoint); 14180 } 14181 pickChoroplethColor(choroplethValue) { 14182 const w = (choroplethValue - this.options.choropleth.coloring.gradient.values.min) / 14183 this.options.choropleth.coloring.gradient.values.maxAdjusted; 14184 const rgba = { 14185 r: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.r * w + 14186 this.options.choropleth.coloring.gradient.colors.lowRGB.r), 14187 g: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.g * w + 14188 this.options.choropleth.coloring.gradient.colors.lowRGB.g), 14189 b: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.b * w + 14190 this.options.choropleth.coloring.gradient.colors.lowRGB.b), 14191 a: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.a * w + 14192 this.options.choropleth.coloring.gradient.colors.lowRGB.a), 14193 }; 14194 return rgba; 14195 } 14196 isRegionDisabled(id, svgfill) { 14197 if (this.options.regions[id] && (this.options.regions[id].disabled || svgfill == "none")) { 14198 return true; 14199 } 14200 else if ((this.options.regions[id] == undefined || 14201 MapSVG.parseBoolean(this.options.regions[id].disabled)) && 14202 (this.options.disableAll || svgfill == "none" || id == "labels" || id == "Labels")) { 14203 return true; 14204 } 14205 else { 14206 return false;
14207 } 14208 } 14209 loadMap(id, container) { 14210 if (!(container instanceof HTMLElement)) { 14211 console.error("Can't load a new map: container was not provided."); 14212 return; 14213 } 14214 const previousMapsIds = [...this.options.previousMapsIds]; 14215 const currentMapId = this.id; 14216 if (previousMapsIds[previousMapsIds.length - 1] !== id) { 14217 previousMapsIds.push(currentMapId); 14218 } 14219 else { 14220 previousMapsIds.pop(); 14221 } 14222 let showPreviousMapButton; 14223 if (typeof this.options.actions.region.click.showAnotherMapContainerId !== "undefined" && 14224 this.options.actions.region.click.showAnotherMapContainerId !== "") { 14225 showPreviousMapButton = false; 14226 } 14227 else { 14228 showPreviousMapButton = this.options.controls.previousMap; 14229 } 14230 const mapsRepo = new MapsRepository(); 14231 const sameContainer = container === this.containers.map; 14232 mapsRepo.findById(id).done((map) => { 14233 sameContainer && this.destroy(); 14234 const newMap = new MapSVGMap(container.getAttribute("id"), map); 14235 newMap.events.on("afterLoad", function () { 14236 this.options.previousMapsIds = previousMapsIds; 14237 this.options.controls.previousMap = showPreviousMapButton; 14238 this.setControls(this.options.controls); 14239 }); 14240 }); 14241 } 14242 loadPreviousMap() { 14243 const previousMapId = this.options.previousMapsIds[this.options.previousMapsIds.length - 1]; 14244 const container = document.getElementById(this.containerId); 14245 this.loadMap(previousMapId, container); 14246 } 14247 markerClusterClickHandler(e, markerCluster) { 14248 this.objectClickedBeforeScroll = null; 14249 if (this.eventsPreventList["click"]) 14250 return; 14251 this.zoomTo(markerCluster.markers); 14252 return; 14253 } 14254 regionClickHandler(e, region) { 14255 this.objectClickedBeforeScroll = null; 14256 if (this.eventsPreventList["click"]) 14257 return; 14258 this.selectRegion(region.id); 14259 if (this.editRegions.on) { 14260 this.regionEditHandler.call(region); 14261 return; 14262 } 14263 const actions = this.options.actions; 14264 if (actions.region.click.zoom) { 14265 this.zoomTo(region, parseInt(actions.region.click.zoomToLevel)); 14266 } 14267 if (actions.region.click.filterDirectory) { 14268 const query = new Query({ 14269 filters: { 14270 regions: { 14271 table_name: this.regionsRepository.getSchema().name, 14272 region_ids: [region.id], 14273 }, 14274 }, 14275 }); 14276 this.objectsRepository.query.resetFilters(); 14277 this.setFilterOut(); 14278 this.objectsRepository.find(query).done(() => { 14279 if (this.controllers.popover) { 14280 this.controllers.popover.redraw(region.forTemplate()); 14281 } 14282 if (this.controllers.detailsView) { 14283 this.controllers.detailsView.redraw(region.forTemplate()); 14284 } 14285 }); 14286 this.updateFiltersState(); 14287 }
14288 if (actions.region.click.showDetails) { 14289 this.loadDetailsView(region); 14290 } 14291 if (actions.region.click.showPopover) { 14292 if (actions.region.click.zoom) { 14293 setTimeout(() => { 14294 this.showPopover(region); 14295 }, 400); 14296 } 14297 else { 14298 this.showPopover(region); 14299 } 14300 } 14301 else if (e && e.type.indexOf("touch") !== -1 && actions.region.touch.showPopover) { 14302 if (actions.region.click.zoom) { 14303 setTimeout(() => { 14304 this.showPopover(region); 14305 }, 400); 14306 } 14307 else { 14308 this.showPopover(region); 14309 } 14310 } 14311 if (actions.region.click.goToLink) { 14312 const linkParts = actions.region.click.linkField.split("."); 14313 let url; 14314 if (linkParts.length > 1) { 14315 const obj = linkParts.shift(); 14316 const attr = "." + linkParts.join("."); 14317 if (obj == "Region") { 14318 if (region.data) { 14319 try { 14320 url = eval("region.data" + attr); 14321 } 14322 catch (err) { 14323 console.log("No such field as region.data" + attr); 14324 } 14325 } 14326 } 14327 else { 14328 if (region.objects && region.objects[0]) { 14329 try { 14330 url = eval("region.objects[0]" + attr); 14331 } 14332 catch (err) { 14333 console.log("No such field as region.objects[0]" + attr); 14334 } 14335 } 14336 } 14337 if (url && !this.disableLinks) { 14338 if (this.editMode) { 14339 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14340 return; 14341 } 14342 if (actions.region.click.newTab) { 14343 const win = window.open(url, "_blank"); 14344 win.focus(); 14345 } 14346 else { 14347 window.location.href = url; 14348 } 14349 } 14350 } 14351 } 14352 if (actions.region.click.showAnotherMap) { 14353 if (this.editMode) { 14354 alert('"Show another map" action is disabled in the preview'); 14355 return; 14356 } 14357 const linkParts = actions.region.click.showAnotherMapField.split("."); 14358 if (linkParts.length > 1) { 14359 const obj = linkParts.shift(); 14360 const attr = "." + linkParts.join("."); 14361 let map_id; 14362 if (obj == "Region") { 14363 if (region.data) 14364 map_id = eval("region.data" + attr); 14365 } 14366 else { 14367 if (region.objects && region.objects[0]) 14368 map_id = eval("region.objects[0]" + attr); 14369 } 14370 if (map_id) { 14371 const container = actions.region.click.showAnotherMapContainerId 14372 ? $$A("#" + actions.region.click.showAnotherMapContainerId)[0] 14373 : $$A(this.containers.map)[0]; 14374 this.loadMap(map_id, container); 14375 } 14376 } 14377 } 14378 this.events.trigger("click.region", region, [e, region, this]); 14379 } 14380 markerClickHandler(e, marker) { 14381 this.objectClickedBeforeScroll = null; 14382 if (this.eventsPreventList["click"]) 14383 return; 14384 const actions = this.options.actions; 14385 this.selectMarker(marker); 14386 const passingObject = marker.object; 14387 if (actions.marker.click.zoom) { 14388 this.zoomTo(marker, parseInt(actions.marker.click.zoomToLevel)); 14389 } 14390 if (actions.marker.click.filterDirectory) { 14391 const query = new Query({ filters: { id: marker.object.id } }); 14392 this.objectsRepository.find(query); 14393 this.updateFiltersState(); 14394 }
14395 if (actions.marker.click.showDetails) 14396 this.loadDetailsView(passingObject); 14397 if (actions.marker.click.showPopover) { 14398 if (actions.marker.click.zoom) { 14399 setTimeout(() => { 14400 this.showPopover(passingObject); 14401 }, 500); 14402 } 14403 else { 14404 this.showPopover(passingObject); 14405 } 14406 } 14407 else if (e && e.type.indexOf("touch") !== -1 && actions.marker.touch.showPopover) { 14408 if (actions.marker.click.zoom) { 14409 setTimeout(() => { 14410 this.showPopover(passingObject); 14411 }, 500); 14412 } 14413 else { 14414 this.showPopover(passingObject); 14415 } 14416 } 14417 if (actions.marker.click.goToLink) { 14418 const linkParts = actions.marker.click.linkField.split("."); 14419 let url; 14420 if (linkParts.length > 1) { 14421 const obj = linkParts.shift(); 14422 const attr = "." + linkParts.join("."); 14423 try { 14424 url = eval("passingObject" + attr); 14425 } 14426 catch (err) { 14427 console.log("MapSVG: No such field as passingObject" + attr); 14428 } 14429 if (url && !this.disableLinks) 14430 if (this.editMode) { 14431 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14432 return; 14433 } 14434 if (actions.marker.click.newTab) { 14435 const win = window.open(url, "_blank"); 14436 win.focus(); 14437 } 14438 else { 14439 window.location.href = url; 14440 } 14441 } 14442 } 14443 this.events.trigger("click.marker", marker, [e, marker, this]); 14444 } 14445 fileExists(url) { 14446 if (url.substr(0, 4) == "data") 14447 return true; 14448 const http = new XMLHttpRequest(); 14449 http.open("HEAD", url, false); 14450 http.send(); 14451 return http.status != 404; 14452 } 14453 hideMarkers() { 14454 this.markers.forEach(function (marker) { 14455 marker.hide(); 14456 }); 14457 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14458 } 14459 hideMarkersExceptOne(id) { 14460 this.markers.forEach(function (marker) { 14461 if (typeof id === "undefined" || (marker.object && id != marker.object.id)) { 14462 marker.hide(); 14463 } 14464 }); 14465 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14466 } 14467 showMarkers() { 14468 this.markers.forEach(function (m) { 14469 m.show(); 14470 }); 14471 this.deselectAllMarkers(); 14472 $$A(this.containers.wrap).removeClass("mapsvg-edit-marker-mode"); 14473 } 14474 markerAddClickHandler(e) { 14475 if ($$A(e.target).hasClass("mapsvg-marker")) 14476 return; 14477 const svgPoint = this.getSvgPointAtClick(e); 14478 const geoPoint = this.isGeo() ? this.converter.convertSVGToGeo(svgPoint) : null; 14479 if (!$$A.isNumeric(svgPoint.x) || !$$A.isNumeric(svgPoint.y)) 14480 return; 14481 if (this.editingMarker) { 14482 if (geoPoint) { 14483 this.editingMarker.location.setGeoPoint(geoPoint); 14484 } 14485 else { 14486 this.editingMarker.location.setSvgPoint(svgPoint); 14487 } 14488 return; 14489 } 14490 const location = new Location({ 14491 svgPoint: svgPoint, 14492 geoPoint: geoPoint, 14493 img: this.options.defaultMarkerImage, 14494 }); 14495 const marker = new Marker({ 14496 location: location, 14497 mapsvg: this, 14498 }); 14499 this.markerAdd(marker); 14500 this.markerEditHandler && this.markerEditHandler.call(location, location); 14501 } 14502 getSvgPointAtClick(e) { 14503 const mc = MapSVG.mouseCoords(e); 14504 const x = mc.x - $$A(this.containers.map).offset().left; 14505 const y = mc.y - $$A(this.containers.map).offset().top; 14506 const screenPoint = new ScreenPoint(x, y); 14507 return this.converter.convertPixelToSVG(screenPoint); 14508 } 14509 setDefaultMarkerImage(src) { 14510 this.options.defaultMarkerImage = src; 14511 } 14512 setMarkerImagesDependency() { 14513 this.locationField = this.objectsRepository.schema.getFieldByType("location"); 14514 if (this.locationField && 14515 this.locationField.markersByFieldEnabled && 14516 this.locationField.markerField && 14517 Object.values(this.locationField.markersByField).length > 0) { 14518 this.setMarkersByField = true; 14519 } 14520 else { 14521 this.setMarkersByField = false;
14522 } 14523 } 14524 getMarkerImage(fieldValueOrObject, location) { 14525 let fieldValue; 14526 if (this.setMarkersByField) { 14527 if (typeof fieldValueOrObject === "object") { 14528 fieldValue = fieldValueOrObject[this.locationField.markerField]; 14529 if (this.locationField.markerField === "regions") { 14530 fieldValue = fieldValue[0] && fieldValue[0].id; 14531 } 14532 else if (typeof fieldValue === "object" && fieldValue.length) { 14533 fieldValue = fieldValue[0].value; 14534 } 14535 } 14536 else { 14537 fieldValue = fieldValueOrObject; 14538 } 14539 if (this.locationField.markersByField[fieldValue]) { 14540 return this.locationField.markersByField[fieldValue]; 14541 } 14542 } 14543 return location && location.imagePath 14544 ? location.imagePath 14545 : this.options.defaultMarkerImage 14546 ? this.options.defaultMarkerImage 14547 : MapSVG.urls.root + "markers/_pin_default.png"; 14548 } 14549 setMarkersEditMode(on, clickAddsMarker) { 14550 this.editMarkers.on = MapSVG.parseBoolean(on); 14551 this.clickAddsMarker = this.editMarkers.on; 14552 this.setEventHandlers(); 14553 } 14554 setRegionsEditMode(on) { 14555 this.editRegions.on = MapSVG.parseBoolean(on); 14556 this.deselectAllRegions(); 14557 this.setEventHandlers(); 14558 } 14559 setEditMode(on) { 14560 this.editMode = on; 14561 } 14562 setDataEditMode(on) { 14563 this.editData.on = MapSVG.parseBoolean(on); 14564 this.deselectAllRegions(); 14565 this.setEventHandlers(); 14566 } 14567 download() { 14568 window.location.href = window.location.origin + this.options.source; 14569 } 14570 popoverAdjustScreenPosition() { 14571 if (this.controllers.popover instanceof PopoverController) { 14572 this.controllers.popover.adjustScreenPosition(); 14573 } 14574 } 14575 popoverMoveScreenPositionBy(deltaX, deltaY) { 14576 if (this.controllers.popover instanceof PopoverController) { 14577 this.controllers.popover.moveSrceenPositionBy(deltaX, deltaY); 14578 } 14579 } 14580 showPopover(object) { 14581 const mapObject = object instanceof Region 14582 ? object 14583 : object.location && object.location.marker 14584 ? object.location.marker 14585 : null; 14586 if (!mapObject) 14587 return; 14588 let point; 14589 if (mapObject instanceof Marker) { 14590 point = mapObject.svgPoint; 14591 } 14592 else { 14593 point = mapObject.getCenterSVG(); 14594 } 14595 this.controllers.popover && this.controllers.popover.destroy(); 14596 this.controllers.popover = new PopoverController({ 14597 container: this.containers.popover, 14598 point: point, 14599 yShift: mapObject instanceof Marker ? mapObject.height : 0, 14600 template: object instanceof Region 14601 ? this.options.templates.popoverRegion 14602 : this.options.templates.popoverMarker, 14603 mapsvg: this, 14604 data: object.getData(), 14605 mapObject: mapObject, 14606 scrollable: true, 14607 withToolbar: !(MapSVG.isPhone && this.options.popovers.mobileFullscreen), 14608 events: { 14609 shown: (popover) => { 14610 if (this.options.popovers.centerOn) { 14611 const shift = popover.containers.main.offsetHeight / 2; 14612 if (this.options.popovers.centerOn && 14613 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14614 this.centerOn(mapObject, shift); 14615 } 14616 } 14617 this.popoverShowingFor = mapObject; 14618 this.events.trigger("shown.popover", this, [this, popover]); 14619 $$A(window).trigger("shown.popover", [this, popover]); 14620 }, 14621 closed: (popover) => { 14622 this.options.popovers.resetViewboxOnClose && this.viewBoxReset(true); 14623 this.popoverShowingFor = null; 14624 this.events.trigger("closed.popover", this, [this, popover]); 14625 }, 14626 resize: (popover) => { 14627 if (this.options.popovers.centerOn) { 14628 const shift = popover.containers.main.offsetHeight / 2; 14629 if (this.options.popovers.centerOn && 14630 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14631 this.centerOn(mapObject, shift); 14632 } 14633 } 14634 }, 14635 }, 14636 }); 14637 this.controllers.popover._init(); 14638 } 14639 hidePopover() { 14640 this.controllers.popover && this.controllers.popover.close(); 14641 } 14642 popoverOffHandler(e) { 14643 if (this.isScrolling || 14644 $$A(e.target).closest(".mapsvg-popover").length || 14645 $$A(e.target).hasClass("mapsvg-btn-map")) 14646 return; 14647 this.controllers.popover && this.controllers.popover.close(); 14648 } 14649 mouseOverHandler(e, object) { 14650 if (this.eventsPreventList["mouseover"]) { 14651 return; 14652 } 14653 if (object instanceof Marker) { 14654 if (this.options.actions.marker.mouseover.showTooltip) { 14655 this.showTooltip(object); 14656 } 14657 } 14658 if (object instanceof Region) { 14659 if (this.options.actions.region.mouseover.showTooltip) { 14660 this.showTooltip(object); 14661 } 14662 } 14663 let ids; 14664 if (this.options.menu.on) { 14665 if (this.options.menu.source == "database") { 14666 if (object instanceof Region && object.objects.length) { 14667 ids = object.objects.map((obj) => { 14668 return obj.id; 14669 }); 14670 } 14671 if (object instanceof Marker) { 14672 ids = object.object ? [object.object.id] : []; 14673 } 14674 } 14675 else { 14676 if (object instanceof Region) { 14677 ids = [object.id]; 14678 } 14679 if (this instanceof Marker && 14680 object.object.regions && 14681 object.object.regions.length) { 14682 ids = object.object.regions.map((obj) => { 14683 return obj.id; 14684 }); 14685 } 14686 } 14687 this.controllers.directory.highlightItems(ids); 14688 } 14689 if (object instanceof Region) { 14690 if (!object.selected) 14691 object.highlight(); 14692 this.events.trigger("mouseover.region", object, [e, this]); 14693 } 14694 else { 14695 this.highlightMarker(object); 14696 this.events.trigger("mouseover.marker", object, [e, this]); 14697 } 14698 } 14699 showTooltip(object) { 14700 let name, _object; 14701 if (object instanceof Region) { 14702 name = "tooltipRegion"; 14703 _object = object; 14704 } 14705 else if (object instanceof Marker) { 14706 name = "tooltipMarker"; 14707 _object = object.object; 14708 } 14709 else { 14710 name = "tooltipMarker"; 14711 _object = object; 14712 } 14713 if (_object != null && this.popoverShowingFor !== object) { 14714 this.controllers.tooltip.setMainTemplate(this.options.templates[name]); 14715 this.controllers.tooltip.redraw(_object.getData()); 14716 this.controllers.tooltip.show(); 14717 } 14718 } 14719 mouseOutHandler(e, object) { 14720 if (this.eventsPreventList["mouseout"]) { 14721 return; 14722 } 14723 if (this.controllers.tooltip) 14724 this.controllers.tooltip.hide(); 14725 if (object instanceof Region) { 14726 if (!object.selected) 14727 object.unhighlight(); 14728 this.events.trigger("mouseout.region", object, [e, this]); 14729 } 14730 else { 14731 this.unhighlightMarker(); 14732 this.events.trigger("mouseout.marker", object, [e, this]); 14733 } 14734 let ids; 14735 if (this.options.menu.on) { 14736 if (this.options.menu.source == "database") { 14737 if (object instanceof Marker) { 14738 const marker = object; 14739 ids = marker.object ? [marker.object.id] : []; 14740 } 14741 } 14742 this.controllers.directory.unhighlightItems(); 14743 } 14744 } 14745 eventsPrevent(event) { 14746 this.eventsPreventList[event] = true; 14747 } 14748 eventsRestore(event) { 14749 if (event) { 14750 this.eventsPreventList[event] = false;
14751 } 14752 else { 14753 this.eventsPreventList = {}; 14754 } 14755 } 14756 setEventHandlers() { 14757 const _this = this; 14758 $$A(_this.containers.map).off(".common.mapsvg"); 14759 $$A(_this.containers.scrollpane).off(".common.mapsvg"); 14760 $$A(document).off(".scroll.mapsvg"); 14761 $$A(document).off(".scrollInit.mapsvg"); 14762 if (_this.editMarkers.on) { 14763 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", ".mapsvg-marker", function (e) { 14764 e.originalEvent.preventDefault(); 14765 const marker = _this.getMarker($$A(this).attr("id")); 14766 const startCoords = MapSVG.mouseCoords(e); 14767 marker.drag(startCoords, _this.scale); 14768 }); 14769 } 14770 if (!_this.editMarkers.on) { 14771 $$A(_this.containers.map) 14772 .on("mouseover.common.mapsvg", ".mapsvg-region", function (e) { 14773 const id = $$A(this).attr("id"); 14774 _this.mouseOverHandler.call(_this, e, _this.getRegion(id)); 14775 }) 14776 .on("mouseleave.common.mapsvg", ".mapsvg-region", function (e) { 14777 const id = $$A(this).attr("id"); 14778 _this.mouseOutHandler.call(_this, e, _this.getRegion(id)); 14779 }); 14780 } 14781 if (!_this.editRegions.on) { 14782 $$A(_this.containers.map) 14783 .on("mouseover.common.mapsvg", ".mapsvg-marker", function (e) { 14784 const id = $$A(this).attr("id"); 14785 _this.mouseOverHandler.call(_this, e, _this.getMarker(id)); 14786 }) 14787 .on("mouseleave.common.mapsvg", ".mapsvg-marker", function (e) { 14788 const id = $$A(this).attr("id"); 14789 _this.mouseOutHandler.call(_this, e, _this.getMarker(id)); 14790 }); 14791 } 14792 if (_this.options.scroll.spacebar) { 14793 $$A(document).on("keydown.scroll.mapsvg", function (e) { 14794 if (!(document.activeElement.tagName === "INPUT" && 14795 $$A(document.activeElement).attr("type") === "text") && 14796 !_this.isScrolling && 14797 e.keyCode == 32) { 14798 e.preventDefault(); 14799 $$A(_this.containers.map).addClass("mapsvg-scrollable"); 14800 $$A(document) 14801 .on("mousemove.scrollInit.mapsvg", function (e) { 14802 _this.isScrolling = true; 14803 $$A(document).off("mousemove.scrollInit.mapsvg"); 14804 _this.scrollStart(e, _this); 14805 }) 14806 .on("keyup.scroll.mapsvg", function (e) { 14807 if (e.keyCode == 32) { 14808 $$A(document).off("mousemove.scrollInit.mapsvg"); 14809 $$A(_this.containers.map).removeClass("mapsvg-scrollable"); 14810 } 14811 }); 14812 } 14813 }); 14814 } 14815 else if (!_this.options.scroll.on) { 14816 if (!_this.editMarkers.on) { 14817 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-region", function (e) { 14818 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14819 }); 14820 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-marker", function (e) { 14821 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14822 }); 14823 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-region", function (e) { 14824 if (e.cancelable) { 14825 e.preventDefault(); 14826 } 14827 if (!_this.scroll.touchScrollStart || 14828 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14829 _this.regionClickHandler(e, _this.getRegion($$A(this).attr("id"))); 14830 } 14831 }); 14832 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker", function (e) { 14833 if (e.cancelable) { 14834 e.preventDefault(); 14835 } 14836 if (!_this.scroll.touchScrollStart || 14837 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14838 _this.markerClickHandler.call(_this, e, _this.getMarker($$A(this).attr("id"))); 14839 } 14840 }); 14841 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker-cluster", function (e) { 14842 if (e.cancelable) { 14843 e.preventDefault(); 14844 } 14845 if (!_this.scroll.touchScrollStart || 14846 _this.scroll.touchScrollStart == $$A(window).scrollTop()) { 14847 const cluster = $$A(this).data("cluster"); 14848 _this.zoomTo(cluster.markers); 14849 } 14850 }); 14851 } 14852 else { 14853 if (_this.clickAddsMarker) 14854 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", function (e) { 14855 if (e.cancelable) { 14856 e.preventDefault(); 14857 } 14858 _this.markerAddClickHandler(e); 14859 }); 14860 } 14861 } 14862 else { 14863 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", function (e) { 14864 if ($$A(e.target).hasClass("mapsvg-popover") || 14865 $$A(e.target).closest(".mapsvg-popover").length) { 14866 if ($$A(e.target).hasClass("mapsvg-popover-close")) { 14867 if (e.type == "touchstart") { 14868 if (e.cancelable) { 14869 e.preventDefault(); 14870 } 14871 } 14872 } 14873 return; 14874 } 14875 if (e.type == "touchstart") { 14876 if (e.cancelable) { 14877 e.preventDefault(); 14878 } 14879 } 14880 let obj; 14881 if (e.target && 14882 $$A(e.target).attr("class") && 14883 $$A(e.target).attr("class").indexOf("mapsvg-region") != -1) { 14884 obj = _this.getRegion($$A(e.target).attr("id")); 14885 _this.setObjectClickedBeforeScroll(obj); 14886 } 14887 else if (e.target && 14888 $$A(e.target).attr("class") && 14889 $$A(e.target).attr("class").indexOf("mapsvg-marker") != -1 && 14890 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster")
14890=== -1) { 14891 if (_this.editMarkers.on) { 14892 return; 14893 } 14894 obj = _this.getMarker($$A(e.target).attr("id")); 14895 _this.setObjectClickedBeforeScroll(obj); 14896 } 14897 else if (e.target && 14898 $$A(e.target).attr("class") && 14899 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster") != -1) { 14900 if (_this.editMarkers.on) { 14901 return; 14902 } 14903 obj = $$A(e.target).data("cluster"); 14904 _this.setObjectClickedBeforeScroll(obj); 14905 } 14906 if (e.type == "mousedown") { 14907 _this.scrollStart(e, _this); 14908 } 14909 else { 14910 _this.touchStart(e, _this); 14911 } 14912 }); 14913 } 14914 $$A(_this.containers.map).on("mouseleave.common.mapsvg", ".mapsvg-choropleth-gradient-wrap", (e) => { 14915 this.controllers.tooltip.hide(); 14916 }); 14917 } 14918 setLabelsRegions(options) { 14919 options = options || this.options.labelsRegions; 14920 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14921 $$A.extend(true, this.options, { labelsRegions: options }); 14922 if (this.options.labelsRegions.on) { 14923 this.regions.forEach((region) => { 14924 if (!region.label) { 14925 region.label = jQuery('<div class="mapsvg-region-label" />')[0]; 14926 $$A(this.layers.labels).append(region.label); 14927 } 14928 try { 14929 $$A(region.label).html(this.templates.labelRegion(region.forTemplate())); 14930 } 14931 catch (err) { 14932 console.error('MapSVG: Error in the "Region Label" template'); 14933 } 14934 }); 14935 this.labelsRegionsAdjustScreenPosition(); 14936 } 14937 else { 14938 this.regions.forEach((region) => { 14939 if (region.label) { 14940 $$A(region.label).remove(); 14941 region.label = null; 14942 delete region.label; 14943 } 14944 }); 14945 } 14946 } 14947 setLabelsMarkers(options) { 14948 options = options || this.options.labelsMarkers; 14949 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14950 $$A.extend(true, this.options, { labelsMarkers: options }); 14951 if (this.options.labelsMarkers.on) { 14952 this.markers.forEach((marker) => { 14953 try { 14954 marker.setLabel(this.templates.labelMarker(marker.object)); 14955 } 14956 catch (err) { 14957 console.error('MapSVG: Error in the "Marker Label" template'); 14958 } 14959 }); 14960 } 14961 else { 14962 this.markers.forEach((marker) => { 14963 marker.setLabel(""); 14964 }); 14965 } 14966 } 14967 addLayer(name) { 14968 this.layers[name] = $$A('<div class="mapsvg-layer mapsvg-layer-' + name + '"></div>')[0]; 14969 this.containers.layers.appendChild(this.layers[name]); 14970 return this.layers[name]; 14971 } 14972 getLayer(name) { 14973 return this.layers[name]; 14974 } 14975 getDb() { 14976 return this.objectsRepository; 14977 } 14978 getDbRegions() { 14979 return this.regionsRepository; 14980 } 14981 regionAdd(svgObject) { 14982 const region = new Region(svgObject, this); 14983 region.setStatus(1); 14984 this.regions.push(region); 14985 this.regions.sort(function (a, b) { 14986 return a.id == b.id ? 0 : +(a.id > b.id) || -1; 14987 }); 14988 return region; 14989 } 14990 regionDelete(id) { 14991 if (this.regions.findById(id)) { 14992 this.regions.findById(id).elem.remove(); 14993 this.regions.delete(id); 14994 } 14995 else if ($$A("#" + id).length) { 14996 $$A("#" + id).remove(); 14997 } 14998 } 14999 reloadRegions() { 15000 this.regions.clear(); 15001 $$A(this.containers.svg).find(".mapsvg-region").removeClass("mapsvg-region"); 15002 $$A(this.containers.svg) 15003 .find(".mapsvg-region-disabled") 15004 .removeClass("mapsvg-region-disabled"); 15005 $$A(this.containers.svg) 15006 .find("path, polygon, circle, ellipse, rect") 15007 .each((index, element) => { 15008 const elem = element; 15009 if ($$A(elem).closest("defs").length) 15010 return; 15011 if (elem.getAttribute("data-stroke-width")) { 15012 elem.style["stroke-width"] = elem.getAttribute("data-stroke-width"); 15013 } 15014 if (elem.getAttribute("id")) { 15015 if (!this.options.regionPrefix || 15016 (this.options.regionPrefix && 15017 elem.getAttribute("id").indexOf(this.options.regionPrefix) === 0)) { 15018 const region = new Region(elem, this); 15019 this.regions.push(region); 15020 } 15021 } 15022 }); 15023 } 15024 reloadRegionsFull() { 15025 const statuses = this.regionsRepository.getSchema().getFieldByType("status"); 15026 this.regions.forEach((region) => { 15027 const _region = this.regionsRepository.getLoaded().findById(region.id); 15028 if (_region) { 15029 region.setData(_region); 15030 if (statuses && _region.status !== undefined && _region.status !== null) { 15031 region.setStatus(_region.status); 15032 } 15033 } 15034 else { 15035 if (this.options.filters.filteredRegionsStatus || 15036 this.options.filters.filteredRegionsStatus === 0 || 15037 (this.options.menu.source === "regions" && 15038 this.options.menu.filterout && 15039 this.options.menu.filterout.field === "status" && 15040 this.options.menu.filterout.val) || 15041 this.options.menu.filterout.val === 0) { 15042 const status = this.options.filters.filteredRegionsStatus || 15043 this.options.filters.filteredRegionsStatus === 0 15044 ? this.options.filters.filteredRegionsStatus 15045 : this.options.menu.filterout.val; 15046 region.setStatus(status); 15047 } 15048 } 15049 }); 15050 this.loadDirectory(); 15051 this.setChoropleth(); 15052 this.setLayersControl(); 15053 this.setGroups(); 15054 if (this.options.labelsRegions.on) { 15055 this.setLabelsRegions(); 15056 } 15057 } 15058 fixMarkersWorldScreen() { 15059 if (this.googleMaps.map) 15060 setTimeout(() => { 15061 const markers = { left: 0, right: 0, leftOut: 0, rightOut: 0 }; 15062 if (this.markers.length > 1) {
15063 this.markers.forEach((m) => { 15064 if ($$A(m.element).offset().left < 15065 $$A(this.containers.map).offset().left + 15066 this.containers.map.clientWidth / 2) { 15067 markers.left++; 15068 if ($$A(m.element).offset().left < $$A(this.containers.map).offset().left) { 15069 markers.leftOut++; 15070 } 15071 } 15072 else { 15073 markers.right++; 15074 if ($$A(m.element).offset().left > 15075 $$A(this.containers.map).offset().left + 15076 this.containers.map.clientWidth) { 15077 markers.rightOut++; 15078 } 15079 } 15080 }); 15081 if ((markers.left === 0 && markers.rightOut) || 15082 (markers.right === 0 && markers.leftOut)) { 15083 const k = markers.left === 0 ? 1 : -1; 15084 const ww = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 15085 360 *
15086 this.getScale(); 15087 this.googleMaps.map.panBy(k * ww, 0); 15088 } 15089 } 15090 }, 600); 15091 } 15092 updateOutdatedOptions(options) { 15093 if (options.menu && (options.menu.position || options.menu.customContainer)) { 15094 if (options.menu.customContainer) { 15095 options.menu.location = "custom"; 15096 } 15097 else { 15098 options.menu.position = options.menu.position === "left" ? "left" : "right"; 15099 options.menu.location = 15100 options.menu.position === "left" ? "leftSidebar" : "rightSidebar"; 15101 if (!options.containers || !options.containers[options.menu.location]) { 15102 options.containers = options.containers || {}; 15103 options.containers[options.menu.location] = { on: false, width: "200px" }; 15104 } 15105 options.containers[options.menu.location].width = options.menu.width; 15106 if (MapSVG.parseBoolean(options.menu.on)) { 15107 options.containers[options.menu.location].on = true; 15108 } 15109 } 15110 delete options.menu.position; 15111 delete options.menu.width; 15112 delete options.menu.customContainer; 15113 } 15114 if (options.detailsView && 15115 (options.detailsView.location === "mapContainer" || 15116 options.detailsView.location === "near" || 15117 options.detailsView.location === "top")) { 15118 options.detailsView.location = "map"; 15119 } 15120 if (!options.controls) { 15121 options.controls = {}; 15122 options.controls.zoom = 15123 options.zoom && 15124 options.zoom.on && 15125 (!options.zoom.buttons || options.zoom.buttons.location !== "hide"); 15126 options.controls.location = 15127 options.zoom && options.zoom.buttons && options.zoom.buttons.location !== "hide" 15128 ? options.zoom.buttons.location 15129 : "right"; 15130 } 15131 if (options.colors && !options.colors.markers) { 15132 options.colors.markers = { 15133 base: { opacity: 100, saturation: 100 }, 15134 hovered: { opacity: 100, saturation: 100 }, 15135 unhovered: { opacity: 100, saturation: 100 }, 15136 active: { opacity: 100, saturation: 100 }, 15137 inactive: { opacity: 100, saturation: 100 }, 15138 }; 15139 } 15140 if (options.tooltipsMode) { 15141 options.tooltips.mode = options.tooltipsMode; 15142 delete options.tooltipsMode; 15143 } 15144 if (options.popover) { 15145 options.popovers = options.popover; 15146 delete options.popover; 15147 } 15148 } 15149 init() { 15150 MapSVG.addInstance(this); 15151 if (this.options.source === "") { 15152 throw new Error("MapSVG: please provide SVG file source."); 15153 } 15154 this.disableAnimation(); 15155 this.setEvents(this.options.events); 15156 this.events.trigger("beforeLoad"); 15157 if (this.options.googleMaps.apiKey && 15158 (this.editMode || 15159 this.options.googleMaps.on || 15160 (this.options.filters.on && 15161 this.options.filtersSchema && 15162 this.options.filtersSchema.find((f) => f.type === "distance")))) { 15163 this.loadGoogleMapsAPI(() => { 15164 return 1; 15165 }, () => { 15166 return 1; 15167 }); 15168 } 15169 this.containers.map.classList.add("mapsvg"); 15170 this.setCss(); 15171 if (this.options.colors && this.options.colors.background) { 15172 this.containers.map.style.background = this.options.colors.background; 15173 }
15174 this.setContainers(this.options.containers); 15175 this.setColors(); 15176 this.addLoadingMessage(); 15177 this.addLayer("markers"); 15178 this.addLayer("labels"); 15179 this.addLayer("bubbles"); 15180 this.addLayer("popovers"); 15181 this.addLayer("scrollpane"); 15182 this.loadExtensions(); 15183 $$A.ajax({ url: this.options.source + "?v=" + this.svgFileLastChanged }) 15184 .fail((resp) => { 15185 this.svgLoadingFailed(resp); 15186 }) 15187 .done((xmlData) => { 15188 this.renderSvgData(xmlData); 15189 }); 15190 return this; 15191 } 15192 getContainer(name) { 15193 return this.containers[name]; 15194 } 15195 renderSvgData(xmlData) { 15196 const svgTag = $$A(xmlData).find("svg"); 15197 this.containers.svg = svgTag[0]; 15198 if (svgTag.attr("width") && svgTag.attr("height")) { 15199 this.svgDefault.width = parseFloat(svgTag.attr("width").replace(/px/g, "")); 15200 this.svgDefault.height = parseFloat(svgTag.attr("height").replace(/px/g, "")); 15201 this.svgDefault.viewBox = svgTag.attr("viewBox") 15202 ? new ViewBox(svgTag.attr("viewBox").split(" ")) 15203 : new ViewBox(0, 0, this.svgDefault.width, this.svgDefault.height); 15204 } 15205 else if (svgTag.attr("viewBox")) { 15206 this.svgDefault.viewBox = new ViewBox(svgTag.attr("viewBox").split(" ")); 15207 this.svgDefault.width = this.svgDefault.viewBox.width; 15208 this.svgDefault.height = this.svgDefault.viewBox.height; 15209 } 15210 else { 15211 const msg = "MapSVG: width/height and viewBox are missing in the SVG file. Can't parse the file because of that."; 15212 if (this.editMode) { 15213 alert(msg); 15214 } 15215 else { 15216 console.error(msg); 15217 } 15218 return false; 15219 } 15220 this.geoViewBox = this.getGeoViewBoxFromSvgTag(this.containers.svg); 15221 if (this.options.viewBox && this.options.viewBox.length == 4) { 15222 this._viewBox = new ViewBox(this.options.viewBox); 15223 } 15224 else { 15225 this._viewBox = new ViewBox(this.svgDefault.viewBox); 15226 } 15227 svgTag.attr("preserveAspectRatio", "xMidYMid meet"); 15228 svgTag.removeAttr("width"); 15229 svgTag.removeAttr("height"); 15230 $$A(this.containers.scrollpane).append(svgTag); 15231 this.setStrokes(); 15232 this.reloadRegions(); 15233 this.setSize(this.options.width, this.options.height, this.options.responsive); 15234 if (this.options.disableAll) { 15235 this.setDisableAll(true); 15236 } 15237 this.setViewBox(this._viewBox); 15238 this.converter = new Converter(this.containers.map, this.svgDefault.viewBox, this.viewBox); 15239 if (this.geoViewBox) { 15240 this.converter.setGeoViewBox(this.geoViewBox); 15241 } 15242 this.setResponsive(this.options.responsive); 15243 this.setScroll(this.options.scroll, true); 15244 this.setZoom(this.options.zoom); 15245 this.setControls(this.options.controls); 15246 this.setGoogleMaps(); 15247 this.setTooltips(this.options.tooltips); 15248 this.setPopovers(this.options.popovers); 15249 if (this.options.cursor) 15250 this.setCursor(this.options.cursor); 15251 this.setTemplates(this.options.templates); 15252 this.loadExtensions(); 15253 this.filtersSchema = new Schema({ fields: this.options.filtersSchema }); 15254 this.objectsRepository.events.on("load", () => { 15255 this.showLoadingMessage(); 15256 }); 15257 this.objectsRepository.events.on("loaded", () => { 15258 this.setGlobalDistanceFilter(); 15259 this.fitOnDataLoadDone = false; 15260 this.addLocations(); 15261 this.fixMarkersWorldScreen();
15262 this.attachDataToRegions(); 15263 this.loadDirectory(); 15264 if (this.options.labelsMarkers.on) { 15265 this.setLabelsMarkers(); 15266 } 15267 if (this.options.templates.labelRegion.indexOf("{{objects") !== -1) { 15268 this.setLabelsRegions(); 15269 } 15270 if (this.options.filters.on && 15271 this.options.filters.source === "database" && 15272 this.controllers.filters && 15273 this.controllers.filters.hideFilters) { 15274 this.controllers.filters.setFiltersCounter(); 15275 } 15276 this.hideLoadingMessage(); 15277 this.events.trigger("databaseLoaded"); 15278 this.updateFiltersState(); 15279 this.setChoropleth(); 15280 }); 15281 this.objectsRepository.events.on("schemaChanged", () => { 15282 this.objectsRepository.reload(); 15283 }); 15284 this.objectsRepository.events.on("updated", (obj) => { 15285 this.attachDataToRegions(obj); 15286 this.reloadRegionsFull(); 15287 }); 15288 this.objectsRepository.events.on("created", (obj) => { 15289 this.attachDataToRegions(obj); 15290 this.reloadRegionsFull(); 15291 }); 15292 this.objectsRepository.events.on("deleted", (id) => { 15293 this.attachDataToRegions(); 15294 this.reloadRegionsFull(); 15295 }); 15296 this.regionsRepository.events.on("load", () => { 15297 this.showLoadingMessage(); 15298 }); 15299 this.regionsRepository.events.on("loaded", () => { 15300 this.hideLoadingMessage(); 15301 this.reloadRegionsFull(); 15302 if (this.options.filters.on && 15303 this.options.filters.source === "regions" && 15304 this.controllers.filters && 15305 this.controllers.filters.hideFilters) { 15306 this.controllers.filters.setFiltersCounter(); 15307 } 15308 this.events.trigger("regionsLoaded"); 15309 }); 15310 this.regionsRepository.events.on("updated", (regionData) => { 15311 this.reloadRegionsFull(); 15312 }); 15313 this.regionsRepository.events.on("created", (regionData) => { 15314 this.reloadRegionsFull(); 15315 }); 15316 this.regionsRepository.events.on("deleted", (regionData) => { 15317 this.reloadRegionsFull(); 15318 }); 15319 this.setMenu(); 15320 this.setFilters(); 15321 this.setFilterOut(); 15322 this.setEventHandlers(); 15323 this.afterLoadBlockers--; 15324 if (!this.id) { 15325 this.finalizeMapLoading(); 15326 return; 15327 } 15328 if (!this.options.data_regions) { 15329 this.regionsRepository.find().done((data) => { 15330 this.afterLoadBlockers--; 15331 this.finalizeMapLoading(); 15332 }); 15333 } 15334 else { 15335 this.regionsRepository.loadDataFromResponse(this.options.data_regions); 15336 this.afterLoadBlockers--; 15337 } 15338 if (!this.options.data_objects) { 15339 if (this.options.database.loadOnStart || this.editMode) { 15340 this.objectsRepository.find().done((data) => { 15341 this.afterLoadBlockers--; 15342 this.finalizeMapLoading(); 15343 }); 15344 } 15345 else { 15346 this.afterLoadBlockers--; 15347 this.finalizeMapLoading(); 15348 } 15349 } 15350 else { 15351 if (this.editMode || this.options.database.loadOnStart) { 15352 this.objectsRepository.loadDataFromResponse(this.options.data_objects); 15353 this.afterLoadBlockers--; 15354 } 15355 else { 15356 this.afterLoadBlockers--; 15357 } 15358 delete this.options.data_regions; 15359 delete this.options.data_objects; 15360 this.finalizeMapLoading(); 15361 } 15362 } 15363 setFilterOut() { 15364 if (this.options.menu.filterout.field) { 15365 const f = {}; 15366 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 15367 if (this.options.menu.source == "regions") ; 15368 else { 15369 this.objectsRepository.query.setFilterOut(f); 15370 } 15371 } 15372 else { 15373 this.objectsRepository.query.setFilterOut(null); 15374 } 15375 } 15376 getGeoViewBoxFromSvgTag(svgTag) { 15377 const geo = $$A(svgTag).attr("mapsvg:geoViewBox") || $$A(svgTag).attr("mapsvg:geoviewbox"); 15378 if (geo) { 15379 const geoParts = geo.split(" ").map((p) => parseFloat(p)); 15380 if (geoParts.length == 4) { 15381 this.mapIsGeo = true; 15382 this.geoCoordinates = true; 15383 const sw = new GeoPoint(geoParts[3], geoParts[0]); 15384 const ne = new GeoPoint(geoParts[1], geoParts[2]); 15385 return new GeoViewBox(sw, ne); 15386 } 15387 } 15388 else { 15389 return null; 15390 } 15391 } 15392 svgLoadingFailed(resp) { 15393 if (resp.status == 404) { 15394 let msg = "MapSVG: file not found - " + 15395 this.options.source + 15396 "\n\nIf you moved MapSVG from another server please read the following docs page: https://mapsvg.com/docs/installation/moving"; 15397 if (this.editMode) { 15398 msg += 15399 "\n\nIf you know the correct path for the SVG file, please write it and press OK:"; 15400 const oldSvgPath = this.options.source; 15401 const userSvgPath = prompt(msg, oldSvgPath); 15402 if (userSvgPath !== null) { 15403 $$A.ajax({ url: userSvgPath + "?v=" + this.svgFileLastChanged }) 15404 .fail(function () { 15405 location.reload(); 15406 }) 15407 .done((xmlData) => { 15408 this.options.source = userSvgPath; 15409 this.renderSvgData(xmlData); 15410 const mapsRepo = new MapsRepository(); 15411 mapsRepo.update(this); 15412 }); 15413 } 15414 else { 15415 location.reload(); 15416 } 15417 } 15418 else { 15419 console.error(msg); 15420 } 15421 } 15422 else { 15423 const msg = "MapSVG: can't load SVG file for unknown reason. Please contact support: https://mapsvg.ticksy.com"; 15424 if (this.editMode) { 15425 alert(msg); 15426 } 15427 else { 15428 console.error(msg); 15429 } 15430 } 15431 } 15432 addLoadingMessage() { 15433 this.containers.loading = document.createElement("div"); 15434 this.containers.loading.className = "mapsvg-loading"; 15435 const loadingTextBlock = document.createElement("div"); 15436 loadingTextBlock.className = "mapsvg-loading-text"; 15437 loadingTextBlock.innerHTML = this.options.loadingText; 15438 const spinner = document.createElement("div"); 15439 spinner.className = "spinner-border spinner-border-sm"; 15440 this.containers.loading.appendChild(spinner); 15441 this.containers.loading.appendChild(loadingTextBlock); 15442 this.containers.map.appendChild(this.containers.loading); 15443 if (this.options.googleMaps.on) { 15444 $$A(this.containers.map).addClass("mapsvg-google-map-loading"); 15445 } 15446 } 15447 hideLoadingMessage() { 15448 $$A(this.containers.loading).hide(); 15449 } 15450 showLoadingMessage() { 15451 $$A(this.containers.loading).show(); 15452 } 15453 disableAnimation() { 15454 this.containers.map.classList.add("no-transitions"); 15455 } 15456 enableAnimation() { 15457 $$A(this.containers.map).removeClass("no-transitions"); 15458 } 15459 loadExtensions() { 15460 if (this.options.extension && 15461 $$A().mapSvg.extensions && 15462 $$A().mapSvg.extensions[_this.options.extension]) { 15463 const ext = $$A().mapSvg.extensions[_this.options.extension]; 15464 ext && ext.common(this); 15465 } 15466 } 15467 finalizeMapLoading() { 15468 if (this.afterLoadBlockers > 0 || this.loaded) { 15469 return; 15470 } 15471 this.selectRegionByIdFromUrl(); 15472 setTimeout(() => { 15473 this.movingItemsAdjustScreenPosition(); 15474 this.adjustStrokes(); 15475 setTimeout(() => { 15476 this.hideLoadingMessage(); 15477 $$A(this.containers.loading).find(".mapsvg-loading-text").hide(); 15478 this.enableAnimation(); 15479 }, 200); 15480 }, 100); 15481 this.loaded = true; 15482 this.events.trigger("afterLoad"); 15483 } 15484 selectRegionByIdFromUrl() { 15485 const match = RegExp("[?&]mapsvg_select=([^&]*)").exec(window.location.search); 15486 if (match) { 15487 const select = decodeURIComponent(match[1].replace(/\+/g, " ")); 15488 this.selectRegion(select); 15489 } 15490 if (window.location.hash) { 15491 const query = window.location.hash.replace("#/m/", ""); 15492 const region = this.getRegion(query); 15493 if (region && this.options.actions.map.afterLoad.selectRegion) { 15494 this.regionClickHandler(null, region); 15495 } 15496 } 15497 } 15498 createForm(options) { 15499 return new FormBuilder(options); 15500 } 15501 getApiUrl(path) { 15502 const server = new Server(); 15503 return server.getUrl(path); 15504 } 15505 getConverter() { 15506 return this.converter; 15507 } 15508 setChoropleth(options) { 15509 const _this = this; 15510 options = options || _this.options.choropleth; 15511 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 15512 $$A.extend(true, _this.options, { choropleth: options }); 15513 let needsRedraw = false;
15514 if (!_this.$gauge) { 15515 _this.$gauge = {}; 15516 _this.$gauge.gradient = $$A("<td> </td>").addClass("mapsvg-gauge-gradient"); 15517 _this.setGaugeGradientCSS(); 15518 _this.$gauge.container = $$A("<div />").addClass("mapsvg-gauge").hide(); 15519 _this.$gauge.table = $$A("<table />"); 15520 const tr = $$A("<tr />"); 15521 _this.$gauge.labelLow = $$A("<td>" + _this.options.choropleth.labels.low + "</td>"); 15522 _this.$gauge.labelHigh = $$A("<td>" + _this.options.choropleth.labels.high + "</td>"); 15523 tr.append(_this.$gauge.labelLow); 15524 tr.append(_this.$gauge.gradient); 15525 tr.append(_this.$gauge.labelHigh); 15526 _this.$gauge.table.append(tr); 15527 _this.$gauge.container.append(_this.$gauge.table); 15528 $$A(_this.containers.map).append(_this.$gauge.container); 15529 } 15530 if (!_this.options.choropleth.on && _this.$gauge.container.is(":visible")) { 15531 _this.$gauge.container.hide(); 15532 needsRedraw = true; 15533 } 15534 else if (_this.options.choropleth.on && !_this.$gauge.container.is(":visible")) { 15535 _this.$gauge.container.show(); 15536 needsRedraw = true; 15537 _this.regionsRepository.events.on("change", function () { 15538 _this.redrawGauge(); 15539 }); 15540 } 15541 if (options.colors) { 15542 _this.options.choropleth.colors.lowRGB = tinycolor(_this.options.choropleth.colors.low).toRgb(); 15543 _this.options.choropleth.colors.highRGB = tinycolor(_this.options.choropleth.colors.high).toRgb(); 15544 _this.options.choropleth.colors.diffRGB = { 15545 r: _this.options.choropleth.colors.highRGB.r - 15546 _this.options.choropleth.colors.lowRGB.r, 15547 g: _this.options.choropleth.colors.highRGB.g - 15548 _this.options.choropleth.colors.lowRGB.g, 15549 b: _this.options.choropleth.colors.highRGB.b - 15550 _this.options.choropleth.colors.lowRGB.b, 15551 a: _this.options.choropleth.colors.highRGB.a - 15552 _this.options.choropleth.colors.lowRGB.a, 15553 }; 15554 needsRedraw = true; 15555 _this.$gauge && _this.setGaugeGradientCSS(); 15556 } 15557 if (options.labels) { 15558 _this.$gauge.labelLow.html(_this.options.choropleth.labels.low); 15559 _this.$gauge.labelHigh.html(_this.options.choropleth.labels.high); 15560 } 15561 needsRedraw && _this.redrawGauge(); 15562 } 15563 redrawGauge() { 15564 const _this = this; 15565 _this.updateGaugeMinMax(); 15566 _this.regionsRedrawColors(); 15567 } 15568 updateGaugeMinMax() { 15569 const _this = this; 15570 _this.options.choropleth.min = 0; 15571 _this.options.choropleth.max = false; 15572 const values = []; 15573 _this.regions.forEach(function (r) { 15574 const gauge = r.data && r.data[_this.options.regionChoroplethField]; 15575 gauge != undefined && values.push(gauge); 15576 }); 15577 if (values.length > 0) { 15578 _this.options.choropleth.min = values.length == 1 ? 0 : Math.min.apply(null, values); 15579 _this.options.choropleth.max = Math.max.apply(null, values); 15580 _this.options.choropleth.maxAdjusted = 15581 _this.options.choropleth.max - _this.options.choropleth.min; 15582 } 15583 } 15584 setGaugeGradientCSS() { 15585 const _this = this; 15586 _this.$gauge.gradient.css({ 15587 background: "linear-gradient(to right," + 15588 _this.options.choropleth.colors.low + 15589 " 1%," + 15590 _this.options.choropleth.colors.high + 15591 " 100%)", 15592 filter: 'progid:DXImageTransform.Microsoft.gradient( startColorstr="' + 15593 _this.options.choropleth.colors.low + 15594 '", endColorstr="' + 15595 _this.options.choropleth.colors.high + 15596 '",GradientType=1 )', 15597 }); 15598 } 15599 get $map() { 15600 return $$A(this.getContainer("map")); 15601 } 15602 get $svg() { 15603 return $$A(this.getContainer("svg")); 15604 } 15605 get $popover() { 15606 return $$A(this.getContainer("popover")); 15607 } 15608 get $details() { 15609 return $$A(this.getContainer("detailsView")); 15610 } 15611 get $directory() { 15612 return $$A(this.getContainer("directory")); 15613 } 15614 get database() { 15615 return this.objectsRepository; 15616 } 15617 get regionsDatabase() { 15618 return this.regionsRepository; 15619 } 15620 } 15621 15622 exports.MapSVGMap = MapSVGMap; 15623 exports.arrayIndexed = ArrayIndexed; 15624 exports.customObject = CustomObject; 15625 exports.formBuilder = FormBuilder; 15626 exports.geoPoint = GeoPoint; 15627 exports.globals = MapSVG; 15628 exports.location = Location; 15629 exports.map = MapSVGMap; 15630 exports.mapsRepository = MapsRepository; 15631 exports.mapsV2Repository = MapsV2Repository; 15632 exports.marker = Marker; 15633 exports.query = Query; 15634 exports.repository = Repository; 15635 exports.schema = Schema; 15636 exports.schemaRepository = SchemaRepository; 15637 exports.screenPoint = ScreenPoint; 15638 exports.server = Server; 15639 exports.svgPoint = SVGPoint; 15640 15641 Object.defineProperty(exports, '__esModule', { value: true }); 15642 15643}))); 15644//# 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.