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 mapsvg-btn">' + 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 this.iosDownscaleFactor = 1; 11706 if (MapSVG.device.ios || MapSVG.device.android || MapSVG.browser.safari) { 11707 this.iosDownscaleFactor = 0.1; 11708 } 11709 this.containers.svg.style.width = 11710 (this.svgDefault.viewBox.width / this.iosDownscaleFactor).toString() + "px"; 11711 this.vbStart = true; 11712 } 11713 setViewBox(viewBox, adjustGoogleMap = true) { 11714 let initial = false; 11715 if (typeof viewBox === "undefined" || (viewBox.width === 0 && viewBox.height === 0)) {
11716 viewBox = this.svgDefault.viewBox; 11717 initial = true; 11718 } 11719 const isZooming = viewBox.width != this.viewBox.width || viewBox.height != this.viewBox.height; 11720 this.viewBox.update(viewBox); 11721 this.whRatio = this.viewBox.width / this.viewBox.height; 11722 !this.vbStart && this.setViewBoxOnStart(); 11723 if (initial) { 11724 if (this._viewBox.width === 0 && this._viewBox.height === 0) { 11725 this._viewBox.update(this.viewBox); 11726 } 11727 this._scale = 1; 11728 } 11729 this.scale = this.getScale(); 11730 this.superScale = (this.whRatioFull * this.svgDefault.viewBox.width) / this.viewBox.width; 11731 const w = this.svgDefault.viewBox.width / this.containers.map.clientWidth; 11732 this.superScale = this.superScale / w; 11733 if (this.iosDownscaleFactor) { 11734 this.superScale *= this.iosDownscaleFactor; 11735 } 11736 this.scroll.tx = Math.round((this.svgDefault.viewBox.x - this.viewBox.x) * this.scale); 11737 this.scroll.ty = Math.round((this.svgDefault.viewBox.y - this.viewBox.y) * this.scale); 11738 if (this.googleMaps.map && adjustGoogleMap !== false) { 11739 const googlePrevZoom = this.googleMaps.map.getZoom(); 11740 this.googleMaps.map.setCenter(this.getCenterGeoPoint()); 11741 this.googleMaps.map.setZoom(this.getZoomForGoogle()); 11742 } 11743 else { 11744 this.containers.scrollpane.style.transform = 11745 "translate(" + this.scroll.tx + "px," + this.scroll.ty + "px)"; 11746 this.containers.svg.style.transform = "scale(" + this.superScale + ")"; 11747 this.syncZoomLevelWithGoogle(); 11748 } 11749 this.movingItemsAdjustScreenPosition(); 11750 if (isZooming) { 11751 this.adjustStrokes(); 11752 this.toggleSvgLayerOnZoom(); 11753 if (this.options.clustering.on) { 11754 this.throttle(this.clusterizeOnZoom, 400, this); 11755 } 11756 else { 11757 this.events.trigger("zoom"); 11758 } 11759 } 11760 return true; 11761 } 11762 syncZoomLevelWithGoogle() { 11763 if (this.googleMaps.map && 11764 this.googleMaps.map.getZoom() !== this.getZoomForGoogle() && 11765 typeof this.zoomDelta !== "undefined") { 11766 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11767 } 11768 } 11769 getCenterGeoPoint() { 11770 return this.converter.convertSVGToGeo(this.getCenterSvgPoint()); 11771 } 11772 getCenterSvgPoint() { 11773 return new SVGPoint(this.viewBox.x + this.viewBox.width / 2, this.viewBox.y + this.viewBox.height / 2); 11774 } 11775 getZoomForGoogle() { 11776 if (typeof this.zoomLevel === "string") { 11777 this.zoomLevel = parseInt(this.zoomLevel); 11778 } 11779 return this.zoomLevel + this.zoomDelta; 11780 } 11781 getZoomRange() { 11782 const range = { min: 0, max: 0 }; 11783 if (this.options.googleMaps.on) { 11784 range.min = Math.max(0, this.options.zoom.limit[0] + this.zoomDelta) - this.zoomDelta; 11785 range.max = Math.min(22, this.options.zoom.limit[1] + this.zoomDelta) - this.zoomDelta; 11786 } 11787 else { 11788 range.min = this.options.zoom.limit[0]; 11789 range.max = this.options.zoom.limit[1]; 11790 } 11791 return range; 11792 } 11793 enableMovingElementsAnimation() { 11794 $$A(this.containers.map).removeClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11795 } 11796 disableMovingElementsAnimation() { 11797 $$A(this.containers.map).addClass("no-transitions-markers no-transitions-labels no-transitions-bubbles"); 11798 } 11799 clusterizeOnZoom() { 11800 if (this.options.googleMaps.on && this.googleMaps.map && this.zoomDelta) { 11801 this.zoomLevel = this.googleMaps.map.getZoom() - this.zoomDelta; 11802 } 11803 this.events.trigger("zoom"); 11804 this.clusterizeMarkers(true); 11805 } 11806 throttle(method, delay, scope, params) { 11807 clearTimeout(method._tId); 11808 method._tId = setTimeout(function () { 11809 method.apply(scope, params); 11810 }, delay); 11811 }
11812 setViewBoxByGoogleMapBounds() { 11813 const googleMapBounds = this.googleMaps.map.getBounds(); 11814 if (!googleMapBounds) 11815 return; 11816 const googleMapBoundsJSON = googleMapBounds.toJSON(); 11817 if (googleMapBoundsJSON.west == -180 && googleMapBoundsJSON.east == 180) { 11818 const center = this.googleMaps.map.getCenter().toJSON(); 11819 } 11820 const ne = new GeoPoint(googleMapBounds.getNorthEast().lat(), googleMapBounds.getNorthEast().lng()); 11821 const sw = new GeoPoint(googleMapBounds.getSouthWest().lat(), googleMapBounds.getSouthWest().lng()); 11822 const xyNE = this.converter.convertGeoToSVG(ne); 11823 const xySW = this.converter.convertGeoToSVG(sw); 11824 if (xyNE.x < xySW.y) { 11825 const mapPointsWidth = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 360; 11826 xySW.x = -(mapPointsWidth - xySW.y); 11827 } 11828 const width = xyNE.x - xySW.x; 11829 const height = xySW.y - xyNE.y; 11830 const viewBox = new ViewBox(xySW.x, xyNE.y, width, height); 11831 this.setViewBox(viewBox); 11832 } 11833 redraw() { 11834 this.disableAnimation(); 11835 if (MapSVG.browser.ie) { 11836 $$A(this.containers.svg).css({ height: this.svgDefault.viewBox.height }); 11837 } 11838 if (this.options.googleMaps.on && this.googleMaps.map) { 11839 google.maps.event.trigger(this.googleMaps.map, "resize"); 11840 } 11841 else { 11842 this.setViewBox(this.viewBox); 11843 } 11844 $$A(this.containers.popover) && 11845 $$A(this.containers.popover).css({ 11846 "max-height": (this.options.popovers.maxHeight * $$A(this.containers.wrap).outerHeight()) / 11847 100 + 11848 "px", 11849 }); 11850 if (this.controllers && this.controllers.directory) { 11851 this.controllers.directory.updateTopShift(); 11852 this.controllers.directory.updateScroll(); 11853 } 11854 this.movingItemsAdjustScreenPosition(); 11855 this.adjustStrokes(); 11856 this.enableAnimation(); 11857 } 11858 setSize(width, height, responsive) { 11859 this.options.width = width; 11860 this.options.height = height; 11861 this.options.responsive = 11862 responsive != null && responsive != undefined 11863 ? MapSVG.parseBoolean(responsive) 11864 : this.options.responsive; 11865 if (!this.options.width && !this.options.height) { 11866 this.options.width = this.svgDefault.width; 11867 this.options.height = this.svgDefault.height; 11868 } 11869 else if (!this.options.width && this.options.height) { 11870 this.options.width = 11871 (this.options.height * this.svgDefault.width) / this.svgDefault.height; 11872 } 11873 else if (this.options.width && !this.options.height) { 11874 this.options.height = 11875 (this.options.width * this.svgDefault.height) / this.svgDefault.width; 11876 } 11877 this.whRatio = this.options.width / this.options.height; 11878 this.scale = this.getScale(); 11879 this.setResponsive(responsive); 11880 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 11881 this.redrawBubbles(); 11882 } 11883 this.movingItemsAdjustScreenPosition(); 11884 } 11885 setResponsive(on) { 11886 on = on != undefined ? MapSVG.parseBoolean(on) : this.options.responsive; 11887 $$A(this.containers.map).css({ 11888 width: "100%", 11889 height: "0", 11890 "padding-bottom": (this.viewBox.height * 100) / this.viewBox.width + "%", 11891 }); 11892 if (on) { 11893 $$A(this.containers.wrap).css({ 11894 width: "100%", 11895 height: "auto", 11896 }); 11897 } 11898 else { 11899 $$A(this.containers.wrap).css({ 11900 width: this.options.width + "px", 11901 height: this.options.height + "px", 11902 }); 11903 } 11904 $$A.extend(true, this.options, { responsive: on }); 11905 if (!this.resizeSensor) { 11906 this.resizeSensor = new ResizeSensor(this.containers.map, () => { 11907 this.redraw(); 11908 }); 11909 } 11910 this.redraw(); 11911 } 11912 setScroll(options, skipEvents) { 11913 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11914 options.limit != undefined && (options.limit = MapSVG.parseBoolean(options.limit)); 11915 $$A.extend(true, this.options, { scroll: options }); 11916 !skipEvents && this.setEventHandlers(); 11917 } 11918 setZoom(options) { 11919 options = options || {}; 11920 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 11921 options.fingers != undefined && (options.fingers = MapSVG.parseBoolean(options.fingers)); 11922 options.mousewheel != undefined && 11923 (options.mousewheel = MapSVG.parseBoolean(options.mousewheel)); 11924 options.delta = 2; 11925 if (options.limit) { 11926 if (typeof options.limit == "string") 11927 options.limit = options.limit.split(";"); 11928 options.limit = [parseInt(options.limit[0]), parseInt(options.limit[1])]; 11929 } 11930 if (!this.zoomLevels) { 11931 this.setZoomLevels(); 11932 } 11933 $$A.extend(true, this.options, { zoom: options }); 11934 $$A(this.containers.scrollpaneWrap).off("wheel.mapsvg"); 11935 if (this.options.zoom.mousewheel) { 11936 if (MapSVG.browser.firefox) { 11937 this.firefoxScroll = { insideIframe: false, scrollX: 0, scrollY: 0 }; 11938 $$A(this.containers.scrollpaneWrap) 11939 .on("mouseenter", () => { 11940 this.firefoxScroll.insideIframe = true; 11941 this.firefoxScroll.scrollX = window.scrollX; 11942 this.firefoxScroll.scrollY = window.scrollY; 11943 }) 11944 .on("mouseleave", () => { 11945 this.firefoxScroll.insideIframe = false;
11946 }); 11947 $$A(document).scroll(() => { 11948 if (this.firefoxScroll.insideIframe) 11949 window.scrollTo(this.firefoxScroll.scrollX, this.firefoxScroll.scrollY); 11950 }); 11951 } 11952 $$A(this.containers.scrollpaneWrap).on("wheel.mapsvg", (event) => { 11953 event.preventDefault(); 11954 this.mouseWheelZoom(event); 11955 return false; 11956 }); 11957 $$A(this.layers.markers).on("wheel.mapsvg", (event) => { 11958 event.preventDefault(); 11959 this.mouseWheelZoom(event); 11960 return false; 11961 }); 11962 } 11963 this.canZoom = true; 11964 } 11965 mouseWheelZoom(event) { 11966 event.preventDefault(); 11967 const d = Math.sign(-event.originalEvent.deltaY); 11968 const center = this.getSvgPointAtClick(event.originalEvent); 11969 d > 0 ? this.zoomIn(center) : this.zoomOut(center); 11970 } 11971 setControls(options) { 11972 options = options || {}; 11973 $$A.extend(true, this.options, { controls: options }); 11974 this.options.controls.zoom = MapSVG.parseBoolean(this.options.controls.zoom); 11975 this.options.controls.zoomReset = MapSVG.parseBoolean(this.options.controls.zoomReset); 11976 this.options.controls.userLocation = MapSVG.parseBoolean(this.options.controls.userLocation); 11977 this.options.controls.previousMap = MapSVG.parseBoolean(this.options.controls.previousMap); 11978 const loc = this.options.controls.location || "right"; 11979 if (!this.containers.controls) { 11980 const buttons = $$A("<div />").addClass("mapsvg-buttons"); 11981 const zoomGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 11982 const zoomIn = $$A("<div />").addClass("mapsvg-btn-map mapsvg-in"); 11983 zoomIn.on("touchend click", (e) => { 11984 if (e.cancelable) { 11985 e.preventDefault(); 11986 } 11987 e.stopPropagation(); 11988 this.zoomIn(); 11989 }); 11990 const zoomOut = $$A("<div />").addClass("mapsvg-btn-map mapsvg-out"); 11991 zoomOut.on("touchend click", (e) => { 11992 if (e.cancelable) { 11993 e.preventDefault(); 11994 } 11995 e.stopPropagation(); 11996 this.zoomOut(); 11997 }); 11998 zoomGroup.append(zoomIn).append(zoomOut); 11999 const location = $$A("<div />").addClass("mapsvg-btn-map mapsvg-btn-location"); 12000 location.on("touchend click", (e) => { 12001 if (e.cancelable) { 12002 e.preventDefault(); 12003 } 12004 e.stopPropagation(); 12005 this.showUserLocation((location) => { 12006 if (this.options.scroll.on) { 12007 this.centerOn(location.marker); 12008 } 12009 }); 12010 }); 12011 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>'; 12012 location.html(userLocationIcon); 12013 const locationGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12014 locationGroup.append(location); 12015 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>'; 12016 const zoomResetButton = $$A("<div />") 12017 .html(zoomResetIcon) 12018 .addClass("mapsvg-btn-map mapsvg-btn-zoom-reset"); 12019 zoomResetButton.on("touchend click", (e) => { 12020 if (e.cancelable) { 12021 e.preventDefault(); 12022 } 12023 e.stopPropagation(); 12024 this.viewBoxReset(true); 12025 }); 12026 const zoomResetGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12027 zoomResetGroup.append(zoomResetButton); 12028 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="">' + 12029 '<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)">' + 12030 '<g id="g4">
12030<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" ' + 12031 'id="path8" inkscape:connector-curvature="0" /></g></g></svg>'; 12032 const previousMapButton = $$A("<div />") 12033 .html(previousMapIcon) 12034 .addClass("mapsvg-btn-map mapsvg-btn-previous-map"); 12035 previousMapButton.on("touchend click", (e) => { 12036 if (e.cancelable) { 12037 e.preventDefault(); 12038 } 12039 e.stopPropagation(); 12040 this.loadPreviousMap(); 12041 }); 12042 const previousMapGroup = $$A("<div />").addClass("mapsvg-btn-group").appendTo(buttons); 12043 previousMapGroup.append(previousMapButton); 12044 this.containers.controls = buttons[0]; 12045 this.controls = { 12046 zoom: zoomGroup[0], 12047 userLocation: locationGroup[0], 12048 zoomReset: zoomResetGroup[0], 12049 previousMap: previousMapGroup[0], 12050 }; 12051 $$A(this.containers.map).append($$A(this.containers.controls)); 12052 } 12053 $$A(this.controls.zoom).toggle(this.options.controls.zoom); 12054 $$A(this.controls.userLocation).toggle(this.options.controls.userLocation); 12055 $$A(this.controls.zoomReset).toggle(this.options.controls.zoomReset); 12056 $$A(this.controls.previousMap).toggle(this.options.controls.previousMap && this.options.previousMapsIds.length > 0); 12057 $$A(this.containers.controls).removeClass("left"); 12058 $$A(this.containers.controls).removeClass("right"); 12059 (loc == "right" && $$A(this.containers.controls).addClass("right")) || 12060 (loc == "left" && $$A(this.containers.controls).addClass("left")); 12061 } 12062 setZoomLevels() { 12063 if (!this.zoomLevels) { 12064 this.zoomLevels = new ArrayIndexed("zoomLevel"); 12065 } 12066 else { 12067 this.zoomLevels.clear(); 12068 } 12069 for (let i = -20; i < 0; i++) { 12070 const _scale = 1 / Math.pow(this.options.zoom.delta, Math.abs(i)); 12071 this.zoomLevels.push({ 12072 zoomLevel: i, 12073 _scale: _scale,
12074 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12075 }); 12076 } 12077 for (let z = 0; z <= 20; z++) { 12078 const _scale = Math.pow(this.options.zoom.delta, Math.abs(z)); 12079 this.zoomLevels.push({ 12080 zoomLevel: z, 12081 _scale: _scale, 12082 viewBox: new ViewBox(0, 0, this._viewBox.width / _scale, this._viewBox.height / _scale), 12083 }); 12084 } 12085 } 12086 setCursor(type) { 12087 type = type == "pointer" ? "pointer" : "default"; 12088 this.options.cursor = type; 12089 if (type == "pointer") 12090 $$A(this.containers.map).addClass("mapsvg-cursor-pointer"); 12091 else 12092 $$A(this.containers.map).removeClass("mapsvg-cursor-pointer"); 12093 } 12094 setMultiSelect(on, deselect) { 12095 this.options.multiSelect = MapSVG.parseBoolean(on); 12096 if (deselect !== false) 12097 this.deselectAllRegions(); 12098 } 12099 _new_setChoropleth(options) { 12100 options = options || this.options.choropleth; 12101 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12102 if (typeof options.coloring === "undefined" || 12103 typeof options.coloring.palette === "undefined" || 12104 typeof options.coloring.palette.colors === "undefined") { 12105 if (typeof options.sourceFieldSelect === "undefined" || 12106 typeof options.sourceFieldSelect.variants === "undefined") { 12107 $$A.extend(true, this.options.choropleth, options); 12108 } 12109 else { 12110 this.options.choropleth.sourceFieldSelect.variants = 12111 options.sourceFieldSelect.variants; 12112 } 12113 } 12114 else { 12115 const paletteColorsIndexes = Object.keys(options.coloring.palette.colors); 12116 if (paletteColorsIndexes.length > 1 || 12117 (paletteColorsIndexes[0] == "0" && 12118 Object.keys(options.coloring.palette.colors[0]).length > 1)) { 12119 this.options.choropleth.coloring.palette.colors = options.coloring.palette.colors; 12120 } 12121 else { 12122 const paletteColorIndex = Object.keys(options.coloring.palette.colors)[0]; 12123 $$A.extend(true, this.options.choropleth.coloring.palette.colors[paletteColorIndex], options.coloring.palette.colors[paletteColorIndex]); 12124 } 12125 } 12126 this.updateChoroplethMinMax(); 12127 if (this.options.choropleth.on && 12128 this.options.choropleth.sourceFieldSelect.on && 12129 this.options.choropleth.sourceFieldSelect.variants) { 12130 if (!this.containers.choroplethSourceSelect) { 12131 const sourceSelectOptions = []; 12132 this.options.choropleth.sourceFieldSelect.variants.forEac
12132h((variant) => { 12133 sourceSelectOptions.push($$A('<option value="' + 12134 variant + 12135 '" ' + 12136 (variant === this.options.choropleth.sourceField 12137 ? "selected" 12138 : "") + 12139 ">" + 12140 variant + 12141 "</option>")); 12142 }); 12143 this.containers.choroplethSourceSelect = { 12144 container: $$A('<div class="mapsvg-choropleth-source-field"></div>')[0], 12145 select: $$A('<select id="mapsvg-choropleth-source-field-select" class="mapsvg-select2"></select>')[0], 12146 options: sourceSelectOptions, 12147 }; 12148 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12149 $$A(this.containers.choroplethSourceSelect.container).append($$A(this.containers.choroplethSourceSelect.select)); 12150 $$A(this.containers.map).append($$A(this.containers.choroplethSourceSelect.container)); 12151 $$A(this.containers.choroplethSourceSelect.select).mselect2(); 12152 $$A(this.containers.choroplethSourceSelect.select) 12153 .mselect2() 12154 .on("select2:select select2:unselecting", (e) => { 12155 if (e.cancelable) { 12156 e.preventDefault(); 12157 } 12158 e.stopPropagation(); 12159 this.setChoropleth({ sourceField: $$A(e.target).mselect2().val() }); 12160 }); 12161 } 12162 else { 12163 $$A(this.containers.choroplethSourceSelect.select).mselect2("destroy"); 12164 $$A(this.containers.choroplethSourceSelect.select).find("option").remove(); 12165 this.containers.choroplethSourceSelect.options = []; 12166 this.options.choropleth.sourceFieldSelect.variants.forEac
12166h((variant) => { 12167 this.containers.choroplethSourceSelect.options.push($$A('<option value="' + 12168 variant + 12169 '" ' + 12170 (variant === this.options.choropleth.sourceField 12171 ? "selected" 12172 : "") + 12173 ">" + 12174 variant + 12175 "</option>")[0]); 12176 }); 12177 $$A(this.containers.choroplethSourceSelect.select).append(this.containers.choroplethSourceSelect.options); 12178 $$A(this.containers.choroplethSourceSelect.select).mselect2({ width: "100%" }); 12179 } 12180 } 12181 if ((!this.options.choropleth.on || !this.options.choropleth.sourceFieldSelect.on) && 12182 this.containers.choroplethSourceSelect && 12183 $$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12184 $$A(this.containers.choroplethSourceSelect.container).hide(); 12185 } 12186 else if (this.options.choropleth.on && 12187 this.options.choropleth.sourceFieldSelect.on && 12188 this.containers.choroplethSourceSelect && 12189 !$$A(this.containers.choroplethSourceSelect.container).is(":visible")) { 12190 $$A(this.containers.choroplethSourceSelect.container).show(); 12191 } 12192 $$A(this.containers.map).find(".mapsvg-choropleth-legend").remove(); 12193 if (this.options.choropleth.on && this.options.choropleth.coloring.legend.on) { 12194 const legend = this.options.choropleth.coloring.legend; 12195 let coloring = ""; 12196 if (this.options.choropleth.coloring.mode === "gradient") { 12197 coloring += 12198 '<div class="mapsvg-choropleth-legend-gradient-no-data">' + 12199 this.options.choropleth.coloring.noData.description + 12200 "</div>"; 12201 let legendGradient = ""; 12202 for (let chunkIdx = 1; chunkIdx < 5; chunkIdx++) { 12203 legendGradient += 12204 '<div class="mapsvg-choropleth-legend-gradient-chunk">' + 12205 ((this.options.choropleth.coloring.gradient.values.maxAdjusted * chunkIdx) / 12206 5 + 12207 this.options.choropleth.coloring.gradient.values.min) + 12208 "</div>"; 12209 } 12210 coloring += 12211 '<div class="mapsvg-choropleth-legend-gradient-colors">' + 12212 legendGradient + 12213 "</div>"; 12214 } 12215 else { 12216 coloring += 12217 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="no-data">' + 12218 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12219 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12220 this.options.choropleth.coloring.noData.description + 12221 "</div>" + 12222 "</div>"; 12223 coloring += 12224 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="out-of-range">' + 12225 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12226 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12227 this.options.choropleth.coloring.palette.outOfRange.description + 12228 "</div>" + 12229 "</div>"; 12230 const paletteColors = this.options.choropleth.coloring.palette.colors; 12231 paletteColors.forEach((paletteColor, idx) => { 12232 let paletteColorElementText = ""; 12233 if (paletteColor.description) { 12234 paletteColorElementText = paletteColor.description; 12235 } 12236 else { 12237 if (idx === 0 && !paletteColor.valueFrom && paletteColor.valueFrom !== 0) { 12238 if (legend.layout === "vertical") { 12239 paletteColorElementText = "Less then " + paletteColor.valueTo; 12240 } 12241 else { 12242 paletteColorElementText = "< " + paletteColor.valueTo; 12243 } 12244 } 12245 else if (idx === paletteColors.length - 1 && !paletteColor.valueTo) { 12246 if (legend.layout === "vertical") { 12247 paletteColorElementText = paletteColor.valueFrom + " or more"; 12248 } 12249 else { 12250 paletteColorElementText = paletteColor.valueFrom + " <"; 12251 } 12252 } 12253 else { 12254 paletteColorElementText = 12255 paletteColor.valueFrom + " ≤ " + paletteColor.valueTo; 12256 } 12257 } 12258 coloring += 12259 '<div class="mapsvg-choropleth-legend-palette-color-wrap" data-idx="' + 12260 idx + 12261 '">' + 12262 '<div class="mapsvg-choropleth-legend-palette-color"></div>' + 12263 '<div class="mapsvg-choropleth-legend-palette-color-description">' + 12264 paletteColorElementText + 12265 "</div>" + 12266 "</div>"; 12267 }); 12268 } 12269 this.containers.legend = { 12270 title: $$A('<div class="mapsvg-choropleth-legend-title">' + legend.title + "</div>")[0], 12271 text: $$A('<div class="mapsvg-choropleth-legend-text">' + legend.text + "</div>")[0], 12272 coloring: $$A('<div class="mapsvg-choropleth-legend-' + 12273 this.options.choropleth.coloring.mode + 12274 '">' + 12275 coloring + 12276 "</div>")[0], 12277 description: $$A('<div class="mapsvg-choropleth-legend-description">' + 12278 legend.description + 12279 "</div>")[0], 12280 container: $$A("<div />").addClass("mapsvg-choropleth-legend mapsvg-choropleth-legend-" + 12281 legend.layout + 12282 " mapsvg-choropleth-legend-container-" + 12283 legend.container)[0], 12284 }; 12285 $$A(this.containers.legend.container) 12286 .append(this.containers.legend.title) 12287 .append(this.containers.legend.text) 12288 .append(this.containers.legend.coloring) 12289 .append(this.containers.legend.description); 12290 $$A(this.containers.map).append(this.containers.legend.container); 12291 this.setChoroplethLegendCSS(); 12292 this.regionsRepository.events.on("updated", () => { 12293 this.redrawChoropleth(); 12294 }); 12295 this.objectsRepository.events.on("updated", () => { 12296 this.redrawChoropleth(); 12297 }); 12298 } 12299 if (this.options.choropleth.on && this.options.choropleth.coloring.mode === "gradient") { 12300 const colors = this.options.choropleth.coloring.gradient.colors; 12301 if (colors) { 12302 colors.lowRGB = tinycolor(colors.low).toRgb(); 12303 colors.highRGB = tinycolor(colors.high).toRgb(); 12304 colors.diffRGB = { 12305 r: colors.highRGB.r - colors.lowRGB.r, 12306 g: colors.highRGB.g - colors.lowRGB.g, 12307 b: colors.highRGB.b - colors.lowRGB.b, 12308 a: colors.highRGB.a - colors.lowRGB.a, 12309 }; 12310 this.containers.legend && this.setChoroplethLegendCSS(); 12311 } 12312 } 12313 this.redrawChoropleth(); 12314 } 12315 redrawChoropleth() { 12316 this.updateChoroplethMinMax(); 12317 this.redrawBubbles(); 12318 this.regionsRedrawColors(); 12319 } 12320 updateChoroplethMinMax() { 12321 if (this.options.choropleth.on) { 12322 const gradient = this.options.choropleth.coloring.gradient, values = []; 12323 gradient.values.min = 0; 12324 gradient.values.max = null; 12325 if (this.options.choropleth.source === "regions") { 12326 this.regions.forEach((region) => { 12327 const choropleth = region.data && region.data[this.options.choropleth.sourceField]; 12328 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12329 }); 12330 } 12331 else {
12332 this.objectsRepository.objects.forEach((object) => { 12333 const choropleth = object[this.options.choropleth.sourceField]; 12334 choropleth != undefined && choropleth !== "" && values.push(choropleth); 12335 }); 12336 } 12337 if (values.length > 0) { 12338 gradient.values.min = Math.min.apply(null, values); 12339 gradient.values.max = Math.max.apply(null, values); 12340 gradient.values.maxAdjusted = gradient.values.max - gradient.values.min; 12341 } 12342 } 12343 } 12344 setChoroplethLegendCSS() { 12345 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; 12346 $$A(".mapsvg-choropleth-legend").css({ 12347 width: legend.width, 12348 height: legend.height, 12349 }); 12350 if (this.options.choropleth.coloring.mode === "gradient") { 12351 if (legend.layout === "horizontal") { 12352 $$A(".mapsvg-choropleth-legend-horizontal .mapsvg-choropleth-legend-gradient-colors").css({ 12353 background: "linear-gradient(to right," + 12354 gradient.colors.low + 12355 " 1%," + 12356 gradient.colors.high + 12357 " 100%)", 12358 }); 12359 } 12360 else { 12361 $$A(".mapsvg-choropleth-legend-vertical .mapsvg-choropleth-legend-gradient-colors").css({ 12362 background: "linear-gradient(to bottom," + 12363 gradient.colors.low + 12364 " 1%," + 12365 gradient.colors.high + 12366 " 100%)", 12367 }); 12368 } 12369 $$A(".mapsvg-choropleth-legend-gradient-no-data").css({ 12370 "background-color": noData.color, 12371 }); 12372 } 12373 else { 12374 const paletteColors = this.options.choropleth.coloring.palette.colors; 12375 paletteColors.forEach(function (paletteColor, idx) { 12376 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="' + 12377 idx + 12378 '"] .mapsvg-choropleth-legend-palette-color').css({ 12379 "background-color": paletteColor.color, 12380 }); 12381 }); 12382 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="no-data"] .mapsvg-choropleth-legend-palette-color').css({ 12383 "background-color": noData.color, 12384 }); 12385 $$A('.mapsvg-choropleth-legend-palette-color-wrap[data-idx="out-of-range"] .mapsvg-choropleth-legend-palette-color').css({ 12386 "background-color": outOfRange.color, 12387 }); 12388 } 12389 } 12390 setCss(css) { 12391 this.options.css = 12392 css || (this.options.css ? this.options.css.replace(/%id%/g, "" + this.id) : ""); 12393 this.liveCss = this.liveCss || $$A("<style></style>").appendTo("head")[0]; 12394 $$A(this.liveCss).html(this.options.css); 12395 } 12396 setFilters(options) { 12397 options = options || this.options.filters; 12398 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12399 options.hide != undefined && (options.hide = MapSVG.parseBoolean(options.hide)); 12400 $$A.extend(true, this.options, { filters: options }); 12401 if (!MapSVG.googleMapsApiLoaded && 12402 this.options.filters.on && 12403 this.filtersSchema.getField("distance")) { 12404 this.loadGoogleMapsAPI(() => { 12405 return 1; 12406 }, () => { 12407 return 1; 12408 }); 12409 } 12410 if (["leftSidebar", "rightSidebar", "header", "footer", "custom", "map"].indexOf(this.options.filters.location) === -1) { 12411 this.options.filters.location = "leftSidebar"; 12412 } 12413 if (this.options.filters.on) { 12414 if (this.formBuilder) { 12415 this.formBuilder.destroy(); 12416 } 12417 if (!this.containers.filters) { 12418 this.containers.filters = $$A('<div class="mapsvg-filters-wrap"></div>')[0]; 12419 } 12420 else { 12421 $$A(this.containers.filters).empty(); 12422 $$A(this.containers.filters).show(); 12423 } 12424 $$A(this.containers.filters).css({ 12425 "background-color": this.options.colors.directorySearch, 12426 }); 12427 if ($$A(this.containers.filtersModal)) { 12428 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 12429 } 12430 if (this.options.filters.location === "custom") { 12431 $$A(this.containers.filters) 12432 .removeClass("mapsvg-filter-container-custom") 12433 .addClass("mapsvg-filter-container-custom"); 12434 if ($$A("#" + this.options.filters.containerId).length) { 12435 $$A("#" + this.options.filters.containerId).append(this.containers.filters); 12436 } 12437 else { 12438 $$A(this.containers.filters).hide(); 12439 console.error("MapSVG: filter container #" + 12440 this.options.filters.containerId + 12441 " does not exists"); 12442 } 12443 } 12444 else { 12445 if (MapSVG.isPhone) { 12446 $$A(this.containers.header).append($$A(this.containers.filters)); 12447 this.setContainers({ header: { on: true } }); 12448 } 12449 else { 12450 const location = MapSVG.isPhone ? "header" : this.options.filters.location; 12451 if (this.options.menu.on && 12452 this.controllers.directory && 12453 this.options.menu.location === this.options.filters.location) { 12454 $$A(this.controllers.directory.containers.view) 12455 .find(".mapsvg-directory-filter-wrap") 12456 .append($$A(this.containers.filters)); 12457 this.controllers.directory.updateTopShift(); 12458 } 12459 else { 12460 $$A(this.containers[location]).append($$A(this.containers.filters)); 12461 this.controllers.directory && this.controllers.directory.updateTopShift(); 12462 } 12463 } 12464 } 12465 this.loadFiltersController(this.containers.filters, false); 12466 this.updateFiltersState(); 12467 } 12468 else { 12469 if ($$A(this.containers.filters)) { 12470 $$A(this.containers.filters).empty(); 12471 $$A(this.containers.filters).hide(); 12472 } 12473 } 12474 if (this.options.menu.on && 12475 this.controllers.directory && 12476 this.options.menu.location === this.options.filters.location) { 12477 this.controllers.directory.updateTopShift(); 12478 } 12479 } 12480 updateFiltersState() { 12481 if (this.options.filters && this.options.filters.on && this.controllers.filters) { 12482 this.controllers.filters.update(this.objectsRepository.query); 12483 this.updateFilterTags(); 12484 } 12485 } 12486 setGlobalDistanceFilter() { 12487 if (this.objectsRepository && 12488 this.objectsRepository.query.filters && 12489 this.objectsRepository.query.filters.distance) { 12490 const dist = this.objectsRepository.query.filters.distance; 12491 MapSVG.distanceSearch = this.objectsRepository.query.filters.distance; 12492 } 12493 else { 12494 MapSVG.distanceSearch = null; 12495 } 12496 } 12497 updateFilterTags() { 12498 $$A(this.containers.filterTags) && $$A(this.containers.filterTags).empty(); 12499 for (const field_name in this.objectsRepository.query.filters) { 12500 let field_value = this.objectsRepository.query.filters[field_name]; 12501 let _field_name = field_name; 12502 const filterField = this.filtersSchema.getField(_field_name); 12503 if (field_name == "regions") { 12504 _field_name = ""; 12505 field_value = field_value.region_ids.map((id) => this.getRegion(id).title); 12506 } 12507 else { 12508 _field_name = filterField && filterField.label; 12509 } 12510 if (field_name !== "distance") { 12511 if (!this.containers.filterTags) { 12512 this.containers.filterTags = $$A('<div class="mapsvg-filter-tags"></div>')[0]; 12513 if ($$A(this.containers.filters)) ; 12514 else { 12515 if (this.options.menu.on && this.controllers.directory) { 12516 $$A(this.controllers.directory.containers.toolbar).append(this.containers.filterTags); 12517 this.controllers.directory.updateTopShift(); 12518 } 12519 else { 12520 $$A(this.containers.map).append(this.containers.filterTags); 12521 if (this.options.zoom.buttons.on) { 12522 if (this.options.layersControl.on) { 12523 if (this.options.layersControl.position == "top-left") { 12524 $$A(this.containers.filterTags).css({ 12525 right: 0, 12526 bottom: 0, 12527 }); 12528 } 12529 else { 12530 $$A(this.containers.filterTags).css({ 12531 bottom: 0, 12532 }); 12533 } 12534 } 12535 else { 12536 if (this.options.zoom.buttons.location == "left") { 12537 $$A(this.containers.filterTags).css({ 12538 right: 0, 12539 }); 12540 } 12541 } 12542 } 12543 } 12544 } 12545 $$A(this.containers.filterTags).on("click", ".mapsvg-filter-delete", (e) => { 12546 const filterField = $$A(e.target).data("filter"); 12547 $$A(e.target).parent().remove(); 12548 this.objectsRepository.query.removeFilter(filterField); 12549 this.deselectAllRegions(); 12550 this.loadDataObjects(); 12551 }); 12552 } 12553 $$A(this.containers.filterTags).append('<div class="mapsvg-filter-tag">' + 12554 (_field_name ? _field_name + ": " : "") + 12555 field_value + 12556 ' <span class="mapsvg-filter-delete" data-filter="' + 12557 field_name + 12558 '">
12558Ã</span></div>'); 12559 } 12560 } 12561 } 12562 setContainers(options) { 12563 const _this = this; 12564 if (!this.containersCreated) { 12565 this.containers.wrapAll = document.createElement("div"); 12566 this.containers.wrapAll.classList.add("mapsvg-wrap-all"); 12567 this.containers.wrapAll.id = "mapsvg-map-" + this.id; 12568 this.containers.wrapAll.setAttribute("data-map-id", this.id ? this.id.toString() : ""); 12569 this.containers.wrap = document.createElement("div"); 12570 this.containers.wrap.classList.add("mapsvg-wrap"); 12571 this.containers.mapContainer = document.createElement("div"); 12572 this.containers.mapContainer.classList.add("mapsvg-map-container"); 12573 this.containers.leftSidebar = document.createElement("div"); 12574 this.containers.leftSidebar.className = 12575 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"; 12576 this.containers.rightSidebar = document.createElement("div"); 12577 this.containers.rightSidebar.className = 12578 "mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"; 12579 this.containers.header = document.createElement("div"); 12580 this.containers.header.className = "mapsvg-header mapsvg-top-container"; 12581 this.containers.footer = document.createElement("div"); 12582 this.containers.footer.className = "mapsvg-footer mapsvg-top-container"; 12583 _this.containers.wrapAll = $$A('<div class="mapsvg-wrap-all"></div>') 12584 .attr("id", "mapsvg-map-" + this.id) 12585 .attr("data-map-id", this.id)[0]; 12586 _this.containers.wrap = $$A('<div class="mapsvg-wrap"></div>')[0]; 12587 _this.containers.mapContainer = $$A('<div class="mapsvg-map-container"></div>')[0]; 12588 _this.containers.leftSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-left"></div>')[0]; 12589 _this.containers.rightSidebar = $$A('<div class="mapsvg-sidebar mapsvg-top-container mapsvg-sidebar-right"></div>')[0]; 12590 _this.containers.header = $$A('<div class="mapsvg-header mapsvg-top-container"></div>')[0]; 12591 _this.containers.footer = $$A('<div class="mapsvg-footer mapsvg-top-container"></div>')[0]; 12592 $$A(_this.containers.wrapAll).insertBefore(_this.containers.map); 12593 $$A(_this.containers.wrapAll).append(_this.containers.header); 12594 $$A(_this.containers.wrapAll).append(_this.containers.wrap); 12595 $$A(_this.containers.wrapAll).append(_this.containers.footer); 12596 $$A(_this.containers.mapContainer).append(_this.containers.map); 12597 $$A(_this.containers.wrap).append(_this.containers.leftSidebar); 12598 $$A(_this.containers.wrap).append(_this.containers.mapContainer); 12599 $$A(_this.containers.wrap).append(_this.containers.rightSidebar); 12600 _this.containersCreated = true; 12601 } 12602 options = options || _this.options.containers || {}; 12603 for (const contName in options) { 12604 if (options[contName].on !== undefined) { 12605 options[contName].on = MapSVG.parseBoolean(options[contName].on); 12606 } 12607 if (options[contName].width) { 12608 if (typeof options[contName].width != "string" || 12609 (options[contName].width.indexOf("px") === -1 && 12610 options[contName].width.indexOf("%") === -1 && 12611 options[contName].width !== "auto")) { 12612 options[contName].width = options[contName].width + "px"; 12613 } 12614 $$A(_this.containers[contName]).css({ "flex-basis": options[contName].width }); 12615 } 12616 if (options[contName].height) { 12617 if (typeof options[contName].height != "string" || 12618 (options[contName].height.indexOf("px") === -1 && 12619 options[contName].height.indexOf("%") === -1 && 12620 options[contName].height !== "auto")) { 12621 options[contName].height = options[contName].height + "px"; 12622 } 12623 $$A(_this.containers[contName]).css({ 12624 "flex-basis": options[contName].height, 12625 height: options[contName].height, 12626 }); 12627 } 12628 $$A.extend(true, _this.options, { containers: options }); 12629 let on = _this.options.containers[contName].on; 12630 if (MapSVG.isPhone && 12631 _this.options.menu.hideOnMobile && 12632 _this.options.menu.location === contName && 12633 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12634 on = false;
12635 } 12636 else if (MapSVG.isPhone && 12637 _this.options.menu.location === "custom" && 12638 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12639 on = false; 12640 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12641 } 12642 else if (MapSVG.isPhone && 12643 !_this.options.menu.hideOnMobile && 12644 _this.options.menu.location === contName && 12645 ["leftSidebar", "rightSidebar"].indexOf(contName) !== -1) { 12646 $$A(_this.containers.wrapAll).addClass("mapsvg-hide-map-list-buttons"); 12647 $$A(_this.containers.wrapAll).addClass("mapsvg-directory-visible"); 12648 } 12649 $$A(_this.containers[contName]).toggle(on); 12650 } 12651 _this.setDetailsView(); 12652 } 12653 shouldBeScrollable(container) { 12654 const _this = this; 12655 switch (container) { 12656 case "map": 12657 case "leftSidebar": 12658 case "rightSidebar": 12659 return true; 12660 case "custom": 12661 return false; 12662 case "header": 12663 case "footer": 12664 if (_this.options.containers[container].height && 12665 _this.options.containers[container].height !== "auto" && 12666 _this.options.containers[container].height !== "100%") { 12667 return true; 12668 } 12669 else { 12670 return false; 12671 } 12672 default: 12673 return false; 12674 } 12675 } 12676 setDirectory(options) { 12677 return this.setMenu(options); 12678 } 12679 setMenu(options) { 12680 options = options || this.options.menu; 12681 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12682 options.search != undefined && (options.search = MapSVG.parseBoolean(options.search)); 12683 options.showMapOnClick != undefined && 12684 (options.showMapOnClick = MapSVG.parseBoolean(options.showMapOnClick)); 12685 options.searchFallback != undefined && 12686 (options.searchFallback = MapSVG.parseBoolean(options.searchFallback)); 12687 options.customContainer != undefined && 12688 (options.customContainer = MapSVG.parseBoolean(options.customContainer)); 12689 $$A.extend(true, this.options, { menu: options }); 12690 this.controllers = this.controllers || {}; 12691 if (!this.containers.directory) { 12692 this.containers.directory = $$A('<div class="mapsvg-directory"></div>')[0]; 12693 } 12694 $$A(this.containers.directory).toggleClass("flex", this.shouldBeScrollable(this.options.menu.location)); 12695 if (this.options.menu.on) { 12696 if (!this.controllers.directory) { 12697 this.controllers.directory = new DirectoryController({ 12698 container: this.containers.directory, 12699 template: this.options.templates.directory, 12700 mapsvg: this, 12701 repository: this.options.menu.source === "regions" 12702 ? this.regionsRepository 12703 : this.objectsRepository, 12704 scrollable: this.shouldBeScrollable(this.options.menu.location), 12705 events: { 12706 click: (e, regionOrObject, mapsvg) => { 12707 this.events.trigger("click.directoryItem", this, [ 12708 e, 12709 regionOrObject, 12710 mapsvg, 12711 ]); 12712 }, 12713 mouseover: (e, regionOrObject, mapsvg) => { 12714 this.events.trigger("mouseover.directoryItem", this, [ 12715 e, 12716 regionOrObject, 12717 mapsvg, 12718 ]); 12719 }, 12720 mouseout: (e, regionOrObject, mapsvg) => { 12721 this.events.trigger("mouseout.directoryItem", this, [ 12722 e, 12723 regionOrObject, 12724 mapsvg, 12725 ]); 12726 }, 12727 }, 12728 }); 12729 this.controllers.directory._init(); 12730 } 12731 if (options.source) { 12732 this.controllers.directory.repository = 12733 this.options.menu.source === "regions" 12734 ? this.regionsRepository 12735 : this.objectsRepository; 12736 } 12737 if (options.sortBy || options.sortDirection) { 12738 this.controllers.directory.repository.query.update({ 12739 sort: [ 12740 { 12741 field: this.options.menu.sortBy, 12742 order: this.options.menu.sortDirection, 12743 }, 12744 ], 12745 }); 12746 } 12747 this.setFilterOut(); 12748 if (options.location) { 12749 this.controllers.directory.scrollable = this.shouldBeScrollable(this.options.menu.location); 12750 } 12751 let $container; 12752 if (MapSVG.isPhone && this.options.menu.hideOnMobile) { 12753 $container = $$A(this.containers.leftSidebar); 12754 } 12755 else { 12756 $container = 12757 this.options.menu.location !== "custom" 12758 ? $$A(this.containers[this.options.menu.location]) 12759 : $$A("#" + this.options.menu.containerId); 12760 } 12761 $container.append(this.containers.directory); 12762 if (this.options.colors.directory) { 12763 $$A(this.containers.directory).css({ 12764 "background-color": this.options.colors.directory, 12765 }); 12766 } 12767 this.setFilters(); 12768 this.setTemplates({ directoryItem: this.options.templates.directoryItem }); 12769 if ((this.options.menu.source === "regions" && this.regionsRepository.loaded) || 12770 (this.options.menu.source === "database" && this.objectsRepository.loaded)) { 12771 if (this.editMode && 12772 (options.sortBy || options.sortDirection || options.filterout)) { 12773 this.controllers.directory.repository.reload(); 12774 } 12775 this.loadDirectory(); 12776 } 12777 } 12778 else { 12779 this.controllers.directory && this.controllers.directory.destroy(); 12780 this.controllers.directory = null; 12781 } 12782 } 12783 setDatabase(options) { 12784 options = options || this.options.database; 12785 if (options.pagination) { 12786 if (options.pagination.on != undefined) { 12787 options.pagination.on = MapSVG.parseBoolean(options.pagination.on); 12788 } 12789 if (options.pagination.perpage != undefined) { 12790 options.pagination.perpage = parseInt(options.pagination.perpage); 12791 } 12792 } 12793 $$A.extend(true, this.options, { database: options }); 12794 if (options.pagination) { 12795 if (options.pagination.on !== undefined || options.pagination.perpage) { 12796 const query = new Query({ 12797 perpage: this.options.database.pagination.on 12798 ? this.options.database.pagination.perpage 12799 : 0, 12800 }); 12801 this.objectsRepository.find(query); 12802 } 12803 else { 12804 this.setPagination(); 12805 } 12806 } 12807 } 12808 updateGoogleMapsMaxZoom(geoPoint) { 12809 this.googleMaps.maxZoomService.getMaxZoomAtLatLng(geoPoint, (result) => { 12810 if (result.status === "OK") { 12811 this.googleMaps.currentMaxZoom = result.zoom; 12812 } 12813 }); 12814 } 12815 setGoogleMaps(options) { 12816 options = options || this.options.googleMaps; 12817 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 12818 if (!this.googleMaps) { 12819 this.googleMaps = { loaded: false, initialized: false, map: null, overlay: null }; 12820 } 12821 $$A.extend(true, this.options, { googleMaps: options }); 12822 if (this.options.googleMaps.on) { 12823 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12824 if (!MapSVG.googleMapsApiLoaded) { 12825 this.loadGoogleMapsAPI(() => { 12826 this.setGoogleMaps(); 12827 }, () => { 12828 this.setGoogleMaps({ on: false }); 12829 }); 12830 } 12831 else { 12832 if (!this.googleMaps.map) { 12833 this.containers.googleMaps = $$A('<div class="mapsvg-layer mapsvg-layer-gm" id="mapsvg-google-maps-' + 12834 this.id + 12835 '"></div>').prependTo(this.containers.map)[0]; 12836 $$A(this.containers.googleMaps).css({ 12837 position: "absolute", 12838 top: 0, 12839 left: 0, 12840 bottom: 0, 12841 right: 0, 12842 "z-index": "0", 12843 }); 12844 this.googleMaps.map = new google.maps.Map(this.containers.googleMaps, { 12845 mapTypeId: options.type, 12846 fullscreenControl: false, 12847 keyboardShortcuts: false, 12848 mapTypeControl: false, 12849 scaleControl: false, 12850 scrollwheel: false, 12851 streetViewControl: false, 12852 zoomControl: false, 12853 styles: options.styleJSON, 12854 tilt: 0, 12855 }); 12856 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 12857 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 12858 const bounds = new google.maps.LatLngBounds(southWest, northEast);
12859 this.googleMaps.overlay = this.createGoogleMapOverlay(bounds, this.googleMaps.map); 12860 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 12861 this.googleMaps.map.fitBounds(bounds, 0); 12862 } 12863 else { 12864 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 12865 this.googleMaps.map.setCenter(this.options.googleMaps.center); 12866 } 12867 this.googleMaps.initialized = true; 12868 this.googleMaps.maxZoomService = new google.maps.MaxZoomService(); 12869 this.googleMaps.map.addListener("idle", () => { 12870 this.isZooming = false; 12871 }); 12872 google.maps.event.addListenerOnce(this.googleMaps.map, "idle", () => { 12873 setTimeout(() => { 12874 $$A(this.containers.map).addClass("mapsvg-fade-in"); 12875 setTimeout(() => { 12876 $$A(this.containers.map).removeClass("mapsvg-google-map-loading"); 12877 $$A(this.containers.map).removeClass("mapsvg-fade-in"); 12878 if (!this.options.googleMaps.center || 12879 !this.options.googleMaps.zoom) { 12880 this.options.googleMaps.center = this.googleMaps.map 12881 .getCenter() 12882 .toJSON(); 12883 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 12884 } 12885 this.zoomDelta = this.options.googleMaps.zoom - this.zoomLevel; 12886 this.updateGoogleMapsMaxZoom(this.options.googleMaps.center); 12887 this.setInitialViewBox(this.viewBox); 12888 this.toggleSvgLayerOnZoom(); 12889 this.events.trigger("googleMapsLoaded"); 12890 this.afterLoadBlockers--; 12891 this.finalizeMapLoading(); 12892 }, 300); 12893 }, 1); 12894 }); 12895 this.events.on("googleMapsBoundsChanged", (bounds) => { 12896 this.setViewBoxByGoogleMapsOverlay(); 12897 }); 12898 } 12899 else { 12900 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", true); 12901 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).show(); 12902 if (options.type) { 12903 this.googleMaps.map.setMapTypeId(options.type); 12904 } 12905 this.setViewBoxByGoogleMapsOverlay(); 12906 } 12907 } 12908 } 12909 else { 12910 $$A(this.containers.map).toggleClass("mapsvg-with-google-map", false); 12911 $$A(this.containers.googleMaps) && $$A(this.containers.googleMaps).hide(); 12912 this.googleMaps.initialized = false; 12913 } 12914 if (this.converter) { 12915 this.converter.setWorldShift(this.options.googleMaps.on); 12916 } 12917 } 12918 createGoogleMapOverlay(bounds, map) { 12919 class GoogleMapsOverlay extends google.maps.OverlayView { 12920 constructor(bounds, googleMapInstance, mapsvg) { 12921 super(); 12922 this.bounds_ = bounds; 12923 this.map_ = googleMapInstance; 12924 this.mapsvg = mapsvg; 12925 this.setMap(googleMapInstance); 12926 this.prevCoords = { 12927 sw: { x: 0, y: 0 }, 12928 sw2: { x: 0, y: 0 }, 12929 ne: { x: 0, y: 0 }, 12930 ne2: { x: 0, y: 0 }, 12931 }; 12932 } 12933 draw() { 12934 this.mapsvg.events.trigger("googleMapsBoundsChanged", this.map_, [ 12935 this.getPixelBounds(), 12936 this.map_, 12937 ]); 12938 } 12939 onAdd() { 12940 this.element = document.createElement("div"); 12941 this.element.style.borderStyle = "none"; 12942 this.element.style.borderWidth = "0px"; 12943 this.element.style.position = "absolute"; 12944 const panes = this.getPanes(); 12945 panes.overlayLayer.appendChild(this.element); 12946 } 12947 getPixelBounds() { 12948 const overlayProjection = this.getProjection(); 12949 if (!overlayProjection) 12950 return;
12951 const geoSW = this.bounds_.getSouthWest(); 12952 const geoNE = this.bounds_.getNorthEast(); 12953 const coords = { 12954 sw: overlayProjection.fromLatLngToDivPixel(geoSW), 12955 ne: overlayProjection.fromLatLngToDivPixel(geoNE), 12956 sw2: overlayProjection.fromLatLngToContainerPixel(geoSW), 12957 ne2: overlayProjection.fromLatLngToContainerPixel(geoNE), 12958 }; 12959 const ww = overlayProjection.getWorldWidth(); 12960 if (this.prevCoords.sw) { 12961 if (coords.ne.x < coords.sw.x) { 12962 if (Math.abs(this.prevCoords.sw.x - coords.sw.x) > 12963 Math.abs(this.prevCoords.ne.x - coords.ne.x)) { 12964 coords.sw.x = coords.sw.x - ww; 12965 } 12966 else { 12967 coords.ne.x = coords.ne.x + ww; 12968 } 12969 if (Math.abs(this.prevCoords.sw2.x - coords.sw2.x) > 12970 Math.abs(this.prevCoords.ne2.x - coords.ne2.x)) { 12971 coords.sw2.x = coords.sw2.x - ww; 12972 } 12973 else { 12974 coords.ne2.x = coords.ne2.x + ww; 12975 } 12976 } 12977 } 12978 this.prevCoords = coords; 12979 return { sw: coords.sw2, ne: coords.ne2 }; 12980 } 12981 } 12982 return new GoogleMapsOverlay(bounds, map, this); 12983 } 12984 loadGoogleMapsAPI(callback, fail) { 12985 if (!this.options.googleMaps.apiKey) { 12986 console.error("MapSVG: can't load Google API because no API key has been provided"); 12987 return; 12988 } 12989 if (window.google !== undefined && google.maps) { 12990 MapSVG.googleMapsApiLoaded = true; 12991 } 12992 if (MapSVG.googleMapsApiLoaded) { 12993 if (typeof callback == "function") { 12994 callback(); 12995 } 12996 return; 12997 } 12998 MapSVG.googleMapsLoadCallbacks = MapSVG.googleMapsLoadCallbacks || []; 12999 if (typeof callback == "function") { 13000 MapSVG.googleMapsLoadCallbacks.push(callback); 13001 } 13002 if (MapSVG.googleMapsApiIsLoading) { 13003 return; 13004 } 13005 MapSVG.googleMapsApiIsLoading = true; 13006 window.gm_authFailure = () => { 13007 if (MapSVG.GoogleMapBadApiKey) { 13008 MapSVG.GoogleMapBadApiKey(); 13009 } 13010 else { 13011 if (this.editMode) { 13012 alert("Google maps API key is incorrect."); 13013 } 13014 else { 13015 console.error("MapSVG: Google maps API key is incorrect."); 13016 } 13017 } 13018 }; 13019 this.googleMapsScript = document.createElement("script"); 13020 this.googleMapsScript.onload = () => { 13021 MapSVG.googleMapsApiLoaded = true; 13022 MapSVG.googleMapsLoadCallbacks.forEach((_callback) => { 13023 if (typeof callback == "function") 13024 _callback(); 13025 }); 13026 }; 13027 const gmLibraries = []; 13028 if (this.options.googleMaps.drawingTools) { 13029 gmLibraries.push("drawing"); 13030 } 13031 if (this.options.googleMaps.geometry) { 13032 gmLibraries.push("geometry"); 13033 } 13034 let libraries = ""; 13035 if (gmLibraries.length > 0) { 13036 libraries = "&libraries=" + gmLibraries.join(","); 13037 } 13038 this.googleMapsScript.src = 13039 "https://maps.googleapis.com/maps/api/js?language=" + 13040 this.options.googleMaps.language + 13041 "&key=" + 13042 this.options.googleMaps.apiKey + 13043 libraries; 13044 document.head.appendChild(this.googleMapsScript); 13045 } 13046 loadDetailsView(obj) { 13047 this.controllers.popover && this.controllers.popover.close(); 13048 if (this.controllers.detailsView) 13049 this.controllers.detailsView.destroy(); 13050 this.controllers.detailsView = new DetailsController({ 13051 autoresize: MapSVG.isPhone && 13052 this.options.detailsView.mobileFullscreen && 13053 this.options.detailsView.location !== "custom" 13054 ? false 13055 : this.options.detailsView.autoresize, 13056 container: this.containers.detailsView, 13057 template: obj instanceof Region 13058 ? this.options.templates.detailsViewRegion 13059 : this.options.templates.detailsView, 13060 mapsvg: this, 13061 data: obj.getData(), 13062 modal: MapSVG.isPhone && 13063 this.options.detailsView.mobileFullscreen && 13064 this.options.detailsView.location !== "custom", 13065 scrollable: (MapSVG.isPhone && 13066 this.options.detailsView.mobileFullscreen && 13067 this.options.detailsView.location !== "custom") || 13068 this.shouldBeScrollable(this.options.detailsView.location), 13069 withToolbar: !(MapSVG.isPhone && 13070 this.options.detailsView.mobileFullscreen && 13071 this.options.detailsView.location !== "custom") && this.shouldBeScrollable(this.options.detailsView.location), 13072 events: { 13073 shown: (detailsController) => { 13074 this.events.trigger("shown.detailsView", this, [this, detailsController]); 13075 $$A(window).trigger("shown.detailsView", [this, detailsController]); 13076 }, 13077 closed: (detailsController) => { 13078 this.deselectAllRegions(); 13079 this.deselectAllMarkers(); 13080 this.controllers && 13081 this.controllers.directory && 13082 this.controllers.directory.deselectItems(); 13083 this.events.trigger("closed.detailsView", [this, detailsController]); 13084 }, 13085 }, 13086 }); 13087 this.controllers.detailsView._init(); 13088 } 13089 loadFiltersModal() { 13090 if (this.options.filters.modalLocation != "custom") { 13091 if (!this.containers.filtersModal) { 13092 this.containers.filtersModal = $$A('<div class="mapsvg-details-container mapsvg-filters-wrap"></div>')[0]; 13093 } 13094 this.setColors(); 13095 $$A(this.containers.filtersModal).css({ width: this.options.filters.width }); 13096 if (MapSVG.isPhone) { 13097 $$A("body").append($$A(this.containers.filtersModal)); 13098 $$A(this.containers.filtersModal).css({ width: "" }); 13099 } 13100 else { 13101 $$A(this.containers[this.options.filters.modalLocation]).append($$A(this.containers.filtersModal)); 13102 } 13103 } 13104 else { 13105 this.containers.filtersModal = $$A("#" + this.options.filters.containerId)[0]; 13106 $$A(this.containers.filtersModal).css({ width: "" }); 13107 } 13108 this.loadFiltersController(this.containers.filtersModal, true); 13109 } 13110 loadFiltersController(container, modal = false) { 13111 if (!this.filtersShouldBeShown()) { 13112 return; 13113 } 13114 let filtersInDirectory, filtersHide; 13115 if (MapSVG.isPhone) { 13116 filtersInDirectory = true; 13117 filtersHide = this.options.filters.hideOnMobile; 13118 } 13119 else { 13120 filtersInDirectory = 13121 this.options.menu.on && 13122 this.controllers.directory && 13123 this.options.menu.location === this.options.filters.location; 13124 filtersHide = this.options.filters.hide; 13125 } 13126 const scrollable = modal || 13127 (!filtersInDirectory && 13128 ["leftSidebar", "rightSidebar"].indexOf(this.options.filters.location) !== -1); 13129 this.filtersRepository = 13130 this.options.filters.source === "regions" 13131 ? this.regionsRepository 13132 : this.objectsRepository; 13133 if (this.options.filters.searchButton) { 13134 this.changedFields = null; 13135 this.changedSearch = null; 13136 } 13137 else { 13138 this.changedSearch = () => { 13139 this.filtersRepository.query.searchFallback = this.filtersSchema.getFieldByType("search").searchFallback; 13140 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13141 }; 13142 this.changedFields = () => { 13143 this.throttle(this.filtersRepository.reload, 400, this.filtersRepository); 13144 }; 13145 } 13146 this.controllers.filters = new FiltersController({ 13147 container: container, 13148 query: this.filtersRepository.query, 13149 mapsvg: this, 13150 schema: this.filtersSchema, 13151 template: '<div class="mapsvg-filters-container"></div>', 13152 scrollable: scrollable, 13153 modal: modal, 13154 withToolbar: MapSVG.isPhone ? false : modal, 13155 width: $$A(container).hasClass("mapsvg-map-container") 13156 ? this.options.filters.width 13157 : "100%", 13158 hide: this.options.filters.hide, 13159 hideOnMobile: this.options.filters.hideOnMobile, 13160 showButtonText: this.options.filters.showButtonText, 13161 clearButton: this.options.filters.clearButton, 13162 clearButtonText: this.options.filters.clearButtonText, 13163 searchButton: this.options.filters.searchButton, 13164 searchButtonText: this.options.filters.searchButtonText, 13165 padding: this.options.filters.padding, 13166 events: { 13167 cleared: () => { 13168 this.deselectAllRegions(); 13169 this.filtersRepository.reload(); 13170 }, 13171 "changed.fields": this.changedFields, 13172 "changed.search": this.changedSearch, 13173 "click.btn.searchButton": () => { 13174 this.filtersRepository.reload(); 13175 }, 13176 loaded: () => { 13177 this.controllers.directory && this.controllers.directory.updateTopShift(); 13178 this.afterLoadBlockers--; 13179 this.finalizeMapLoading(); 13180 }, 13181 "click.btn.showFilters": () => { 13182 this.loadFiltersModal(); 13183 }, 13184 }, 13185 }); 13186 this.controllers.filters._init(); 13187 } 13188 filtersShouldBeShown() { 13189 return (this.options.filters.on && 13190 this.options.filtersSchema && 13191 this.options.filtersSchema.length > 0); 13192 } 13193 textSearch(text, fallback = false) { 13194 const query = new Query({ 13195 filters: { search: text }, 13196 searchFallback: fallback, 13197 }); 13198 this.filtersRepository.find(query); 13199 } 13200 getRegion(id) { 13201 return this.regions.findById(id); 13202 } 13203 getRegions() { 13204 return this.regions; 13205 } 13206 getMarker(id) { 13207 return this.markers.findById(id); 13208 } 13209 checkId(id) { 13210 if (this.getRegion(id)) 13211 return { canUse: false, error: "This ID is already being used by a Region" }; 13212 else if (this.getMarker(id)) 13213 return { canUse: false, error: "This ID is already being used by another Marker" }; 13214 else 13215 return { canUse: true, error: "" }; 13216 } 13217 regionsRedrawColors() { 13218 this.regions.forEach((region) => { 13219 region.setFill(); 13220 }); 13221 } 13222 redrawBubbles() { 13223 $$A(this.containers.map).removeClass("bubbles-regions-on bubbles-database-on"); 13224 if (this.options.choropleth.on && this.options.choropleth.bubbleMode) { 13225 $$A(this.containers.map).addClass("bubbles-" + this.options.choropleth.source + "-on"); 13226 } 13227 this.regions.forEach(function (region) { 13228 region.drawBubble(); 13229 }); 13230 const markersBubbleMode = this.options.choropleth.on && 13231 this.options.choropleth.source == "database" && 13232 this.options.choropleth.bubbleMode;
13233 this.markers.forEach(function (marker) { 13234 marker.setBubbleMode(markersBubbleMode); 13235 }); 13236 } 13237 destroy() { 13238 if (this.controllers && this.controllers.directory) { 13239 this.controllers.directory.mobileButtons.remove(); 13240 } 13241 $$A(this.containers.map) 13242 .empty() 13243 .insertBefore($$A(this.containers.wrapAll)) 13244 .attr("style", "") 13245 .removeClass("mapsvg mapsvg-responsive"); 13246 this.controllers.popover && this.controllers.popover.close(); 13247 if (this.controllers.detailsView) 13248 this.controllers.detailsView.destroy(); 13249 $$A(this.containers.detailsView).remove(); 13250 $$A(this.containers.popover).remove(); 13251 $$A(this.containers.tooltip).remove(); 13252 $$A(this.containers.wrapAll).remove(); 13253 } 13254 getData() { 13255 return { 13256 id: this.id, 13257 title: this.options.title, 13258 options: this.getOptions(false, false), 13259 }; 13260 } 13261 mayBeFitMarkers() { 13262 if (!this.lastTimeFitWas) { 13263 this.lastTimeFitWas = Date.now() - 99999; 13264 } 13265 this.fitDelta = Date.now() - this.lastTimeFitWas; 13266 if (this.fitDelta > 1000 && 13267 !this.firstDataLoad && 13268 !this.fitOnDataLoadDone && 13269 this.options.fitMarkers) { 13270 this.fitMarkers(); 13271 this.fitOnDataLoadDone = true; 13272 } 13273 if (this.firstDataLoad && 13274 (this.options.fitMarkersOnStart || 13275 (this.options.fitMarkers && this.options.database.loadOnStart === false))) { 13276 this.firstDataLoad = false; 13277 if (this.options.googleMaps.on && !this.googleMaps.map) { 13278 this.events.on("googleMapsLoaded", () => { 13279 this.fitMarkers(); 13280 }); 13281 } 13282 else { 13283 this.fitMarkers(); 13284 } 13285 } 13286 this.lastTimeFitWas = Date.now(); 13287 } 13288 fitMarkers() { 13289 const dbObjects = this.objectsRepository.getLoaded(); 13290 if (!dbObjects || dbObjects.length === 0) { 13291 return; 13292 } 13293 if (this.options.googleMaps.on && typeof google !== "undefined") { 13294 const lats = []; 13295 const lngs = []; 13296 if (dbObjects.length > 1) { 13297 dbObjects.forEach((object) => { 13298 if (object.location && object.location.geoPoint) { 13299 lats.push(object.location.geoPoint.lat); 13300 lngs.push(object.location.geoPoint.lng); 13301 } 13302 }); 13303 const minlat = Math.min.apply(null, lats), maxlat = Math.max.apply(null, lats); 13304 const minlng = Math.min.apply(null, lngs), maxlng = Math.max.apply(null, lngs); 13305 const bbox = new google.maps.LatLngBounds({ lat: minlat, lng: minlng }, { lat: maxlat, lng: maxlng }); 13306 this.googleMaps.map.fitBounds(bbox, 0); 13307 } 13308 else { 13309 if (dbObjects[0].location && 13310 dbObjects[0].location.geoPoint.lat && 13311 dbObjects[0].location.geoPoint.lng) { 13312 const coords = { 13313 lat: dbObjects[0].location.geoPoint.lat, 13314 lng: dbObjects[0].location.geoPoint.lng, 13315 }; 13316 if (this.googleMaps.map) { 13317 this.googleMaps.map.setCenter(coords); 13318 this.googleMaps.map.setZoom(this.options.fitSingleMarkerZoom); 13319 } 13320 } 13321 } 13322 } 13323 else { 13324 if (this.options.clustering.on) { 13325 const arr = [];
13326 this.markersClusters.forEach((c) => { 13327 arr.push(c); 13328 }); 13329 this.markers.forEach((m) => { 13330 arr.push(m); 13331 }); 13332 this.zoomTo(arr); 13333 return; 13334 } 13335 else { 13336 this.zoomTo(this.markers); 13337 return; 13338 } 13339 } 13340 } 13341 setFitSingleMarkerZoom(zoom) { 13342 this.options.fitSingleMarkerZoom = parseInt(zoom); 13343 } 13344 showUserLocation(callback) { 13345 this.getUserLocation((geoPoint) => { 13346 this.userLocation = null; 13347 this.userLocation = new Location({ 13348 geoPoint: geoPoint, 13349 img: MapSVG.urls.root + "/markers/user-location.svg", 13350 }); 13351 this.userLocationMarker && this.userLocationMarker.delete(); 13352 this.userLocationMarker = new Marker({ 13353 location: this.userLocation, 13354 mapsvg: this, 13355 width: 15, 13356 height: 15, 13357 }); 13358 $$A(this.userLocationMarker.element).addClass("mapsvg-user-location"); 13359 this.userLocationMarker.centered = true; 13360 this.getLayer("markers").append(this.userLocationMarker.element); 13361 this.userLocationMarker.adjustScreenPosition(); 13362 callback && callback(this.userLocation); 13363 }); 13364 } 13365 getUserLocation(callback) { 13366 if (navigator.geolocation) { 13367 navigator.geolocation.getCurrentPosition(function (position) { 13368 const pos = new GeoPoint(position.coords.latitude, position.coords.longitude); 13369 callback && callback(pos); 13370 }); 13371 } 13372 else { 13373 return false; 13374 } 13375 } 13376 getScale() { 13377 const scale2 = this.containers.map.clientWidth / this.viewBox.width; 13378 return scale2 || 1; 13379 } 13380 getViewBox() { 13381 return this.viewBox; 13382 }
13383 viewBoxSetBySize(width, height) { 13384 this.setSize(width, height); 13385 this._viewBox.update(this.viewBoxGetBySize(width, height)); 13386 this.setViewBox(this._viewBox); 13387 $$A(window).trigger("resize"); 13388 this.setSize(width, height); 13389 this.setZoomLevels(); 13390 return this.viewBox; 13391 } 13392 viewBoxGetBySize(width, height) { 13393 const new_ratio = width / height; 13394 const old_ratio = this.svgDefault.viewBox.width / this.svgDefault.viewBox.height; 13395 const vb = this.svgDefault.viewBox.clone(); 13396 if (new_ratio != old_ratio) { 13397 if (new_ratio > old_ratio) { 13398 vb.width = this.svgDefault.viewBox.height * new_ratio; 13399 vb.x = this.svgDefault.viewBox.x - (vb.width - this.svgDefault.viewBox.width) / 2; 13400 } 13401 else { 13402 vb.height = this.svgDefault.viewBox.width / new_ratio; 13403 vb.y = this.svgDefault.viewBox.y - (vb.height - this.svgDefault.viewBox.height) / 2; 13404 } 13405 } 13406 return vb; 13407 }
13408 viewBoxReset(toInitial) { 13409 if (this.options.googleMaps.on && this.googleMaps.map) { 13410 if (!toInitial) { 13411 this.options.googleMaps.center = null; 13412 this.options.googleMaps.zoom = null; 13413 } 13414 if (!this.options.googleMaps.center || !this.options.googleMaps.zoom) { 13415 const southWest = new google.maps.LatLng(this.geoViewBox.sw.lat, this.geoViewBox.sw.lng); 13416 const northEast = new google.maps.LatLng(this.geoViewBox.ne.lat, this.geoViewBox.ne.lng); 13417 const bounds = new google.maps.LatLngBounds(southWest, northEast); 13418 this.googleMaps.map.fitBounds(bounds, 0); 13419 this.options.googleMaps.center = this.googleMaps.map.getCenter().toJSON(); 13420 this.options.googleMaps.zoom = this.googleMaps.map.getZoom(); 13421 } 13422 else { 13423 this.googleMaps.map.setZoom(this.options.googleMaps.zoom); 13424 this.googleMaps.map.setCenter(this.options.googleMaps.center); 13425 } 13426 } 13427 else { 13428 if (toInitial) { 13429 const v = this._viewBox || this.svgDefault.viewBox; 13430 this.zoomLevel = 0; 13431 this._scale = 1; 13432 this.setViewBox(v); 13433 } 13434 else { 13435 this.setViewBox(); 13436 } 13437 } 13438 return this.viewBox; 13439 } 13440 getGeoViewBox() { 13441 const v = this.viewBox; 13442 const p1 = new SVGPoint(v.x, v.y); 13443 const p2 = new SVGPoint(v.x + v.width, v.y); 13444 const p3 = new SVGPoint(v.x, v.y); 13445 const p4 = new SVGPoint(v.x, v.y + v.height); 13446 const leftLon = this.converter.convertSVGToGeo(p1).lng; 13447 const rightLon = this.converter.convertSVGToGeo(p2).lng; 13448 const topLat = this.converter.convertSVGToGeo(p3).lat; 13449 const bottomLat = this.converter.convertSVGToGeo(p4).lat; 13450 return [leftLon, topLat, rightLon, bottomLat]; 13451 } 13452 setStrokes() { 13453 $$A(this.containers.svg) 13454 .find("path, polygon, circle, ellipse, rect, line, polyline") 13455 .each((index, elem) => { 13456 const width = MapObject.getComputedStyle("stroke-width", elem); 13457 if (width) { 13458 $$A(elem).attr("data-stroke-width", width.replace("px", "")); 13459 } 13460 }); 13461 } 13462 adjustStrokes() { 13463 $$A(this.containers.svg) 13464 .find("path, polygon, circle, ellipse, rect, line, polyline") 13465 .each((index, elem) => { 13466 const width = elem.getAttribute("data-stroke-width"); 13467 if (width) { 13468 $$A(elem).css("stroke-width", Number(width) / this.scale); 13469 } 13470 }); 13471 } 13472 zoomIn(center) { 13473 if (this.canZoom) { 13474 this.isZooming = true; 13475 this.canZoom = false;
13476 setTimeout(() => { 13477 this.isZooming = false; 13478 this.canZoom = true; 13479 }, 700); 13480 this.zoom(1, center); 13481 } 13482 } 13483 zoomOut(center) { 13484 if (this.canZoom) { 13485 this.isZooming = true; 13486 this.canZoom = false; 13487 setTimeout(() => { 13488 this.isZooming = false; 13489 this.canZoom = true; 13490 }, 700); 13491 this.zoom(-1, center); 13492 } 13493 } 13494 zoomTo(mapObjects, zoomToLevel) { 13495 if (mapObjects instanceof Marker || mapObjects instanceof MarkerCluster) { 13496 return this.zoomToMarkerOrCluster(mapObjects, zoomToLevel); 13497 } 13498 else { 13499 const convertedObjects = !Array.isArray(mapObjects) ? [mapObjects] : mapObjects; 13500 const bbox = this.getGroupBBox(convertedObjects); 13501 return this.fitViewBox(bbox, zoomToLevel); 13502 } 13503 } 13504 zoomToMarkerOrCluster(mapObject, zoomToLevel) { 13505 this.zoomLevel = zoomToLevel || 1; 13506 const foundZoomLevel = this.zoomLevels.get(this.zoomLevel); 13507 if (!foundZoomLevel) { 13508 return false; 13509 } 13510 const vb = foundZoomLevel.viewBox; 13511 if (this.canZoom) { 13512 this.isZooming = true; 13513 this.canZoom = false;
13514 setTimeout(() => { 13515 this.isZooming = false; 13516 this.canZoom = true; 13517 }, 700); 13518 const vbNew = new ViewBox(mapObject.svgPoint.x - vb.width / 2, mapObject.svgPoint.y - vb.height / 2, vb.width, vb.height); 13519 this.setViewBox(vbNew); 13520 this._scale = foundZoomLevel._scale; 13521 return true; 13522 } 13523 return false; 13524 } 13525 getGroupBBox(mapObjects) { 13526 let _bbox; 13527 const xmax = []; 13528 const ymax = []; 13529 const xmin = []; 13530 const ymin = []; 13531 for (let i = 0; i < mapObjects.length; i++) { 13532 _bbox = mapObjects[i].getBBox(); 13533 xmin.push(_bbox.x); 13534 ymin.push(_bbox.y); 13535 const _w = _bbox.x + _bbox.width; 13536 const _h = _bbox.y + _bbox.height; 13537 xmax.push(_w); 13538 ymax.push(_h); 13539 } 13540 const _xmin = Math.min(...xmin); 13541 const _ymin = Math.min(...ymin); 13542 const width = Math.max(...xmax) - _xmin; 13543 const height = Math.max(...ymax) - _ymin; 13544 let padding = 10; 13545 const point1 = new ScreenPoint(padding, 0); 13546 const point2 = new ScreenPoint(0, 0); 13547 padding = 13548 this.converter.convertPixelToSVG(point1).x - this.converter.convertPixelToSVG(point2).x; 13549 return new ViewBox(_xmin - padding, _ymin - padding, width + padding * 2, height + padding * 2); 13550 } 13551 fitViewBox(fitViewBox, forceZoomLevel) { 13552 let viewBoxPrev; 13553 let foundZoomLevelNumber = 0; 13554 let foundZoomLevel; 13555 let newViewBox;
13556 this.zoomLevels.forEach((zoomLevel) => { 13557 if (viewBoxPrev && viewBoxPrev.x !== undefined) { 13558 if (fitViewBox.fitsInViewBox(viewBoxPrev) && 13559 zoomLevel.viewBox.fitsInViewBox(fitViewBox, true)) { 13560 foundZoomLevelNumber = forceZoomLevel ? forceZoomLevel : zoomLevel.zoomLevel; 13561 foundZoomLevel = this.zoomLevels.get(foundZoomLevelNumber); 13562 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); 13563 } 13564 } 13565 viewBoxPrev = zoomLevel && zoomLevel.viewBox; 13566 }); 13567 if (foundZoomLevel) { 13568 if (this.canZoom) { 13569 this.isZooming = true; 13570 this.canZoom = false; 13571 setTimeout(() => { 13572 this.isZooming = false; 13573 this.canZoom = true; 13574 }, 700); 13575 this.zoomLevel = foundZoomLevelNumber; 13576 this._scale = foundZoomLevel._scale; 13577 this.setViewBox(newViewBox); 13578 return true; 13579 } 13580 } 13581 else { 13582 return false; 13583 } 13584 } 13585 zoomToRegion(region, zoomToLevel) { 13586 this.fitViewBox(region.getBBox(), zoomToLevel); 13587 return true; 13588 } 13589 centerOn(region, yShift) { 13590 if (this.options.googleMaps.on) { 13591 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13592 $$A(this.containers.map).addClass("scrolling"); 13593 const latLng = region.getCenterLatLng(yShift); 13594 this.googleMaps.map.panTo(latLng); 13595 setTimeout(() => { 13596 $$A(this.containers.map).removeClass("scrolling"); 13597 }, 100); 13598 } 13599 else { 13600 yShift = yShift ? (yShift + 12) / this.getScale() : 0; 13601 const bbox = region.getBBox(); 13602 const vb = this.viewBox; 13603 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); 13604 this.setViewBox(newViewBox); 13605 } 13606 } 13607 zoom(delta, center) { 13608 let newViewBox = new ViewBox(0, 0, 0, 0); 13609 const d = delta > 0 ? 1 : -1; 13610 if (!this.zoomLevels.get(this.zoomLevel + d)) 13611 return;
13612 const newZoomLevel = this.zoomLevel + d; 13613 const zoomIn = d > 0; 13614 const zoomOut = d < 0; 13615 const zoomRange = this.getZoomRange(); 13616 const isInZoomRange = this.zoomLevel >= zoomRange.min && this.zoomLevel <= zoomRange.max; 13617 const goingOutOfZoomRange = isInZoomRange && (newZoomLevel > zoomRange.max || newZoomLevel < zoomRange.min); 13618 const outOfRangeAndMovingAway = !isInZoomRange && 13619 ((zoomIn && newZoomLevel > zoomRange.max) || (zoomOut && newZoomLevel < zoomRange.min)); 13620 if (goingOutOfZoomRange || outOfRangeAndMovingAway) { 13621 return; 13622 } 13623 this.zoomLevel = newZoomLevel; 13624 const z = this.zoomLevels.get(this.zoomLevel); 13625 this._scale = z._scale; 13626 newViewBox = z.viewBox; 13627 let shift = []; 13628 if (center) { 13629 const koef = zoomIn ? 0.5 : -1; 13630 newViewBox.x = this.viewBox.x + (center.x - this.viewBox.x) * koef; 13631 newViewBox.y = this.viewBox.y + (center.y - this.viewBox.y) * koef; 13632 } 13633 else { 13634 shift = [ 13635 (this.viewBox.width - newViewBox.width) / 2, 13636 (this.viewBox.height - newViewBox.height) / 2, 13637 ]; 13638 newViewBox.x = this.viewBox.x + shift[0]; 13639 newViewBox.y = this.viewBox.y + shift[1]; 13640 } 13641 this.shiftViewBoxToScrollBoundaries(newViewBox); 13642 this.setViewBox(newViewBox); 13643 } 13644 toggleSvgLayerOnZoom() { 13645 if (this.options.googleMaps.on && 13646 this.googleMaps.map && 13647 this.options.zoom.hideSvg && 13648 this.googleMaps.map.getZoom() >= this.options.zoom.hideSvgZoomLevel) { 13649 if (!$$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13650 $$A(this.containers.svg).animate({ opacity: 0 }, 400, "linear", () => { 13651 $$A(this.containers.svg).addClass("mapsvg-invisible"); 13652 }); 13653 } 13654 } 13655 else { 13656 if ($$A(this.containers.svg).hasClass("mapsvg-invisible")) { 13657 $$A(this.containers.svg).animate({ opacity: 1 }, 400, "linear", () => { 13658 $$A(this.containers.svg).removeClass("mapsvg-invisible"); 13659 }); 13660 } 13661 } 13662 } 13663 shiftViewBoxToScrollBoundaries(newViewBox) { 13664 if (this.options.scroll.limit) { 13665 if (newViewBox.x < this.svgDefault.viewBox.x) 13666 newViewBox.x = this.svgDefault.viewBox.x; 13667 else if (newViewBox.x + newViewBox.width > 13668 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13669 newViewBox.x = 13670 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - newViewBox.width; 13671 if (newViewBox.y < this.svgDefault.viewBox.y) 13672 newViewBox.y = this.svgDefault.viewBox.y; 13673 else if (newViewBox.y + newViewBox.height > 13674 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13675 newViewBox.y = 13676 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height - newViewBox.height; 13677 } 13678 return newViewBox; 13679 } 13680 markerDelete(marker) { 13681 if (this.editingMarker && this.editingMarker.id == marker.id) { 13682 this.unsetEditingMarker(); 13683 } 13684 if (this.markers.findById(marker.id)) { 13685 this.markers.delete(marker.id); 13686 } 13687 marker.delete(); 13688 marker = null; 13689 if (this.markers.length === 0) 13690 this.options.markerLastID = 0; 13691 } 13692 markersClusterAdd(markersCluster) { 13693 this.layers.markers.append(markersCluster.elem); 13694 this.markersClusters.push(markersCluster); 13695 markersCluster.adjustScreenPosition(); 13696 } 13697 markerAdd(marker) { 13698 $$A(marker.element).hide(); 13699 marker.adjustScreenPosition(); 13700 this.layers.markers.append(marker.element); 13701 this.markers.push(marker); 13702 marker.mapped = true; 13703 setTimeout(function () { 13704 $$A(marker.element).show(); 13705 }, 100); 13706 } 13707 markerRemove(marker) { 13708 if (this.editingMarker && this.editingMarker.id == marker.id) { 13709 this.editingMarker = null; 13710 delete this.editingMarker; 13711 } 13712 if (this.markers.findById(marker.id)) { 13713 this.markers.findById(marker.id).element.remove(); 13714 this.markers.delete(marker.id); 13715 marker = null; 13716 } 13717 if (this.markers.length === 0) 13718 this.options.markerLastID = 0; 13719 } 13720 markerId() { 13721 this.options.markerLastID = this.options.markerLastID + 1; 13722 const id = "marker_" + this.options.markerLastID; 13723 if (this.getMarker(id)) 13724 return this.markerId(); 13725 else 13726 return id; 13727 } 13728 movingItemsAdjustScreenPosition() { 13729 this.markersAdjustScreenPosition(); 13730 this.popoverAdjustScreenPosition(); 13731 this.bubblesRegionsAdjustScreenPosition(); 13732 this.labelsRegionsAdjustScreenPosition(); 13733 } 13734 movingItemsMoveScreenPositionBy(deltaX, deltaY) { 13735 this.markersMoveScreenPositionBy(deltaX, deltaY); 13736 this.popoverMoveScreenPositionBy(deltaX, deltaY); 13737 this.bubblesRegionsMoveScreenPositionBy(deltaX, deltaY); 13738 this.labelsRegionsMoveScreenPositionBy(deltaX, deltaY); 13739 } 13740 labelsRegionsAdjustScreenPosition() { 13741 if ($$A(this.containers.map).is(":visible")) { 13742 this.regions.forEach(function (region) { 13743 region.adjustLabelScreenPosition(); 13744 }); 13745 } 13746 } 13747 bubblesRegionsAdjustScreenPosition() { 13748 if ($$A(this.containers.map).is(":visible")) { 13749 this.regions.forEach(function (region) { 13750 region.adjustBubbleScreenPosition(); 13751 }); 13752 } 13753 } 13754 labelsRegionsMoveScreenPositionBy(deltaX, deltaY) { 13755 if ($$A(this.containers.map).is(":visible")) { 13756 this.regions.forEach(function (region) { 13757 region.moveLabelScreenPositionBy(deltaX, deltaY); 13758 }); 13759 } 13760 } 13761 bubblesRegionsMoveScreenPositionBy(deltaX, deltaY) { 13762 if ($$A(this.containers.map).is(":visible")) { 13763 this.regions.forEach((region) => { 13764 region.moveBubbleScreenPositionBy(deltaX, deltaY); 13765 }); 13766 } 13767 } 13768 markersAdjustScreenPosition() {
13769 this.markers.forEach((marker) => { 13770 marker.adjustScreenPosition(); 13771 }); 13772 this.markersClusters.forEach((cluster) => { 13773 cluster.adjustScreenPosition(); 13774 }); 13775 if (this.userLocationMarker) { 13776 this.userLocationMarker.adjustScreenPosition(); 13777 } 13778 } 13779 markersMoveScreenPositionBy(deltaX, deltaY) { 13780 this.markers.forEach((marker) => { 13781 marker.moveSrceenPositionBy(deltaX, deltaY); 13782 }); 13783 this.markersClusters.forEach((cluster) => { 13784 cluster.moveSrceenPositionBy(deltaX, deltaY); 13785 }); 13786 if (this.userLocationMarker) { 13787 this.userLocationMarker.moveSrceenPositionBy(deltaX, deltaY); 13788 } 13789 } 13790 setEditingMarker(marker) { 13791 this.editingMarker = marker; 13792 if (!this.editingMarker.mapped) { 13793 this.editingMarker.needToRemove = true; 13794 this.markerAdd(this.editingMarker); 13795 } 13796 } 13797 unsetEditingMarker() { 13798 if (this.editingMarker && this.editingMarker.needToRemove) { 13799 this.markerRemove(this.editingMarker); 13800 } 13801 this.editingMarker = null; 13802 } 13803 getEditingMarker() { 13804 return this.editingMarker; 13805 } 13806 scrollStart(e, mapsvg) { 13807 if ($$A(e.target).hasClass("mapsvg-btn-map") || 13808 $$A(e.target).closest(".mapsvg-choropleth").length) 13809 return; 13810 if (this.editMarkers.on && $$A(e.target).hasClass("mapsvg-marker")) 13811 return; 13812 e.preventDefault(); 13813 $$A(this.containers.map).addClass("no-transitions"); 13814 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13815 ? e.originalEvent.touches[0] 13816 : e; 13817 this.scrollStarted = true; 13818 this.scroll = { 13819 tx: this.scroll.tx || 0, 13820 ty: this.scroll.ty || 0, 13821 vxi: this.viewBox.x, 13822 vyi: this.viewBox.y, 13823 x: ce.clientX, 13824 y: ce.clientY, 13825 dx: 0, 13826 dy: 0, 13827 vx: 0, 13828 vy: 0, 13829 gx: ce.clientX, 13830 gy: ce.clientY, 13831 touchScrollStart: 0, 13832 }; 13833 if (e.type.indexOf("mouse") === 0) { 13834 $$A(document).on("mousemove.scroll.mapsvg", (e) => { 13835 this.scrollMove(e); 13836 }); 13837 if (this.options.scroll.spacebar) { 13838 $$A(document).on("keyup.scroll.mapsvg", (e) => { 13839 if (e.keyCode == 32) { 13840 this.scrollEnd(e, mapsvg); 13841 } 13842 }); 13843 } 13844 else { 13845 $$A(document).on("mouseup.scroll.mapsvg", (e) => { 13846 this.scrollEnd(e, mapsvg); 13847 }); 13848 } 13849 } 13850 } 13851 scrollMove(e) { 13852 e.preventDefault(); 13853 if (!this.isScrolling) { 13854 this.isScrolling = true; 13855 $$A(this.containers.map).addClass("scrolling"); 13856 } 13857 const ce = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0] 13858 ? e.originalEvent.touches[0] 13859 : e; 13860 this.panBy(this.scroll.gx - ce.clientX, this.scroll.gy - ce.clientY); 13861 this.scroll.gx = ce.clientX; 13862 this.scroll.gy = ce.clientY; 13863 this.scroll.dx = this.scroll.x - ce.clientX; 13864 this.scroll.dy = this.scroll.y - ce.clientY; 13865 let vx = this.scroll.vxi + this.scroll.dx / this.scale; 13866 let vy = this.scroll.vyi + this.scroll.dy / this.scale; 13867 if (this.options.scroll.limit) { 13868 if (vx < this.svgDefault.viewBox.x) 13869 vx = this.svgDefault.viewBox.x; 13870 else if (this.viewBox.width + vx > 13871 this.svgDefault.viewBox.x + this.svgDefault.viewBox.width) 13872 vx = this.svgDefault.viewBox.x + this.svgDefault.viewBox.width - this.viewBox.width; 13873 if (vy < this.svgDefault.viewBox.y) 13874 vy = this.svgDefault.viewBox.y; 13875 else if (this.viewBox.height + vy > 13876 this.svgDefault.viewBox.y + this.svgDefault.viewBox.height) 13877 vy = 13878 this.svgDefault.viewBox.y + 13879 this.svgDefault.viewBox.height - 13880 this.viewBox.height; 13881 } 13882 this.scroll.vx = vx; 13883 this.scroll.vy = vy; 13884 } 13885 scrollEnd(e, mapsvg, noClick) { 13886 setTimeout(() => { 13887 this.enableAnimation(); 13888 this.scrollStarted = false;
13889 this.isScrolling = false; 13890 }, 100); 13891 if (this.googleMaps && this.googleMaps.overlay) { 13892 this.googleMaps.overlay.draw(); 13893 } 13894 $$A(this.containers.map).removeClass("scrolling"); 13895 $$A(document).off("keyup.scroll.mapsvg"); 13896 $$A(document).off("mousemove.scroll.mapsvg"); 13897 $$A(document).off("mouseup.scroll.mapsvg"); 13898 if (noClick !== true && Math.abs(this.scroll.dx) < 5 && Math.abs(this.scroll.dy) < 5) { 13899 if (this.editMarkers.on) 13900 this.clickAddsMarker && this.markerAddClickHandler(e); 13901 else if (this.objectClickedBeforeScroll) 13902 if (this.objectClickedBeforeScroll instanceof Marker) { 13903 this.markerClickHandler(e, this.objectClickedBeforeScroll); 13904 } 13905 else if (this.objectClickedBeforeScroll instanceof Region) { 13906 this.regionClickHandler(e, this.objectClickedBeforeScroll); 13907 } 13908 else if (this.objectClickedBeforeScroll instanceof MarkerCluster) { 13909 this.markerClusterClickHandler(e, this.objectClickedBeforeScroll); 13910 } 13911 } 13912 this.viewBox.x = this.scroll.vx || this.viewBox.x; 13913 this.viewBox.y = this.scroll.vy || this.viewBox.y; 13914 } 13915 setViewBoxByGoogleMapsOverlay() { 13916 const bounds = this.googleMaps.overlay.getPixelBounds(); 13917 const scale = (bounds.ne.x - bounds.sw.x) / this.svgDefault.viewBox.width; 13918 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); 13919 this.setViewBox(vb, false); 13920 } 13921 panBy(x, y) { 13922 let tx = this.scroll.tx - x; 13923 let ty = this.scroll.ty - y; 13924 const scrolled = { x: true, y: true }; 13925 if (this.options.scroll.limit) { 13926 const svg = $$A(this.containers.svg)[0].getBoundingClientRect(); 13927 const bounds = $$A(this.containers.map)[0].getBoundingClientRect(); 13928 if ((svg.left - x > bounds.left && x < 0) || (svg.right - x < bounds.right && x > 0)) { 13929 tx = this.scroll.tx; 13930 scrolled.x = false; 13931 } 13932 if ((svg.top - y > bounds.top && y < 0) || (svg.bottom - y < bounds.bottom && y > 0)) { 13933 ty = this.scroll.ty; 13934 scrolled.y = false; 13935 } 13936 } 13937 $$A(this.containers.scrollpane).css({ 13938 transform: "translate(" + tx + "px," + ty + "px)", 13939 }); 13940 this.scroll.tx = tx; 13941 this.scroll.ty = ty; 13942 if (scrolled.x || scrolled.y) { 13943 const moveX = scrolled.x ? x : 0; 13944 const moveY = scrolled.y ? y : 0; 13945 this.movingItemsMoveScreenPositionBy(moveX, moveY); 13946 if (this.googleMaps.map) { 13947 let point = this.googleMaps.map.getCenter(); 13948 const projection = this.googleMaps.overlay.getProjection(); 13949 const pixelpoint = projection.fromLatLngToDivPixel(point); 13950 pixelpoint.x += moveX; 13951 pixelpoint.y += moveY; 13952 point = projection.fromDivPixelToLatLng(pixelpoint); 13953 this.googleMaps.map.setCenter(point); 13954 } 13955 } 13956 return scrolled; 13957 } 13958 setObjectClickedBeforeScroll(object) { 13959 this.objectClickedBeforeScroll = object; 13960 } 13961 touchStart(_e, mapsvg) { 13962 _e.preventDefault(); 13963 if (this.scrollStarted) { 13964 this.scrollEnd(_e, mapsvg, true); 13965 } 13966 const e = _e.originalEvent; 13967 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13968 this.touchZoomStart = true; 13969 this.scaleDistStart = Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY); 13970 } 13971 else if (e.touches && e.touches.length == 1) { 13972 this.scrollStart(_e, mapsvg); 13973 } 13974 $$A(document) 13975 .on("touchmove.scroll.mapsvg", (e) => { 13976 e.preventDefault(); 13977 this.touchMove(e, this); 13978 }) 13979 .on("touchend.scroll.mapsvg", (e) => { 13980 e.preventDefault(); 13981 this.touchEnd(e, this); 13982 }); 13983 } 13984 touchMove(_e, mapsvg) { 13985 _e.preventDefault(); 13986 const e = _e.originalEvent; 13987 if (this.options.zoom.fingers && e.touches && e.touches.length == 2) { 13988 if (!MapSVG.ios) { 13989 e.scale = 13990 Math.hypot(e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageY - e.touches[1].pageY) / this.scaleDistStart; 13991 } 13992 if (e.scale != 1 && this.canZoom) { 13993 const d = e.scale > 1 ? 1 : -1; 13994 const cx = e.touches[0].pageX >= e.touches[1].pageX 13995 ? e.touches[0].pageX - 13996 (e.touches[0].pageX - e.touches[1].pageX) / 2 - 13997 $$A(this.containers.map).offset().left 13998 : e.touches[1].pageX - 13999 (e.touches[1].pageX - e.touches[0].pageX) / 2 - 14000 $$A(this.containers.map).offset().left; 14001 const cy = e.touches[0].pageY >= e.touches[1].pageY 14002 ? e.touches[0].pageY - 14003 (e.touches[0].pageY - e.touches[1].pageY) - 14004 $$A(this.containers.map).offset().top 14005 : e.touches[1].pageY - 14006 (e.touches[1].pageY - e.touches[0].pageY) - 14007 $$A(this.containers.map).offset().top; 14008 const center = this.converter.convertPixelToSVG(new ScreenPoint(cx, cy)); 14009 if (d > 0) 14010 this.zoomIn(center); 14011 else 14012 this.zoomOut(center); 14013 } 14014 } 14015 else if (e.touches && e.touches.length == 1) { 14016 this.scrollMove(_e); 14017 } 14018 } 14019 touchEnd(_e, mapsvg) { 14020 _e.preventDefault(); 14021 const e = _e.originalEvent; 14022 if (this.touchZoomStart) { 14023 this.touchZoomStart = false;
14024 } 14025 else if (this.scrollStarted) { 14026 this.scrollEnd(_e, mapsvg); 14027 } 14028 $$A(document).off("touchmove.scroll.mapsvg"); 14029 $$A(document).off("touchend.scroll.mapsvg"); 14030 } 14031 getSelected() { 14032 return this.selected_id; 14033 } 14034 selectRegion(id, skipDirectorySelection) { 14035 let region; 14036 if (typeof id == "string") { 14037 region = this.getRegion(id); 14038 } 14039 else { 14040 region = id; 14041 } 14042 if (!region) 14043 return; 14044 let ids; 14045 if (this.options.multiSelect && !this.editRegions.on) { 14046 if (region.selected) { 14047 this.deselectRegion(region); 14048 if (!skipDirectorySelection && this.options.menu.on) { 14049 if (this.options.menu.source == "database") { 14050 if (region.objects && region.objects.length) { 14051 ids = region.objects.map((obj) => { 14052 return obj.id.toString(); 14053 }); 14054 } 14055 } 14056 else { 14057 ids = [region.id]; 14058 } 14059 this.controllers.directory.deselectItems(); 14060 } 14061 return; 14062 } 14063 } 14064 else if (this.selected_id.length > 0) { 14065 this.deselectAllRegions(); 14066 if (!skipDirectorySelection && this.options.menu.on) { 14067 if (this.options.menu.source == "database") { 14068 if (region.objects && region.objects.length) { 14069 ids = region.objects.map((obj) => { 14070 return obj.id.toString(); 14071 }); 14072 } 14073 } 14074 else { 14075 ids = [region.id]; 14076 } 14077 this.controllers.directory.deselectItems(); 14078 } 14079 } 14080 this.selected_id.push(region.id); 14081 region.select(); 14082 const skip = this.options.actions.region.click.filterDirectory; 14083 if (!skip && 14084 !skipDirectorySelection && 14085 this.options.menu.on && 14086 this.controllers && 14087 this.controllers.directory) { 14088 if (this.options.menu.source == "database") { 14089 if (region.objects && region.objects.length) { 14090 ids = region.objects.map((obj) => { 14091 return obj.id.toString(); 14092 }); 14093 } 14094 else { 14095 ids = [region.id]; 14096 } 14097 } 14098 else { 14099 ids = [region.id]; 14100 } 14101 this.controllers.directory.selectItems(ids); 14102 } 14103 if (this.options.actions.region.click.addIdToUrl && 14104 !this.options.actions.region.click.showAnotherMap) { 14105 window.location.hash = "/m/" + region.id; 14106 } 14107 } 14108 deselectAllRegions() { 14109 $$A.each(this.selected_id, (index, id) => { 14110 this.deselectRegion(this.getRegion(id)); 14111 }); 14112 } 14113 deselectRegion(region) { 14114 if (!region) 14115 region = this.getRegion(this.selected_id[0]); 14116 if (region) { 14117 region.deselect(); 14118 const i = $$A.inArray(region.id, this.selected_id); 14119 this.selected_id.splice(i, 1); 14120 } 14121 if (this.options.actions.region.click.addIdToUrl) { 14122 if (window.location.hash.indexOf(region.id) !== -1) { 14123 history.replaceState(null, null, " "); 14124 } 14125 } 14126 } 14127 highlightRegions(regions) { 14128 regions.forEach((region) => { 14129 if (region && !region.selected && !region.disabled) { 14130 this.highlightedRegions.push(region); 14131 region.highlight(); 14132 } 14133 }); 14134 } 14135 unhighlightRegions() { 14136 this.highlightedRegions.forEach((region) => { 14137 if (region && !region.selected && !region.disabled) 14138 region.unhighlight(); 14139 }); 14140 this.highlightedRegions = []; 14141 } 14142 selectMarker(marker) { 14143 if (!(marker instanceof Marker)) 14144 return; 14145 this.deselectAllMarkers(); 14146 marker.select(); 14147 this.selected_marker = marker; 14148 $$A(this.layers.markers).addClass("mapsvg-with-marker-active"); 14149 if (this.options.menu.on && this.options.menu.source == "database") { 14150 this.controllers.directory.deselectItems(); 14151 this.controllers.directory.selectItems(marker.object.id); 14152 } 14153 } 14154 deselectAllMarkers() { 14155 this.selected_marker && this.selected_marker.deselect(); 14156 $$A(this.layers.markers).removeClass("mapsvg-with-marker-active"); 14157 } 14158 deselectMarker(marker) { 14159 if (marker) { 14160 marker.deselect(); 14161 } 14162 } 14163 highlightMarker(marker) { 14164 $$A(this.layers.markers).addClass("mapsvg-with-marker-hover"); 14165 marker.highlight(); 14166 this.highlighted_marker = marker; 14167 } 14168 unhighlightMarker() { 14169 $$A(this.layers.markers).removeClass("mapsvg-with-marker-hover"); 14170 this.highlighted_marker && this.highlighted_marker.unhighlight(); 14171 } 14172 convertMouseToSVG(e) { 14173 const mc = MapSVG.mouseCoords(e); 14174 const x = mc.x - $$A(this.containers.map).offset().left; 14175 const y = mc.y - $$A(this.containers.map).offset().top; 14176 const screenPoint = new ScreenPoint(x, y); 14177 return this.converter.convertPixelToSVG(screenPoint); 14178 } 14179 pickChoroplethColor(choroplethValue) { 14180 const w = (choroplethValue - this.options.choropleth.coloring.gradient.values.min) / 14181 this.options.choropleth.coloring.gradient.values.maxAdjusted; 14182 const rgba = { 14183 r: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.r * w + 14184 this.options.choropleth.coloring.gradient.colors.lowRGB.r), 14185 g: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.g * w + 14186 this.options.choropleth.coloring.gradient.colors.lowRGB.g), 14187 b: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.b * w + 14188 this.options.choropleth.coloring.gradient.colors.lowRGB.b), 14189 a: Math.round(this.options.choropleth.coloring.gradient.colors.diffRGB.a * w + 14190 this.options.choropleth.coloring.gradient.colors.lowRGB.a), 14191 }; 14192 return rgba; 14193 } 14194 isRegionDisabled(id, svgfill) { 14195 if (this.options.regions[id] && (this.options.regions[id].disabled || svgfill == "none")) { 14196 return true; 14197 } 14198 else if ((this.options.regions[id] == undefined || 14199 MapSVG.parseBoolean(this.options.regions[id].disabled)) && 14200 (this.options.disableAll || svgfill == "none" || id == "labels" || id == "Labels")) { 14201 return true; 14202 } 14203 else { 14204 return false;
14205 } 14206 } 14207 loadMap(id, container) { 14208 if (!(container instanceof HTMLElement)) { 14209 console.error("Can't load a new map: container was not provided."); 14210 return; 14211 } 14212 const previousMapsIds = [...this.options.previousMapsIds]; 14213 const currentMapId = this.id; 14214 if (previousMapsIds[previousMapsIds.length - 1] !== id) { 14215 previousMapsIds.push(currentMapId); 14216 } 14217 else { 14218 previousMapsIds.pop(); 14219 } 14220 let showPreviousMapButton; 14221 if (typeof this.options.actions.region.click.showAnotherMapContainerId !== "undefined" && 14222 this.options.actions.region.click.showAnotherMapContainerId !== "") { 14223 showPreviousMapButton = false; 14224 } 14225 else { 14226 showPreviousMapButton = this.options.controls.previousMap; 14227 } 14228 const mapsRepo = new MapsRepository(); 14229 const sameContainer = container === this.containers.map; 14230 mapsRepo.findById(id).done((map) => { 14231 sameContainer && this.destroy(); 14232 const newMap = new MapSVGMap(container.getAttribute("id"), map); 14233 newMap.events.on("afterLoad", function () { 14234 this.options.previousMapsIds = previousMapsIds; 14235 this.options.controls.previousMap = showPreviousMapButton; 14236 this.setControls(this.options.controls); 14237 }); 14238 }); 14239 } 14240 loadPreviousMap() { 14241 const previousMapId = this.options.previousMapsIds[this.options.previousMapsIds.length - 1]; 14242 const container = document.getElementById(this.containerId); 14243 this.loadMap(previousMapId, container); 14244 } 14245 markerClusterClickHandler(e, markerCluster) { 14246 this.objectClickedBeforeScroll = null; 14247 if (this.eventsPreventList["click"]) 14248 return; 14249 this.zoomTo(markerCluster.markers); 14250 return; 14251 } 14252 regionClickHandler(e, region) { 14253 this.objectClickedBeforeScroll = null; 14254 if (this.eventsPreventList["click"]) 14255 return; 14256 this.selectRegion(region.id); 14257 if (this.editRegions.on) { 14258 this.regionEditHandler.call(region); 14259 return; 14260 } 14261 const actions = this.options.actions; 14262 if (actions.region.click.zoom) { 14263 this.zoomTo(region, parseInt(actions.region.click.zoomToLevel)); 14264 } 14265 if (actions.region.click.filterDirectory) { 14266 const query = new Query({ 14267 filters: { 14268 regions: { 14269 table_name: this.regionsRepository.getSchema().name, 14270 region_ids: [region.id], 14271 }, 14272 }, 14273 }); 14274 this.objectsRepository.query.resetFilters(); 14275 this.setFilterOut(); 14276 this.objectsRepository.find(query).done(() => { 14277 if (this.controllers.popover) { 14278 this.controllers.popover.redraw(region.forTemplate()); 14279 } 14280 if (this.controllers.detailsView) { 14281 this.controllers.detailsView.redraw(region.forTemplate()); 14282 } 14283 }); 14284 this.updateFiltersState(); 14285 }
14286 if (actions.region.click.showDetails) { 14287 this.loadDetailsView(region); 14288 } 14289 if (actions.region.click.showPopover) { 14290 if (actions.region.click.zoom) { 14291 setTimeout(() => { 14292 this.showPopover(region); 14293 }, 400); 14294 } 14295 else { 14296 this.showPopover(region); 14297 } 14298 } 14299 else if (e && e.type.indexOf("touch") !== -1 && actions.region.touch.showPopover) { 14300 if (actions.region.click.zoom) { 14301 setTimeout(() => { 14302 this.showPopover(region); 14303 }, 400); 14304 } 14305 else { 14306 this.showPopover(region); 14307 } 14308 } 14309 if (actions.region.click.goToLink) { 14310 const linkParts = actions.region.click.linkField.split("."); 14311 let url; 14312 if (linkParts.length > 1) { 14313 const obj = linkParts.shift(); 14314 const attr = "." + linkParts.join("."); 14315 if (obj == "Region") { 14316 if (region.data) { 14317 try { 14318 url = eval("region.data" + attr); 14319 } 14320 catch (err) { 14321 console.log("No such field as region.data" + attr); 14322 } 14323 } 14324 } 14325 else { 14326 if (region.objects && region.objects[0]) { 14327 try { 14328 url = eval("region.objects[0]" + attr); 14329 } 14330 catch (err) { 14331 console.log("No such field as region.objects[0]" + attr); 14332 } 14333 } 14334 } 14335 if (url && !this.disableLinks) { 14336 if (this.editMode) { 14337 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14338 return; 14339 } 14340 if (actions.region.click.newTab) { 14341 const win = window.open(url, "_blank"); 14342 win.focus(); 14343 } 14344 else { 14345 window.location.href = url; 14346 } 14347 } 14348 } 14349 } 14350 if (actions.region.click.showAnotherMap) { 14351 if (this.editMode) { 14352 alert('"Show another map" action is disabled in the preview'); 14353 return; 14354 } 14355 const linkParts = actions.region.click.showAnotherMapField.split("."); 14356 if (linkParts.length > 1) { 14357 const obj = linkParts.shift(); 14358 const attr = "." + linkParts.join("."); 14359 let map_id; 14360 if (obj == "Region") { 14361 if (region.data) 14362 map_id = eval("region.data" + attr); 14363 } 14364 else { 14365 if (region.objects && region.objects[0]) 14366 map_id = eval("region.objects[0]" + attr); 14367 } 14368 if (map_id) { 14369 const container = actions.region.click.showAnotherMapContainerId 14370 ? $$A("#" + actions.region.click.showAnotherMapContainerId)[0] 14371 : $$A(this.containers.map)[0]; 14372 this.loadMap(map_id, container); 14373 } 14374 } 14375 } 14376 this.events.trigger("click.region", region, [e, region, this]); 14377 } 14378 markerClickHandler(e, marker) { 14379 this.objectClickedBeforeScroll = null; 14380 if (this.eventsPreventList["click"]) 14381 return; 14382 const actions = this.options.actions; 14383 this.selectMarker(marker); 14384 const passingObject = marker.object; 14385 if (actions.marker.click.zoom) { 14386 this.zoomTo(marker, parseInt(actions.marker.click.zoomToLevel)); 14387 } 14388 if (actions.marker.click.filterDirectory) { 14389 const query = new Query({ filters: { id: marker.object.id } }); 14390 this.objectsRepository.find(query); 14391 this.updateFiltersState(); 14392 }
14393 if (actions.marker.click.showDetails) 14394 this.loadDetailsView(passingObject); 14395 if (actions.marker.click.showPopover) { 14396 if (actions.marker.click.zoom) { 14397 setTimeout(() => { 14398 this.showPopover(passingObject); 14399 }, 500); 14400 } 14401 else { 14402 this.showPopover(passingObject); 14403 } 14404 } 14405 else if (e && e.type.indexOf("touch") !== -1 && actions.marker.touch.showPopover) { 14406 if (actions.marker.click.zoom) { 14407 setTimeout(() => { 14408 this.showPopover(passingObject); 14409 }, 500); 14410 } 14411 else { 14412 this.showPopover(passingObject); 14413 } 14414 } 14415 if (actions.marker.click.goToLink) { 14416 const linkParts = actions.marker.click.linkField.split("."); 14417 let url; 14418 if (linkParts.length > 1) { 14419 const obj = linkParts.shift(); 14420 const attr = "." + linkParts.join("."); 14421 try { 14422 url = eval("passingObject" + attr); 14423 } 14424 catch (err) { 14425 console.log("MapSVG: No such field as passingObject" + attr); 14426 } 14427 if (url && !this.disableLinks) 14428 if (this.editMode) { 14429 alert("Redirect: " + url + "\nLinks are disabled in the preview."); 14430 return; 14431 } 14432 if (actions.marker.click.newTab) { 14433 const win = window.open(url, "_blank"); 14434 win.focus(); 14435 } 14436 else { 14437 window.location.href = url; 14438 } 14439 } 14440 } 14441 this.events.trigger("click.marker", marker, [e, marker, this]); 14442 } 14443 fileExists(url) { 14444 if (url.substr(0, 4) == "data") 14445 return true; 14446 const http = new XMLHttpRequest(); 14447 http.open("HEAD", url, false); 14448 http.send(); 14449 return http.status != 404; 14450 } 14451 hideMarkers() { 14452 this.markers.forEach(function (marker) { 14453 marker.hide(); 14454 }); 14455 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14456 } 14457 hideMarkersExceptOne(id) { 14458 this.markers.forEach(function (marker) { 14459 if (typeof id === "undefined" || (marker.object && id != marker.object.id)) { 14460 marker.hide(); 14461 } 14462 }); 14463 $$A(this.containers.wrap).addClass("mapsvg-edit-marker-mode"); 14464 } 14465 showMarkers() { 14466 this.markers.forEach(function (m) { 14467 m.show(); 14468 }); 14469 this.deselectAllMarkers(); 14470 $$A(this.containers.wrap).removeClass("mapsvg-edit-marker-mode"); 14471 } 14472 markerAddClickHandler(e) { 14473 if ($$A(e.target).hasClass("mapsvg-marker")) 14474 return; 14475 const svgPoint = this.getSvgPointAtClick(e); 14476 const geoPoint = this.isGeo() ? this.converter.convertSVGToGeo(svgPoint) : null; 14477 if (!$$A.isNumeric(svgPoint.x) || !$$A.isNumeric(svgPoint.y)) 14478 return; 14479 if (this.editingMarker) { 14480 if (geoPoint) { 14481 this.editingMarker.location.setGeoPoint(geoPoint); 14482 } 14483 else { 14484 this.editingMarker.location.setSvgPoint(svgPoint); 14485 } 14486 return; 14487 } 14488 const location = new Location({ 14489 svgPoint: svgPoint, 14490 geoPoint: geoPoint, 14491 img: this.options.defaultMarkerImage, 14492 }); 14493 const marker = new Marker({ 14494 location: location, 14495 mapsvg: this, 14496 }); 14497 this.markerAdd(marker); 14498 this.markerEditHandler && this.markerEditHandler.call(location, location); 14499 } 14500 getSvgPointAtClick(e) { 14501 const mc = MapSVG.mouseCoords(e); 14502 const x = mc.x - $$A(this.containers.map).offset().left; 14503 const y = mc.y - $$A(this.containers.map).offset().top; 14504 const screenPoint = new ScreenPoint(x, y); 14505 return this.converter.convertPixelToSVG(screenPoint); 14506 } 14507 setDefaultMarkerImage(src) { 14508 this.options.defaultMarkerImage = src; 14509 } 14510 setMarkerImagesDependency() { 14511 this.locationField = this.objectsRepository.schema.getFieldByType("location"); 14512 if (this.locationField && 14513 this.locationField.markersByFieldEnabled && 14514 this.locationField.markerField && 14515 Object.values(this.locationField.markersByField).length > 0) { 14516 this.setMarkersByField = true; 14517 } 14518 else { 14519 this.setMarkersByField = false;
14520 } 14521 } 14522 getMarkerImage(fieldValueOrObject, location) { 14523 let fieldValue; 14524 if (this.setMarkersByField) { 14525 if (typeof fieldValueOrObject === "object") { 14526 fieldValue = fieldValueOrObject[this.locationField.markerField]; 14527 if (this.locationField.markerField === "regions") { 14528 fieldValue = fieldValue[0] && fieldValue[0].id; 14529 } 14530 else if (typeof fieldValue === "object" && fieldValue.length) { 14531 fieldValue = fieldValue[0].value; 14532 } 14533 } 14534 else { 14535 fieldValue = fieldValueOrObject; 14536 } 14537 if (this.locationField.markersByField[fieldValue]) { 14538 return this.locationField.markersByField[fieldValue]; 14539 } 14540 } 14541 return location && location.imagePath 14542 ? location.imagePath 14543 : this.options.defaultMarkerImage 14544 ? this.options.defaultMarkerImage 14545 : MapSVG.urls.root + "markers/_pin_default.png"; 14546 } 14547 setMarkersEditMode(on, clickAddsMarker) { 14548 this.editMarkers.on = MapSVG.parseBoolean(on); 14549 this.clickAddsMarker = this.editMarkers.on; 14550 this.setEventHandlers(); 14551 } 14552 setRegionsEditMode(on) { 14553 this.editRegions.on = MapSVG.parseBoolean(on); 14554 this.deselectAllRegions(); 14555 this.setEventHandlers(); 14556 } 14557 setEditMode(on) { 14558 this.editMode = on; 14559 } 14560 setDataEditMode(on) { 14561 this.editData.on = MapSVG.parseBoolean(on); 14562 this.deselectAllRegions(); 14563 this.setEventHandlers(); 14564 } 14565 download() { 14566 window.location.href = window.location.origin + this.options.source; 14567 } 14568 popoverAdjustScreenPosition() { 14569 if (this.controllers.popover instanceof PopoverController) { 14570 this.controllers.popover.adjustScreenPosition(); 14571 } 14572 } 14573 popoverMoveScreenPositionBy(deltaX, deltaY) { 14574 if (this.controllers.popover instanceof PopoverController) { 14575 this.controllers.popover.moveSrceenPositionBy(deltaX, deltaY); 14576 } 14577 } 14578 showPopover(object) { 14579 const mapObject = object instanceof Region 14580 ? object 14581 : object.location && object.location.marker 14582 ? object.location.marker 14583 : null; 14584 if (!mapObject) 14585 return; 14586 let point; 14587 if (mapObject instanceof Marker) { 14588 point = mapObject.svgPoint; 14589 } 14590 else { 14591 point = mapObject.getCenterSVG(); 14592 } 14593 this.controllers.popover && this.controllers.popover.destroy(); 14594 this.controllers.popover = new PopoverController({ 14595 container: this.containers.popover, 14596 point: point, 14597 yShift: mapObject instanceof Marker ? mapObject.height : 0, 14598 template: object instanceof Region 14599 ? this.options.templates.popoverRegion 14600 : this.options.templates.popoverMarker, 14601 mapsvg: this, 14602 data: object.getData(), 14603 mapObject: mapObject, 14604 scrollable: true, 14605 withToolbar: !(MapSVG.isPhone && this.options.popovers.mobileFullscreen), 14606 events: { 14607 shown: (popover) => { 14608 if (this.options.popovers.centerOn) { 14609 const shift = popover.containers.main.offsetHeight / 2; 14610 if (this.options.popovers.centerOn && 14611 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14612 this.centerOn(mapObject, shift); 14613 } 14614 } 14615 this.popoverShowingFor = mapObject; 14616 this.events.trigger("shown.popover", this, [this, popover]); 14617 $$A(window).trigger("shown.popover", [this, popover]); 14618 }, 14619 closed: (popover) => { 14620 this.options.popovers.resetViewboxOnClose && this.viewBoxReset(true); 14621 this.popoverShowingFor = null; 14622 this.events.trigger("closed.popover", this, [this, popover]); 14623 }, 14624 resize: (popover) => { 14625 if (this.options.popovers.centerOn) { 14626 const shift = popover.containers.main.offsetHeight / 2; 14627 if (this.options.popovers.centerOn && 14628 !(MapSVG.isPhone && this.options.popovers.mobileFullscreen)) { 14629 this.centerOn(mapObject, shift); 14630 } 14631 } 14632 }, 14633 }, 14634 }); 14635 this.controllers.popover._init(); 14636 } 14637 hidePopover() { 14638 this.controllers.popover && this.controllers.popover.close(); 14639 } 14640 popoverOffHandler(e) { 14641 if (this.isScrolling || 14642 $$A(e.target).closest(".mapsvg-popover").length || 14643 $$A(e.target).hasClass("mapsvg-btn-map")) 14644 return; 14645 this.controllers.popover && this.controllers.popover.close(); 14646 } 14647 mouseOverHandler(e, object) { 14648 if (this.eventsPreventList["mouseover"]) { 14649 return; 14650 } 14651 if (object instanceof Marker) { 14652 if (this.options.actions.marker.mouseover.showTooltip) { 14653 this.showTooltip(object); 14654 } 14655 } 14656 if (object instanceof Region) { 14657 if (this.options.actions.region.mouseover.showTooltip) { 14658 this.showTooltip(object); 14659 } 14660 } 14661 let ids; 14662 if (this.options.menu.on) { 14663 if (this.options.menu.source == "database") { 14664 if (object instanceof Region && object.objects.length) { 14665 ids = object.objects.map((obj) => { 14666 return obj.id; 14667 }); 14668 } 14669 if (object instanceof Marker) { 14670 ids = object.object ? [object.object.id] : []; 14671 } 14672 } 14673 else { 14674 if (object instanceof Region) { 14675 ids = [object.id]; 14676 } 14677 if (this instanceof Marker && 14678 object.object.regions && 14679 object.object.regions.length) { 14680 ids = object.object.regions.map((obj) => { 14681 return obj.id; 14682 }); 14683 } 14684 } 14685 this.controllers.directory.highlightItems(ids); 14686 } 14687 if (object instanceof Region) { 14688 if (!object.selected) 14689 object.highlight(); 14690 this.events.trigger("mouseover.region", object, [e, this]); 14691 } 14692 else { 14693 this.highlightMarker(object); 14694 this.events.trigger("mouseover.marker", object, [e, this]); 14695 } 14696 } 14697 showTooltip(object) { 14698 let name, _object; 14699 if (object instanceof Region) { 14700 name = "tooltipRegion"; 14701 _object = object; 14702 } 14703 else if (object instanceof Marker) { 14704 name = "tooltipMarker"; 14705 _object = object.object; 14706 } 14707 else { 14708 name = "tooltipMarker"; 14709 _object = object; 14710 } 14711 if (_object != null && this.popoverShowingFor !== object) { 14712 this.controllers.tooltip.setMainTemplate(this.options.templates[name]); 14713 this.controllers.tooltip.redraw(_object.getData()); 14714 this.controllers.tooltip.show(); 14715 } 14716 } 14717 mouseOutHandler(e, object) { 14718 if (this.eventsPreventList["mouseout"]) { 14719 return; 14720 } 14721 if (this.controllers.tooltip) 14722 this.controllers.tooltip.hide(); 14723 if (object instanceof Region) { 14724 if (!object.selected) 14725 object.unhighlight(); 14726 this.events.trigger("mouseout.region", object, [e, this]); 14727 } 14728 else { 14729 this.unhighlightMarker(); 14730 this.events.trigger("mouseout.marker", object, [e, this]); 14731 } 14732 let ids; 14733 if (this.options.menu.on) { 14734 if (this.options.menu.source == "database") { 14735 if (object instanceof Marker) { 14736 const marker = object; 14737 ids = marker.object ? [marker.object.id] : []; 14738 } 14739 } 14740 this.controllers.directory.unhighlightItems(); 14741 } 14742 } 14743 eventsPrevent(event) { 14744 this.eventsPreventList[event] = true; 14745 } 14746 eventsRestore(event) { 14747 if (event) { 14748 this.eventsPreventList[event] = false;
14749 } 14750 else { 14751 this.eventsPreventList = {}; 14752 } 14753 } 14754 setEventHandlers() { 14755 const _this = this; 14756 $$A(_this.containers.map).off(".common.mapsvg"); 14757 $$A(_this.containers.scrollpane).off(".common.mapsvg"); 14758 $$A(document).off(".scroll.mapsvg"); 14759 $$A(document).off(".scrollInit.mapsvg"); 14760 if (_this.editMarkers.on) { 14761 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", ".mapsvg-marker", function (e) { 14762 e.originalEvent.preventDefault(); 14763 const marker = _this.getMarker($$A(this).attr("id")); 14764 const startCoords = MapSVG.mouseCoords(e); 14765 marker.drag(startCoords, _this.scale); 14766 }); 14767 } 14768 if (!_this.editMarkers.on) { 14769 $$A(_this.containers.map) 14770 .on("mouseover.common.mapsvg", ".mapsvg-region", function (e) { 14771 const id = $$A(this).attr("id"); 14772 _this.mouseOverHandler.call(_this, e, _this.getRegion(id)); 14773 }) 14774 .on("mouseleave.common.mapsvg", ".mapsvg-region", function (e) { 14775 const id = $$A(this).attr("id"); 14776 _this.mouseOutHandler.call(_this, e, _this.getRegion(id)); 14777 }); 14778 } 14779 if (!_this.editRegions.on) { 14780 $$A(_this.containers.map) 14781 .on("mouseover.common.mapsvg", ".mapsvg-marker", function (e) { 14782 const id = $$A(this).attr("id"); 14783 _this.mouseOverHandler.call(_this, e, _this.getMarker(id)); 14784 }) 14785 .on("mouseleave.common.mapsvg", ".mapsvg-marker", function (e) { 14786 const id = $$A(this).attr("id"); 14787 _this.mouseOutHandler.call(_this, e, _this.getMarker(id)); 14788 }); 14789 } 14790 if (_this.options.scroll.spacebar) { 14791 $$A(document).on("keydown.scroll.mapsvg", function (e) { 14792 if (!(document.activeElement.tagName === "INPUT" && 14793 $$A(document.activeElement).attr("type") === "text") && 14794 !_this.isScrolling && 14795 e.keyCode == 32) { 14796 e.preventDefault(); 14797 $$A(_this.containers.map).addClass("mapsvg-scrollable"); 14798 $$A(document) 14799 .on("mousemove.scrollInit.mapsvg", function (e) { 14800 _this.isScrolling = true; 14801 $$A(document).off("mousemove.scrollInit.mapsvg"); 14802 _this.scrollStart(e, _this); 14803 }) 14804 .on("keyup.scroll.mapsvg", function (e) { 14805 if (e.keyCode == 32) { 14806 $$A(document).off("mousemove.scrollInit.mapsvg"); 14807 $$A(_this.containers.map).removeClass("mapsvg-scrollable"); 14808 } 14809 }); 14810 } 14811 }); 14812 } 14813 else if (!_this.options.scroll.on) { 14814 if (!_this.editMarkers.on) { 14815 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-region", function (e) { 14816 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14817 }); 14818 $$A(_this.containers.map).on("touchstart.common.mapsvg", ".mapsvg-marker", function (e) { 14819 _this.scroll.touchScrollStart = $$A(window).scrollTop(); 14820 }); 14821 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-region", function (e) { 14822 if (e.cancelable) { 14823 e.preventDefault(); 14824 } 14825 if (!_this.scroll.touchScrollStart || 14826 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14827 _this.regionClickHandler(e, _this.getRegion($$A(this).attr("id"))); 14828 } 14829 }); 14830 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker", function (e) { 14831 if (e.cancelable) { 14832 e.preventDefault(); 14833 } 14834 if (!_this.scroll.touchScrollStart || 14835 _this.scroll.touchScrollStart === $$A(window).scrollTop()) { 14836 _this.markerClickHandler.call(_this, e, _this.getMarker($$A(this).attr("id"))); 14837 } 14838 }); 14839 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", ".mapsvg-marker-cluster", function (e) { 14840 if (e.cancelable) { 14841 e.preventDefault(); 14842 } 14843 if (!_this.scroll.touchScrollStart || 14844 _this.scroll.touchScrollStart == $$A(window).scrollTop()) { 14845 const cluster = $$A(this).data("cluster"); 14846 _this.zoomTo(cluster.markers); 14847 } 14848 }); 14849 } 14850 else { 14851 if (_this.clickAddsMarker) 14852 $$A(_this.containers.map).on("touchend.common.mapsvg mouseup.common.mapsvg", function (e) { 14853 if (e.cancelable) { 14854 e.preventDefault(); 14855 } 14856 _this.markerAddClickHandler(e); 14857 }); 14858 } 14859 } 14860 else { 14861 $$A(_this.containers.map).on("touchstart.common.mapsvg mousedown.common.mapsvg", function (e) { 14862 if ($$A(e.target).hasClass("mapsvg-popover") || 14863 $$A(e.target).closest(".mapsvg-popover").length) { 14864 if ($$A(e.target).hasClass("mapsvg-popover-close")) { 14865 if (e.type == "touchstart") { 14866 if (e.cancelable) { 14867 e.preventDefault(); 14868 } 14869 } 14870 } 14871 return; 14872 } 14873 if (e.type == "touchstart") { 14874 if (e.cancelable) { 14875 e.preventDefault(); 14876 } 14877 } 14878 let obj; 14879 if (e.target && 14880 $$A(e.target).attr("class") && 14881 $$A(e.target).attr("class").indexOf("mapsvg-region") != -1) { 14882 obj = _this.getRegion($$A(e.target).attr("id")); 14883 _this.setObjectClickedBeforeScroll(obj); 14884 } 14885 else if (e.target && 14886 $$A(e.target).attr("class") && 14887 $$A(e.target).attr("class").indexOf("mapsvg-marker") != -1 && 14888 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster")
14888=== -1) { 14889 if (_this.editMarkers.on) { 14890 return; 14891 } 14892 obj = _this.getMarker($$A(e.target).attr("id")); 14893 _this.setObjectClickedBeforeScroll(obj); 14894 } 14895 else if (e.target && 14896 $$A(e.target).attr("class") && 14897 $$A(e.target).attr("class").indexOf("mapsvg-marker-cluster") != -1) { 14898 if (_this.editMarkers.on) { 14899 return; 14900 } 14901 obj = $$A(e.target).data("cluster"); 14902 _this.setObjectClickedBeforeScroll(obj); 14903 } 14904 if (e.type == "mousedown") { 14905 _this.scrollStart(e, _this); 14906 } 14907 else { 14908 _this.touchStart(e, _this); 14909 } 14910 }); 14911 } 14912 $$A(_this.containers.map).on("mouseleave.common.mapsvg", ".mapsvg-choropleth-gradient-wrap", (e) => { 14913 this.controllers.tooltip.hide(); 14914 }); 14915 } 14916 setLabelsRegions(options) { 14917 options = options || this.options.labelsRegions; 14918 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14919 $$A.extend(true, this.options, { labelsRegions: options }); 14920 if (this.options.labelsRegions.on) { 14921 this.regions.forEach((region) => { 14922 if (!region.label) { 14923 region.label = jQuery('<div class="mapsvg-region-label" />')[0]; 14924 $$A(this.layers.labels).append(region.label); 14925 } 14926 try { 14927 $$A(region.label).html(this.templates.labelRegion(region.forTemplate())); 14928 } 14929 catch (err) { 14930 console.error('MapSVG: Error in the "Region Label" template'); 14931 } 14932 }); 14933 this.labelsRegionsAdjustScreenPosition(); 14934 } 14935 else { 14936 this.regions.forEach((region) => { 14937 if (region.label) { 14938 $$A(region.label).remove(); 14939 region.label = null; 14940 delete region.label; 14941 } 14942 }); 14943 } 14944 } 14945 setLabelsMarkers(options) { 14946 options = options || this.options.labelsMarkers; 14947 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 14948 $$A.extend(true, this.options, { labelsMarkers: options }); 14949 if (this.options.labelsMarkers.on) { 14950 this.markers.forEach((marker) => { 14951 try { 14952 marker.setLabel(this.templates.labelMarker(marker.object)); 14953 } 14954 catch (err) { 14955 console.error('MapSVG: Error in the "Marker Label" template'); 14956 } 14957 }); 14958 } 14959 else { 14960 this.markers.forEach((marker) => { 14961 marker.setLabel(""); 14962 }); 14963 } 14964 } 14965 addLayer(name) { 14966 this.layers[name] = $$A('<div class="mapsvg-layer mapsvg-layer-' + name + '"></div>')[0]; 14967 this.containers.layers.appendChild(this.layers[name]); 14968 return this.layers[name]; 14969 } 14970 getLayer(name) { 14971 return this.layers[name]; 14972 } 14973 getDb() { 14974 return this.objectsRepository; 14975 } 14976 getDbRegions() { 14977 return this.regionsRepository; 14978 } 14979 regionAdd(svgObject) { 14980 const region = new Region(svgObject, this); 14981 region.setStatus(1); 14982 this.regions.push(region); 14983 this.regions.sort(function (a, b) { 14984 return a.id == b.id ? 0 : +(a.id > b.id) || -1; 14985 }); 14986 return region; 14987 } 14988 regionDelete(id) { 14989 if (this.regions.findById(id)) { 14990 this.regions.findById(id).elem.remove(); 14991 this.regions.delete(id); 14992 } 14993 else if ($$A("#" + id).length) { 14994 $$A("#" + id).remove(); 14995 } 14996 } 14997 reloadRegions() { 14998 this.regions.clear(); 14999 $$A(this.containers.svg).find(".mapsvg-region").removeClass("mapsvg-region"); 15000 $$A(this.containers.svg) 15001 .find(".mapsvg-region-disabled") 15002 .removeClass("mapsvg-region-disabled"); 15003 $$A(this.containers.svg) 15004 .find("path, polygon, circle, ellipse, rect") 15005 .each((index, element) => { 15006 const elem = element; 15007 if ($$A(elem).closest("defs").length) 15008 return; 15009 if (elem.getAttribute("data-stroke-width")) { 15010 elem.style["stroke-width"] = elem.getAttribute("data-stroke-width"); 15011 } 15012 if (elem.getAttribute("id")) { 15013 if (!this.options.regionPrefix || 15014 (this.options.regionPrefix && 15015 elem.getAttribute("id").indexOf(this.options.regionPrefix) === 0)) { 15016 const region = new Region(elem, this); 15017 this.regions.push(region); 15018 } 15019 } 15020 }); 15021 } 15022 reloadRegionsFull() { 15023 const statuses = this.regionsRepository.getSchema().getFieldByType("status"); 15024 this.regions.forEach((region) => { 15025 const _region = this.regionsRepository.getLoaded().findById(region.id); 15026 if (_region) { 15027 region.setData(_region); 15028 if (statuses && _region.status !== undefined && _region.status !== null) { 15029 region.setStatus(_region.status); 15030 } 15031 } 15032 else { 15033 if (this.options.filters.filteredRegionsStatus || 15034 this.options.filters.filteredRegionsStatus === 0 || 15035 (this.options.menu.source === "regions" && 15036 this.options.menu.filterout && 15037 this.options.menu.filterout.field === "status" && 15038 this.options.menu.filterout.val) || 15039 this.options.menu.filterout.val === 0) { 15040 const status = this.options.filters.filteredRegionsStatus || 15041 this.options.filters.filteredRegionsStatus === 0 15042 ? this.options.filters.filteredRegionsStatus 15043 : this.options.menu.filterout.val; 15044 region.setStatus(status); 15045 } 15046 } 15047 }); 15048 this.loadDirectory(); 15049 this.setChoropleth(); 15050 this.setLayersControl(); 15051 this.setGroups(); 15052 if (this.options.labelsRegions.on) { 15053 this.setLabelsRegions(); 15054 } 15055 } 15056 fixMarkersWorldScreen() { 15057 if (this.googleMaps.map) 15058 setTimeout(() => { 15059 const markers = { left: 0, right: 0, leftOut: 0, rightOut: 0 }; 15060 if (this.markers.length > 1) {
15061 this.markers.forEach((m) => { 15062 if ($$A(m.element).offset().left < 15063 $$A(this.containers.map).offset().left + 15064 this.containers.map.clientWidth / 2) { 15065 markers.left++; 15066 if ($$A(m.element).offset().left < $$A(this.containers.map).offset().left) { 15067 markers.leftOut++; 15068 } 15069 } 15070 else { 15071 markers.right++; 15072 if ($$A(m.element).offset().left > 15073 $$A(this.containers.map).offset().left + 15074 this.containers.map.clientWidth) { 15075 markers.rightOut++; 15076 } 15077 } 15078 }); 15079 if ((markers.left === 0 && markers.rightOut) || 15080 (markers.right === 0 && markers.leftOut)) { 15081 const k = markers.left === 0 ? 1 : -1; 15082 const ww = (this.svgDefault.viewBox.width / this.converter.mapLonDelta) * 15083 360 *
15084 this.getScale(); 15085 this.googleMaps.map.panBy(k * ww, 0); 15086 } 15087 } 15088 }, 600); 15089 } 15090 updateOutdatedOptions(options) { 15091 if (options.menu && (options.menu.position || options.menu.customContainer)) { 15092 if (options.menu.customContainer) { 15093 options.menu.location = "custom"; 15094 } 15095 else { 15096 options.menu.position = options.menu.position === "left" ? "left" : "right"; 15097 options.menu.location = 15098 options.menu.position === "left" ? "leftSidebar" : "rightSidebar"; 15099 if (!options.containers || !options.containers[options.menu.location]) { 15100 options.containers = options.containers || {}; 15101 options.containers[options.menu.location] = { on: false, width: "200px" }; 15102 } 15103 options.containers[options.menu.location].width = options.menu.width; 15104 if (MapSVG.parseBoolean(options.menu.on)) { 15105 options.containers[options.menu.location].on = true; 15106 } 15107 } 15108 delete options.menu.position; 15109 delete options.menu.width; 15110 delete options.menu.customContainer; 15111 } 15112 if (options.detailsView && 15113 (options.detailsView.location === "mapContainer" || 15114 options.detailsView.location === "near" || 15115 options.detailsView.location === "top")) { 15116 options.detailsView.location = "map"; 15117 } 15118 if (!options.controls) { 15119 options.controls = {}; 15120 options.controls.zoom = 15121 options.zoom && 15122 options.zoom.on && 15123 (!options.zoom.buttons || options.zoom.buttons.location !== "hide"); 15124 options.controls.location = 15125 options.zoom && options.zoom.buttons && options.zoom.buttons.location !== "hide" 15126 ? options.zoom.buttons.location 15127 : "right"; 15128 } 15129 if (options.colors && !options.colors.markers) { 15130 options.colors.markers = { 15131 base: { opacity: 100, saturation: 100 }, 15132 hovered: { opacity: 100, saturation: 100 }, 15133 unhovered: { opacity: 100, saturation: 100 }, 15134 active: { opacity: 100, saturation: 100 }, 15135 inactive: { opacity: 100, saturation: 100 }, 15136 }; 15137 } 15138 if (options.tooltipsMode) { 15139 options.tooltips.mode = options.tooltipsMode; 15140 delete options.tooltipsMode; 15141 } 15142 if (options.popover) { 15143 options.popovers = options.popover; 15144 delete options.popover; 15145 } 15146 } 15147 init() { 15148 MapSVG.addInstance(this); 15149 if (this.options.source === "") { 15150 throw new Error("MapSVG: please provide SVG file source."); 15151 } 15152 this.disableAnimation(); 15153 this.setEvents(this.options.events); 15154 this.events.trigger("beforeLoad"); 15155 if (this.options.googleMaps.apiKey && 15156 (this.editMode || 15157 this.options.googleMaps.on || 15158 (this.options.filters.on && 15159 this.options.filtersSchema && 15160 this.options.filtersSchema.find((f) => f.type === "distance")))) { 15161 this.loadGoogleMapsAPI(() => { 15162 return 1; 15163 }, () => { 15164 return 1; 15165 }); 15166 } 15167 this.containers.map.classList.add("mapsvg"); 15168 this.setCss(); 15169 if (this.options.colors && this.options.colors.background) { 15170 this.containers.map.style.background = this.options.colors.background; 15171 }
15172 this.setContainers(this.options.containers); 15173 this.setColors(); 15174 this.addLoadingMessage(); 15175 this.addLayer("markers"); 15176 this.addLayer("labels"); 15177 this.addLayer("bubbles"); 15178 this.addLayer("popovers"); 15179 this.addLayer("scrollpane"); 15180 this.loadExtensions(); 15181 $$A.ajax({ url: this.options.source + "?v=" + this.svgFileLastChanged }) 15182 .fail((resp) => { 15183 this.svgLoadingFailed(resp); 15184 }) 15185 .done((xmlData) => { 15186 this.renderSvgData(xmlData); 15187 }); 15188 return this; 15189 } 15190 getContainer(name) { 15191 return this.containers[name]; 15192 } 15193 renderSvgData(xmlData) { 15194 const svgTag = $$A(xmlData).find("svg"); 15195 this.containers.svg = svgTag[0]; 15196 if (svgTag.attr("width") && svgTag.attr("height")) { 15197 this.svgDefault.width = parseFloat(svgTag.attr("width").replace(/px/g, "")); 15198 this.svgDefault.height = parseFloat(svgTag.attr("height").replace(/px/g, "")); 15199 this.svgDefault.viewBox = svgTag.attr("viewBox") 15200 ? new ViewBox(svgTag.attr("viewBox").split(" ")) 15201 : new ViewBox(0, 0, this.svgDefault.width, this.svgDefault.height); 15202 } 15203 else if (svgTag.attr("viewBox")) { 15204 this.svgDefault.viewBox = new ViewBox(svgTag.attr("viewBox").split(" ")); 15205 this.svgDefault.width = this.svgDefault.viewBox.width; 15206 this.svgDefault.height = this.svgDefault.viewBox.height; 15207 } 15208 else { 15209 const msg = "MapSVG: width/height and viewBox are missing in the SVG file. Can't parse the file because of that."; 15210 if (this.editMode) { 15211 alert(msg); 15212 } 15213 else { 15214 console.error(msg); 15215 } 15216 return false; 15217 } 15218 this.geoViewBox = this.getGeoViewBoxFromSvgTag(this.containers.svg); 15219 if (this.options.viewBox && this.options.viewBox.length == 4) { 15220 this._viewBox = new ViewBox(this.options.viewBox); 15221 } 15222 else { 15223 this._viewBox = new ViewBox(this.svgDefault.viewBox); 15224 } 15225 svgTag.attr("preserveAspectRatio", "xMidYMid meet"); 15226 svgTag.removeAttr("width"); 15227 svgTag.removeAttr("height"); 15228 $$A(this.containers.scrollpane).append(svgTag); 15229 this.setStrokes(); 15230 this.reloadRegions(); 15231 this.setSize(this.options.width, this.options.height, this.options.responsive); 15232 if (this.options.disableAll) { 15233 this.setDisableAll(true); 15234 } 15235 this.setViewBox(this._viewBox); 15236 this.converter = new Converter(this.containers.map, this.svgDefault.viewBox, this.viewBox); 15237 if (this.geoViewBox) { 15238 this.converter.setGeoViewBox(this.geoViewBox); 15239 } 15240 this.setResponsive(this.options.responsive); 15241 this.setScroll(this.options.scroll, true); 15242 this.setZoom(this.options.zoom); 15243 this.setControls(this.options.controls); 15244 this.setGoogleMaps(); 15245 this.setTooltips(this.options.tooltips); 15246 this.setPopovers(this.options.popovers); 15247 if (this.options.cursor) 15248 this.setCursor(this.options.cursor); 15249 this.setTemplates(this.options.templates); 15250 this.loadExtensions(); 15251 this.filtersSchema = new Schema({ fields: this.options.filtersSchema }); 15252 this.objectsRepository.events.on("load", () => { 15253 this.showLoadingMessage(); 15254 }); 15255 this.objectsRepository.events.on("loaded", () => { 15256 this.setGlobalDistanceFilter(); 15257 this.fitOnDataLoadDone = false; 15258 this.addLocations(); 15259 this.fixMarkersWorldScreen();
15260 this.attachDataToRegions(); 15261 this.loadDirectory(); 15262 if (this.options.labelsMarkers.on) { 15263 this.setLabelsMarkers(); 15264 } 15265 if (this.options.templates.labelRegion.indexOf("{{objects") !== -1) { 15266 this.setLabelsRegions(); 15267 } 15268 if (this.options.filters.on && 15269 this.options.filters.source === "database" && 15270 this.controllers.filters && 15271 this.controllers.filters.hideFilters) { 15272 this.controllers.filters.setFiltersCounter(); 15273 } 15274 this.hideLoadingMessage(); 15275 this.events.trigger("databaseLoaded"); 15276 this.updateFiltersState(); 15277 this.setChoropleth(); 15278 }); 15279 this.objectsRepository.events.on("schemaChanged", () => { 15280 this.objectsRepository.reload(); 15281 }); 15282 this.objectsRepository.events.on("updated", (obj) => { 15283 this.attachDataToRegions(obj); 15284 this.reloadRegionsFull(); 15285 }); 15286 this.objectsRepository.events.on("created", (obj) => { 15287 this.attachDataToRegions(obj); 15288 this.reloadRegionsFull(); 15289 }); 15290 this.objectsRepository.events.on("deleted", (id) => { 15291 this.attachDataToRegions(); 15292 this.reloadRegionsFull(); 15293 }); 15294 this.regionsRepository.events.on("load", () => { 15295 this.showLoadingMessage(); 15296 }); 15297 this.regionsRepository.events.on("loaded", () => { 15298 this.hideLoadingMessage(); 15299 this.reloadRegionsFull(); 15300 if (this.options.filters.on && 15301 this.options.filters.source === "regions" && 15302 this.controllers.filters && 15303 this.controllers.filters.hideFilters) { 15304 this.controllers.filters.setFiltersCounter(); 15305 } 15306 this.events.trigger("regionsLoaded"); 15307 }); 15308 this.regionsRepository.events.on("updated", (regionData) => { 15309 this.reloadRegionsFull(); 15310 }); 15311 this.regionsRepository.events.on("created", (regionData) => { 15312 this.reloadRegionsFull(); 15313 }); 15314 this.regionsRepository.events.on("deleted", (regionData) => { 15315 this.reloadRegionsFull(); 15316 }); 15317 this.setMenu(); 15318 this.setFilters(); 15319 this.setFilterOut(); 15320 this.setEventHandlers(); 15321 this.afterLoadBlockers--; 15322 if (!this.id) { 15323 this.finalizeMapLoading(); 15324 return; 15325 } 15326 if (!this.options.data_regions) { 15327 this.regionsRepository.find().done((data) => { 15328 this.afterLoadBlockers--; 15329 this.finalizeMapLoading(); 15330 }); 15331 } 15332 else { 15333 this.regionsRepository.loadDataFromResponse(this.options.data_regions); 15334 this.afterLoadBlockers--; 15335 } 15336 if (!this.options.data_objects) { 15337 if (this.options.database.loadOnStart || this.editMode) { 15338 this.objectsRepository.find().done((data) => { 15339 this.afterLoadBlockers--; 15340 this.finalizeMapLoading(); 15341 }); 15342 } 15343 else { 15344 this.afterLoadBlockers--; 15345 this.finalizeMapLoading(); 15346 } 15347 } 15348 else { 15349 if (this.editMode || this.options.database.loadOnStart) { 15350 this.objectsRepository.loadDataFromResponse(this.options.data_objects); 15351 this.afterLoadBlockers--; 15352 } 15353 else { 15354 this.afterLoadBlockers--; 15355 } 15356 delete this.options.data_regions; 15357 delete this.options.data_objects; 15358 this.finalizeMapLoading(); 15359 } 15360 } 15361 setFilterOut() { 15362 if (this.options.menu.filterout.field) { 15363 const f = {}; 15364 f[this.options.menu.filterout.field] = this.options.menu.filterout.val; 15365 if (this.options.menu.source == "regions") ; 15366 else { 15367 this.objectsRepository.query.setFilterOut(f); 15368 } 15369 } 15370 else { 15371 this.objectsRepository.query.setFilterOut(null); 15372 } 15373 } 15374 getGeoViewBoxFromSvgTag(svgTag) { 15375 const geo = $$A(svgTag).attr("mapsvg:geoViewBox") || $$A(svgTag).attr("mapsvg:geoviewbox"); 15376 if (geo) { 15377 const geoParts = geo.split(" ").map((p) => parseFloat(p)); 15378 if (geoParts.length == 4) { 15379 this.mapIsGeo = true; 15380 this.geoCoordinates = true; 15381 const sw = new GeoPoint(geoParts[3], geoParts[0]); 15382 const ne = new GeoPoint(geoParts[1], geoParts[2]); 15383 return new GeoViewBox(sw, ne); 15384 } 15385 } 15386 else { 15387 return null; 15388 } 15389 } 15390 svgLoadingFailed(resp) { 15391 if (resp.status == 404) { 15392 let msg = "MapSVG: file not found - " + 15393 this.options.source + 15394 "\n\nIf you moved MapSVG from another server please read the following docs page: https://mapsvg.com/docs/installation/moving"; 15395 if (this.editMode) { 15396 msg += 15397 "\n\nIf you know the correct path for the SVG file, please write it and press OK:"; 15398 const oldSvgPath = this.options.source; 15399 const userSvgPath = prompt(msg, oldSvgPath); 15400 if (userSvgPath !== null) { 15401 $$A.ajax({ url: userSvgPath + "?v=" + this.svgFileLastChanged }) 15402 .fail(function () { 15403 location.reload(); 15404 }) 15405 .done((xmlData) => { 15406 this.options.source = userSvgPath; 15407 this.renderSvgData(xmlData); 15408 const mapsRepo = new MapsRepository(); 15409 mapsRepo.update(this); 15410 }); 15411 } 15412 else { 15413 location.reload(); 15414 } 15415 } 15416 else { 15417 console.error(msg); 15418 } 15419 } 15420 else { 15421 const msg = "MapSVG: can't load SVG file for unknown reason. Please contact support: https://mapsvg.ticksy.com"; 15422 if (this.editMode) { 15423 alert(msg); 15424 } 15425 else { 15426 console.error(msg); 15427 } 15428 } 15429 } 15430 addLoadingMessage() { 15431 this.containers.loading = document.createElement("div"); 15432 this.containers.loading.className = "mapsvg-loading"; 15433 const loadingTextBlock = document.createElement("div"); 15434 loadingTextBlock.className = "mapsvg-loading-text"; 15435 loadingTextBlock.innerHTML = this.options.loadingText; 15436 const spinner = document.createElement("div"); 15437 spinner.className = "spinner-border spinner-border-sm"; 15438 this.containers.loading.appendChild(spinner); 15439 this.containers.loading.appendChild(loadingTextBlock); 15440 this.containers.map.appendChild(this.containers.loading); 15441 if (this.options.googleMaps.on) { 15442 $$A(this.containers.map).addClass("mapsvg-google-map-loading"); 15443 } 15444 } 15445 hideLoadingMessage() { 15446 $$A(this.containers.loading).hide(); 15447 } 15448 showLoadingMessage() { 15449 $$A(this.containers.loading).show(); 15450 } 15451 disableAnimation() { 15452 this.containers.map.classList.add("no-transitions"); 15453 } 15454 enableAnimation() { 15455 $$A(this.containers.map).removeClass("no-transitions"); 15456 } 15457 loadExtensions() { 15458 if (this.options.extension && 15459 $$A().mapSvg.extensions && 15460 $$A().mapSvg.extensions[_this.options.extension]) { 15461 const ext = $$A().mapSvg.extensions[_this.options.extension]; 15462 ext && ext.common(this); 15463 } 15464 } 15465 finalizeMapLoading() { 15466 if (this.afterLoadBlockers > 0 || this.loaded) { 15467 return; 15468 } 15469 this.selectRegionByIdFromUrl(); 15470 setTimeout(() => { 15471 this.movingItemsAdjustScreenPosition(); 15472 this.adjustStrokes(); 15473 setTimeout(() => { 15474 this.hideLoadingMessage(); 15475 $$A(this.containers.loading).find(".mapsvg-loading-text").hide(); 15476 this.enableAnimation(); 15477 }, 200); 15478 }, 100); 15479 this.loaded = true; 15480 this.events.trigger("afterLoad"); 15481 } 15482 selectRegionByIdFromUrl() { 15483 const match = RegExp("[?&]mapsvg_select=([^&]*)").exec(window.location.search); 15484 if (match) { 15485 const select = decodeURIComponent(match[1].replace(/\+/g, " ")); 15486 this.selectRegion(select); 15487 } 15488 if (window.location.hash) { 15489 const query = window.location.hash.replace("#/m/", ""); 15490 const region = this.getRegion(query); 15491 if (region && this.options.actions.map.afterLoad.selectRegion) { 15492 this.regionClickHandler(null, region); 15493 } 15494 } 15495 } 15496 createForm(options) { 15497 return new FormBuilder(options); 15498 } 15499 getApiUrl(path) { 15500 const server = new Server(); 15501 return server.getUrl(path); 15502 } 15503 getConverter() { 15504 return this.converter; 15505 } 15506 setChoropleth(options) { 15507 const _this = this; 15508 options = options || _this.options.choropleth; 15509 options.on != undefined && (options.on = MapSVG.parseBoolean(options.on)); 15510 $$A.extend(true, _this.options, { choropleth: options }); 15511 let needsRedraw = false;
15512 if (!_this.$gauge) { 15513 _this.$gauge = {}; 15514 _this.$gauge.gradient = $$A("<td> </td>").addClass("mapsvg-gauge-gradient"); 15515 _this.setGaugeGradientCSS(); 15516 _this.$gauge.container = $$A("<div />").addClass("mapsvg-gauge").hide(); 15517 _this.$gauge.table = $$A("<table />"); 15518 const tr = $$A("<tr />"); 15519 _this.$gauge.labelLow = $$A("<td>" + _this.options.choropleth.labels.low + "</td>"); 15520 _this.$gauge.labelHigh = $$A("<td>" + _this.options.choropleth.labels.high + "</td>"); 15521 tr.append(_this.$gauge.labelLow); 15522 tr.append(_this.$gauge.gradient); 15523 tr.append(_this.$gauge.labelHigh); 15524 _this.$gauge.table.append(tr); 15525 _this.$gauge.container.append(_this.$gauge.table); 15526 $$A(_this.containers.map).append(_this.$gauge.container); 15527 } 15528 if (!_this.options.choropleth.on && _this.$gauge.container.is(":visible")) { 15529 _this.$gauge.container.hide(); 15530 needsRedraw = true; 15531 } 15532 else if (_this.options.choropleth.on && !_this.$gauge.container.is(":visible")) { 15533 _this.$gauge.container.show(); 15534 needsRedraw = true; 15535 _this.regionsRepository.events.on("change", function () { 15536 _this.redrawGauge(); 15537 }); 15538 } 15539 if (options.colors) { 15540 _this.options.choropleth.colors.lowRGB = tinycolor(_this.options.choropleth.colors.low).toRgb(); 15541 _this.options.choropleth.colors.highRGB = tinycolor(_this.options.choropleth.colors.high).toRgb(); 15542 _this.options.choropleth.colors.diffRGB = { 15543 r: _this.options.choropleth.colors.highRGB.r - 15544 _this.options.choropleth.colors.lowRGB.r, 15545 g: _this.options.choropleth.colors.highRGB.g - 15546 _this.options.choropleth.colors.lowRGB.g, 15547 b: _this.options.choropleth.colors.highRGB.b - 15548 _this.options.choropleth.colors.lowRGB.b, 15549 a: _this.options.choropleth.colors.highRGB.a - 15550 _this.options.choropleth.colors.lowRGB.a, 15551 }; 15552 needsRedraw = true; 15553 _this.$gauge && _this.setGaugeGradientCSS(); 15554 } 15555 if (options.labels) { 15556 _this.$gauge.labelLow.html(_this.options.choropleth.labels.low); 15557 _this.$gauge.labelHigh.html(_this.options.choropleth.labels.high); 15558 } 15559 needsRedraw && _this.redrawGauge(); 15560 } 15561 redrawGauge() { 15562 const _this = this; 15563 _this.updateGaugeMinMax(); 15564 _this.regionsRedrawColors(); 15565 } 15566 updateGaugeMinMax() { 15567 const _this = this; 15568 _this.options.choropleth.min = 0; 15569 _this.options.choropleth.max = false; 15570 const values = []; 15571 _this.regions.forEach(function (r) { 15572 const gauge = r.data && r.data[_this.options.regionChoroplethField]; 15573 gauge != undefined && values.push(gauge); 15574 }); 15575 if (values.length > 0) { 15576 _this.options.choropleth.min = values.length == 1 ? 0 : Math.min.apply(null, values); 15577 _this.options.choropleth.max = Math.max.apply(null, values); 15578 _this.options.choropleth.maxAdjusted = 15579 _this.options.choropleth.max - _this.options.choropleth.min; 15580 } 15581 } 15582 setGaugeGradientCSS() { 15583 const _this = this; 15584 _this.$gauge.gradient.css({ 15585 background: "linear-gradient(to right," + 15586 _this.options.choropleth.colors.low + 15587 " 1%," + 15588 _this.options.choropleth.colors.high + 15589 " 100%)", 15590 filter: 'progid:DXImageTransform.Microsoft.gradient( startColorstr="' + 15591 _this.options.choropleth.colors.low + 15592 '", endColorstr="' + 15593 _this.options.choropleth.colors.high + 15594 '",GradientType=1 )', 15595 }); 15596 } 15597 get $map() { 15598 return $$A(this.getContainer("map")); 15599 } 15600 get $svg() { 15601 return $$A(this.getContainer("svg")); 15602 } 15603 get $popover() { 15604 return $$A(this.getContainer("popover")); 15605 } 15606 get $details() { 15607 return $$A(this.getContainer("detailsView")); 15608 } 15609 get $directory() { 15610 return $$A(this.getContainer("directory")); 15611 } 15612 get database() { 15613 return this.objectsRepository; 15614 } 15615 get regionsDatabase() { 15616 return this.regionsRepository; 15617 } 15618 } 15619 15620 exports.MapSVGMap = MapSVGMap; 15621 exports.arrayIndexed = ArrayIndexed; 15622 exports.customObject = CustomObject; 15623 exports.formBuilder = FormBuilder; 15624 exports.geoPoint = GeoPoint; 15625 exports.globals = MapSVG; 15626 exports.location = Location; 15627 exports.map = MapSVGMap; 15628 exports.mapsRepository = MapsRepository; 15629 exports.mapsV2Repository = MapsV2Repository; 15630 exports.marker = Marker; 15631 exports.query = Query; 15632 exports.repository = Repository; 15633 exports.schema = Schema; 15634 exports.schemaRepository = SchemaRepository; 15635 exports.screenPoint = ScreenPoint; 15636 exports.server = Server; 15637 exports.svgPoint = SVGPoint; 15638 15639 Object.defineProperty(exports, '__esModule', { value: true }); 15640 15641}))); 15642//# 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.