ar-poncho 2.0.308 → 2.0.310
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-poncho.yml +15 -32
- package/dist/css/device-breadcrumb.css +1 -1
- package/dist/css/icono-arg.css +110 -8
- package/dist/css/poncho-map.css +1 -1
- package/dist/css/poncho.css +2 -2
- package/dist/css/poncho.min.css +2 -2
- package/dist/css/poncho_mobile.css +2 -2
- package/dist/fonts/{icono-arg_a6cc69d556789499dda37d7617476d6b.ttf → icono-arg_62584f1d69ebd710fc7e1ea3cfa4bceb.eot} +0 -0
- package/dist/fonts/{icono-arg_a6cc69d556789499dda37d7617476d6b.svg → icono-arg_62584f1d69ebd710fc7e1ea3cfa4bceb.svg} +440 -32
- package/dist/fonts/{icono-arg_a6cc69d556789499dda37d7617476d6b.eot → icono-arg_62584f1d69ebd710fc7e1ea3cfa4bceb.ttf} +0 -0
- package/dist/fonts/icono-arg_62584f1d69ebd710fc7e1ea3cfa4bceb.woff +0 -0
- package/dist/fonts/icono-arg_62584f1d69ebd710fc7e1ea3cfa4bceb.woff2 +0 -0
- package/dist/js/device-breadcrumb.js +1 -1
- package/dist/js/mapa-argentina.js +1 -1
- package/dist/js/poncho.js +2650 -1016
- package/dist/js/poncho.min.js +1 -1
- package/dist/js/showdown-extensions.js +2 -2
- package/dist/jsons/icono-arg.json +7603 -0
- package/gulpfile.js +10 -15
- package/package-lock.json +14866 -10143
- package/package.json +59 -49
- package/dist/css/argentina.css +0 -7
- package/dist/fonts/icono-arg_a6cc69d556789499dda37d7617476d6b.woff +0 -0
- package/dist/fonts/icono-arg_a6cc69d556789499dda37d7617476d6b.woff2 +0 -0
- package/test/color.test.js +0 -16
- package/test/gapi-sheet-data.test.js +0 -17
- package/test/html.test.js +0 -18
- package/test/poncho-gapi-legacy.test.js +0 -7
- package/test/resources/response.js +0 -56
- package/test/string.test.js +0 -20
package/dist/js/poncho.js
CHANGED
|
@@ -314,11 +314,25 @@ const ponchoColorDefinitions = color => {
|
|
|
314
314
|
* getColor("celeste")
|
|
315
315
|
* @returns {string} Color en formato hexadecimal.
|
|
316
316
|
*/
|
|
317
|
-
const ponchoColor = color =>
|
|
317
|
+
const ponchoColor = color => {
|
|
318
|
+
const defaultColor = "#99999";
|
|
319
|
+
|
|
320
|
+
if (typeof color !== "string") {
|
|
321
|
+
console.warn(`Invalid color provided. Using default: ${defaultColor}`);
|
|
322
|
+
return defaultColor;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const definition = ponchoColorDefinitions(color);
|
|
326
|
+
if (definition) {
|
|
327
|
+
return definition.color || defaultColor;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return defaultColor;
|
|
331
|
+
};
|
|
318
332
|
|
|
319
333
|
|
|
320
334
|
/**
|
|
321
|
-
*
|
|
335
|
+
* Hace un refactor del número hexa
|
|
322
336
|
*
|
|
323
337
|
* @param {string} value Valor hexadecimal
|
|
324
338
|
* @returns {string}
|
|
@@ -330,10 +344,12 @@ const cleanUpHex = value => {
|
|
|
330
344
|
.trim()
|
|
331
345
|
.toUpperCase();
|
|
332
346
|
|
|
333
|
-
if(hex.length
|
|
347
|
+
if (hex.length < 3 || hex.length > 6){
|
|
348
|
+
return false;
|
|
349
|
+
} else if(hex.length == 3){
|
|
334
350
|
hex = Array.from(hex).map(a => a.repeat(2)).join("");
|
|
335
351
|
}
|
|
336
|
-
return hex
|
|
352
|
+
return `#${hex}`;
|
|
337
353
|
};
|
|
338
354
|
|
|
339
355
|
|
|
@@ -354,7 +370,7 @@ const cleanUpHex = value => {
|
|
|
354
370
|
* findByHex("#f79525");
|
|
355
371
|
* @returns {object} Objecto con la defición del color
|
|
356
372
|
*/
|
|
357
|
-
const
|
|
373
|
+
const ponchoColorByHex = value => ponchoColorDefinitionsList.find(f => {
|
|
358
374
|
const colorToFind = cleanUpHex(value);
|
|
359
375
|
const colorToCompare = cleanUpHex(f.color);
|
|
360
376
|
if(colorToFind == colorToCompare){
|
|
@@ -363,8 +379,11 @@ const findPonchoColorByHex = value => ponchoColorDefinitionsList.find(f => {
|
|
|
363
379
|
return false;
|
|
364
380
|
});
|
|
365
381
|
|
|
366
|
-
|
|
367
|
-
|
|
382
|
+
if (typeof exports !== "undefined") {
|
|
383
|
+
module.exports = {
|
|
384
|
+
ponchoColorDefinitionsList,
|
|
385
|
+
ponchoColorDefinitions, ponchoColor, ponchoColorByHex, cleanUpHex};
|
|
386
|
+
}
|
|
368
387
|
|
|
369
388
|
/**
|
|
370
389
|
* Fetch data
|
|
@@ -376,17 +395,19 @@ const findPonchoColorByHex = value => ponchoColorDefinitionsList.find(f => {
|
|
|
376
395
|
* });
|
|
377
396
|
* ```
|
|
378
397
|
*/
|
|
379
|
-
async function fetch_json(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
);
|
|
398
|
+
async function fetch_json(uri, options={}) {
|
|
399
|
+
|
|
400
|
+
let defaultOptions = {
|
|
401
|
+
method: "GET",
|
|
402
|
+
headers: {
|
|
403
|
+
"Accept": "application/json",
|
|
404
|
+
"Content-Type": "application/json"
|
|
405
|
+
},
|
|
406
|
+
redirect: "follow"
|
|
407
|
+
};
|
|
408
|
+
let opts = Object.assign({}, defaultOptions, options);
|
|
409
|
+
const response = await fetch(uri, opts);
|
|
410
|
+
|
|
390
411
|
if (!response.ok) {
|
|
391
412
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
392
413
|
}
|
|
@@ -436,935 +457,1744 @@ const slugify = (string) =>{
|
|
|
436
457
|
+ "rrsssssttuuuuuuuuuwxyyzzz------";
|
|
437
458
|
const p = new RegExp(a.split("").join("|"), "g");
|
|
438
459
|
|
|
439
|
-
return string.toString().toLowerCase()
|
|
440
|
-
.replace(/\s+/g, "-")
|
|
441
|
-
.replace(p, c => b.charAt(a.indexOf(c)))
|
|
442
|
-
.replace(/&/g, "-and-")
|
|
443
|
-
.replace(/[^\w\-]+/g, "")
|
|
444
|
-
.replace(/\-\-+/g, "-")
|
|
445
|
-
.replace(/^-+/, "")
|
|
446
|
-
.replace(/-+$/, "");
|
|
447
|
-
};
|
|
460
|
+
return string.toString().toLowerCase()
|
|
461
|
+
.replace(/\s+/g, "-")
|
|
462
|
+
.replace(p, c => b.charAt(a.indexOf(c)))
|
|
463
|
+
.replace(/&/g, "-and-")
|
|
464
|
+
.replace(/[^\w\-]+/g, "")
|
|
465
|
+
.replace(/\-\-+/g, "-")
|
|
466
|
+
.replace(/^-+/, "")
|
|
467
|
+
.replace(/-+$/, "");
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
if (typeof exports !== "undefined") {
|
|
472
|
+
module.exports = {slugify, replaceSpecialChars};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Impide que se impriman etiquetas HTML.
|
|
477
|
+
*
|
|
478
|
+
* @summary Impide que se impriman etiquetas HTML exceptuando aquellas
|
|
479
|
+
* asignadas en el parámetro exclude.
|
|
480
|
+
* @param {string} str Cadena de texto a remplazar.
|
|
481
|
+
* @param {object} exclude Etiquetas que deben preservarse.
|
|
482
|
+
* @example
|
|
483
|
+
* // returns <h1>Hello world!</h1> <a href="#">Link</a>
|
|
484
|
+
* secureHTML('<h1>Hello world!</h1> <a href="#">Link</a>', ["a"])
|
|
485
|
+
*
|
|
486
|
+
* @returns {string} Texto remplazado.
|
|
487
|
+
*/
|
|
488
|
+
const secureHTML = (str, exclude=[]) => {
|
|
489
|
+
if(exclude.some(e => e === "*")){
|
|
490
|
+
return str;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
let replaceString = str.toString()
|
|
494
|
+
.replace(/</g, "<")
|
|
495
|
+
.replace(/>/g, ">");
|
|
496
|
+
|
|
497
|
+
// let replaceString = str.toString()
|
|
498
|
+
// .replace(/<(?=[a-zA-Z])([^<>]*)>/gm, "<$1>")
|
|
499
|
+
// .replace(/<\/(?=[a-zA-Z])([^<>]*)>/gm, "</$1>");
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
if(exclude.length > 0){
|
|
503
|
+
const regexStart = new RegExp(
|
|
504
|
+
"<(" + exclude.join("|") + ")(.*?)>", "g");
|
|
505
|
+
const regexEnd = new RegExp(
|
|
506
|
+
"<\/(" + exclude.join("|") + ")(.*?)>", "g");
|
|
507
|
+
|
|
508
|
+
return replaceString
|
|
509
|
+
.replace(regexStart, "<$1$2>")
|
|
510
|
+
.replace(regexEnd, "</$1>");
|
|
511
|
+
}
|
|
512
|
+
return replaceString;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
if (typeof exports !== "undefined") {
|
|
518
|
+
module.exports = {secureHTML};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
function flattenNestedObjects(entries) {
|
|
523
|
+
return entries.map(entry => {
|
|
524
|
+
return flattenObject(entry, "");
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function flattenObject(obj, prefix) {
|
|
529
|
+
const flattened = {};
|
|
530
|
+
for (const key in obj) {
|
|
531
|
+
const value = obj[key];
|
|
532
|
+
const newKey = (prefix ? `${prefix}__${key}` : key);
|
|
533
|
+
|
|
534
|
+
if (typeof value === "object" && value !== null) {
|
|
535
|
+
Object.assign(flattened, flattenObject(value, newKey));
|
|
536
|
+
} else {
|
|
537
|
+
flattened[newKey] = value;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return flattened;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
*
|
|
545
|
+
*/
|
|
546
|
+
ponchoTableLegacyPatch = () => {
|
|
547
|
+
document
|
|
548
|
+
.querySelectorAll("select[id=ponchoTableFiltro]")
|
|
549
|
+
.forEach(element => {
|
|
550
|
+
// const node = element.closest(".form-group");
|
|
551
|
+
const node = element.parentElement;
|
|
552
|
+
const newElement = document.createElement("div");
|
|
553
|
+
newElement.id = "ponchoTableFiltro";
|
|
554
|
+
newElement.classList.add("row");
|
|
555
|
+
node.parentElement.appendChild(newElement);
|
|
556
|
+
node.remove();
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
function ponchoTable(opt) {
|
|
562
|
+
ponchoTableLegacyPatch();
|
|
563
|
+
return ponchoTableDependant(opt);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Agenda
|
|
569
|
+
*
|
|
570
|
+
* @summary Agenda de eventos basada en PonchoTable donde se agrupan las
|
|
571
|
+
* entradas por fecha de inicio, fecha de fin, y categoría.
|
|
572
|
+
* @author Agustín Bouillet <bouilleta@jefatura.gob.ar>
|
|
573
|
+
* @requires jQuery, dataTables
|
|
574
|
+
* @see https://github.com/argob/poncho/tree/master/src/js/poncho-table
|
|
575
|
+
*
|
|
576
|
+
*
|
|
577
|
+
* MIT License
|
|
578
|
+
*
|
|
579
|
+
* Copyright (c) 2024 Argentina.gob.ar
|
|
580
|
+
*
|
|
581
|
+
* Permission is hereby granted, free of charge, to any person
|
|
582
|
+
* obtaining a copy of this software and associated documentation
|
|
583
|
+
* files (the "Software"), to deal in the Software without restriction,
|
|
584
|
+
* including without limitation the rightsto use, copy, modify, merge,
|
|
585
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
586
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
587
|
+
* subject to the following conditions:
|
|
588
|
+
*
|
|
589
|
+
* The above copyright notice and this permission notice shall be
|
|
590
|
+
* included in all copies or substantial portions of the Software.
|
|
591
|
+
*
|
|
592
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
593
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
594
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
595
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
596
|
+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
597
|
+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
598
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
599
|
+
* SOFTWARE.
|
|
600
|
+
*/
|
|
601
|
+
class PonchoAgenda {
|
|
602
|
+
|
|
603
|
+
DATE_REGEX = /^([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\/([1-9]|0[1-9]|1[0-2])\/([1-9][0-9]{3})$/;
|
|
604
|
+
|
|
605
|
+
constructor(options={}){
|
|
606
|
+
options.headers = this._refactorHeaders(options);
|
|
607
|
+
options.headersOrder = this._refactorHeadersOrder(options);
|
|
608
|
+
|
|
609
|
+
// Global Options
|
|
610
|
+
this.opts = Object.assign({}, this.defaults, options);
|
|
611
|
+
|
|
612
|
+
this.categoryTitleClassList = this.opts.categoryTitleClassList;
|
|
613
|
+
this.itemContClassList = this.opts.itemContClassList;
|
|
614
|
+
this.itemClassList = this.opts.itemClassList;
|
|
615
|
+
this.groupCategory = this.opts.groupCategory;
|
|
616
|
+
this.dateSeparator = this.opts.dateSeparator;
|
|
617
|
+
this.startDateId = this.opts.startDateId;
|
|
618
|
+
this.endDateId = this.opts.endDateId;
|
|
619
|
+
this.timeId = this.opts.timeId;
|
|
620
|
+
|
|
621
|
+
this.descriptionId = this.opts.descriptionId;
|
|
622
|
+
this.criteriaOneId = this.opts.criteriaOneId;
|
|
623
|
+
this.criteriaTwoId = this.opts.criteriaTwoId;
|
|
624
|
+
this.criteriaThreeId = this.opts.criteriaThreeId;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Opciones por defecto
|
|
630
|
+
*/
|
|
631
|
+
defaults = {
|
|
632
|
+
allowedTags: [
|
|
633
|
+
"strong","span", "dl", "dt", "dd", "img", "em","button", "button",
|
|
634
|
+
"p", "div", "h3", "ul", "li", "time", "a", "h1"],
|
|
635
|
+
|
|
636
|
+
criteriaOneId: "destinatarios",
|
|
637
|
+
criteriaThreeId: "destacado",
|
|
638
|
+
criteriaTwoId: "url",
|
|
639
|
+
descriptionId: "descripcion",
|
|
640
|
+
categoryTitleClassList: ["h6", "text-secondary"],
|
|
641
|
+
itemContClassList: ["list-unstyled"],
|
|
642
|
+
itemClassList: ["m-b-2"],
|
|
643
|
+
dateSeparator: "/",
|
|
644
|
+
filterStatus: {
|
|
645
|
+
header: "Estado",
|
|
646
|
+
nextDates: "Próximas",
|
|
647
|
+
pastDates: "Anteriores",
|
|
648
|
+
},
|
|
649
|
+
endDateId: "hasta",
|
|
650
|
+
groupCategory: "filtro-ministerio",
|
|
651
|
+
rangeLabel: "Fechas",
|
|
652
|
+
startDateId: "desde",
|
|
653
|
+
timeId: "horario",
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Agrega los indices range y filtro-status al al array si no existieran.
|
|
659
|
+
*
|
|
660
|
+
* @param {object} options Opciones para ponchoTabla y Agenda
|
|
661
|
+
* @returns {object}
|
|
662
|
+
*/
|
|
663
|
+
_refactorHeadersOrder = options => {
|
|
664
|
+
if(options.hasOwnProperty("headersOrder") &&
|
|
665
|
+
options.headersOrder.length > 0){
|
|
666
|
+
let order = options.headersOrder;
|
|
667
|
+
for(const i of ["range", "filtro-status"]){
|
|
668
|
+
if(!options.headersOrder.includes(i)){
|
|
669
|
+
options.headersOrder.push(i);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return order;
|
|
673
|
+
}
|
|
674
|
+
return [];
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Mapea los headers.
|
|
679
|
+
*
|
|
680
|
+
* @return {string} key Key del item.
|
|
681
|
+
*/
|
|
682
|
+
_header = (key) => {
|
|
683
|
+
return (this.opts.headers.hasOwnProperty(key) ?
|
|
684
|
+
this.opts.headers[key] : key);
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Refactor de headers
|
|
689
|
+
*
|
|
690
|
+
* @summary Agrega los headers de range y filterheader a los
|
|
691
|
+
* asignados en el JSON.
|
|
692
|
+
* @param {object} options Opciones para ponchoTabla y Agenda
|
|
693
|
+
* @returns {object}
|
|
694
|
+
*/
|
|
695
|
+
_refactorHeaders = options => {
|
|
696
|
+
let labelStatus = this.defaults.filterStatus.header;
|
|
697
|
+
if(options?.filterStatus?.header){
|
|
698
|
+
labelStatus = options.filterStatus.header;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
let rangeLabel = this.defaults.rangeLabel;
|
|
702
|
+
if(options?.rangeLabel){
|
|
703
|
+
rangeLabel = options.rangeLabel;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const headers = {
|
|
707
|
+
...{ "range": rangeLabel},
|
|
708
|
+
...options.headers,
|
|
709
|
+
...{"filtro-status": labelStatus}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
return headers;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Showdown habilitado.
|
|
718
|
+
*
|
|
719
|
+
* Verifica si la librería _showdown_ está disponible.
|
|
720
|
+
* @returns {boolean}
|
|
721
|
+
*/
|
|
722
|
+
_isMarkdownEnable = () => {
|
|
723
|
+
if(typeof showdown !== "undefined" &&
|
|
724
|
+
showdown.hasOwnProperty("Converter")){
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
return false;
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Opciones para markdown
|
|
733
|
+
* @returns {object}
|
|
734
|
+
*/
|
|
735
|
+
_markdownOptions = () => {
|
|
736
|
+
if(this._isMarkdownEnable()){
|
|
737
|
+
if(this.opts.hasOwnProperty("markdownOptions") &&
|
|
738
|
+
typeof this.opts.markdownOptions === "object"){
|
|
739
|
+
return this.opts.markdownOptions;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return {};
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Convierte un string a markdown
|
|
748
|
+
*
|
|
749
|
+
* @param {string} str Cadena de texto a convertir
|
|
750
|
+
* @returns {string}
|
|
751
|
+
*/
|
|
752
|
+
_markdownConverter = str => {
|
|
753
|
+
if(this._isMarkdownEnable()){
|
|
754
|
+
const converter = new showdown.Converter(this._markdownOptions());
|
|
755
|
+
return converter.makeHtml(str);
|
|
756
|
+
}
|
|
757
|
+
return str;
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Fecha pasada
|
|
763
|
+
*
|
|
764
|
+
* @param {string} fecha Fecha a evaluar
|
|
765
|
+
* @returns {boolean}
|
|
766
|
+
*/
|
|
767
|
+
_isPastDate = fecha => {
|
|
768
|
+
if(!this._isValidDateFormat(fecha)){
|
|
769
|
+
console.error(`La fecha no tiene un formato válido: ${fecha}`);
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
const dateToEvaluate = this._dateParser(fecha).date.getTime();
|
|
774
|
+
const current = this._currentDate().date.getTime();
|
|
775
|
+
return current > dateToEvaluate;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Formato para fecha y hora
|
|
781
|
+
*
|
|
782
|
+
* @param {objecct} date Fecha como objeto {day, month, year}
|
|
783
|
+
* @param {object} time Tiempo como objeto {hours, minutes, seconds}
|
|
784
|
+
* @returns {string}
|
|
785
|
+
*/
|
|
786
|
+
_dateTimeFormat = (date, time=false) => {
|
|
787
|
+
const {day, month, year} = date;
|
|
788
|
+
const dateFormat = [day, month, year].join(this.dateSeparator);
|
|
789
|
+
let timeFormat = "";
|
|
790
|
+
if(time){
|
|
791
|
+
timeFormat = [hours, minutes].join(":");
|
|
792
|
+
}
|
|
793
|
+
return dateFormat + timeFormat;
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Fecha al momento de ejecutarse el script.
|
|
799
|
+
*
|
|
800
|
+
* @returns {object} Retorna un objeto con: el día, mes, año y el
|
|
801
|
+
* objeto Date en fecha.
|
|
802
|
+
*/
|
|
803
|
+
_currentDate = () => {
|
|
804
|
+
const today = new Date();
|
|
805
|
+
const year = today.getFullYear();
|
|
806
|
+
const month = today.getMonth() + 1;
|
|
807
|
+
const day = today.getDate();
|
|
808
|
+
const format = [
|
|
809
|
+
this._pad(day),
|
|
810
|
+
this._pad(month),
|
|
811
|
+
year].join(this.dateSeparator);
|
|
812
|
+
|
|
813
|
+
return {...this._dateParser(format), ...{format}};
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Rellena con ceros a la izquierda
|
|
818
|
+
*
|
|
819
|
+
* @param {string|int} num Numero a rellenar con ceros.
|
|
820
|
+
* @param {int} counter Cantidad total de caracteres.
|
|
821
|
+
* @returns {string}
|
|
822
|
+
*/
|
|
823
|
+
_pad = (num, counter=2) => num.toString().padStart(counter, "0");
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Parsea una fecha.
|
|
828
|
+
*
|
|
829
|
+
* @param {string} date Fecha en formato dd/mm/yyyy.
|
|
830
|
+
* @param {string} time Tiempo en formato hh:mm:ss
|
|
831
|
+
* @example
|
|
832
|
+
* // {
|
|
833
|
+
* // day: '09',
|
|
834
|
+
* // month: '05',
|
|
835
|
+
* // year: '2012',
|
|
836
|
+
* // hours: '00',
|
|
837
|
+
* // minutes: '00',
|
|
838
|
+
* // date: Wed May 09 2012 00:00:00 GMT-0300...
|
|
839
|
+
* // }
|
|
840
|
+
* this._dateParser("09/05/2012")
|
|
841
|
+
* @returns {object|boolean}
|
|
842
|
+
*/
|
|
843
|
+
_dateParser = (date, time="00:00:00") => {
|
|
844
|
+
if(!this._isValidDateFormat(date)){
|
|
845
|
+
console.error(`Formato de fecha incorrecto: ${date}`);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const regex = this.DATE_REGEX;
|
|
849
|
+
const result = regex.exec(date);
|
|
850
|
+
const [, day, month, year] = result;
|
|
851
|
+
const objectDate = new Date(`${year}-${month}-${day} ${time}`);
|
|
852
|
+
|
|
853
|
+
return {
|
|
854
|
+
day: this._pad(day),
|
|
855
|
+
month: this._pad(month),
|
|
856
|
+
year,
|
|
857
|
+
hours: this._pad(objectDate.getHours()),
|
|
858
|
+
minutes: this._pad(objectDate.getMinutes()),
|
|
859
|
+
"date": objectDate
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Valida el formato de la fecha.
|
|
866
|
+
* @summary El formato de fecha aceptado es: dd/mm/yyyy.
|
|
867
|
+
* Al momento de escribir este documento, no hay otro habilitado.
|
|
868
|
+
* @example
|
|
869
|
+
* // true
|
|
870
|
+
* this._isValidDateFormat("09/05/2012")
|
|
871
|
+
*
|
|
872
|
+
* // false
|
|
873
|
+
* this._isValidDateFormat("09/10/15")
|
|
874
|
+
* @param {string} str Fecha en formato dd/mm/yyyy.
|
|
875
|
+
* @returns {boolean}
|
|
876
|
+
*/
|
|
877
|
+
_isValidDateFormat = str => {
|
|
878
|
+
const regex = this.DATE_REGEX;
|
|
879
|
+
const result = regex.exec(str);
|
|
880
|
+
|
|
881
|
+
return (result !== null ? true : false);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Agrupa contenidos por fecha y la categoría asignada.
|
|
887
|
+
*
|
|
888
|
+
* @param {object} datos JSON a procesar
|
|
889
|
+
* @returns {object}
|
|
890
|
+
*/
|
|
891
|
+
_groupByFingerprintAndCategory = (datos) => {
|
|
892
|
+
const agrupados = {};
|
|
893
|
+
|
|
894
|
+
for (const dato of datos) {
|
|
895
|
+
const categoria = dato[this.groupCategory];
|
|
896
|
+
const {fingerprint} = dato;
|
|
897
|
+
if (!agrupados[fingerprint]) {
|
|
898
|
+
agrupados[fingerprint] = {};
|
|
899
|
+
}
|
|
900
|
+
if (!agrupados[fingerprint][categoria]) {
|
|
901
|
+
agrupados[fingerprint][categoria] = [];
|
|
902
|
+
}
|
|
903
|
+
agrupados[fingerprint][categoria].push(dato);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
return agrupados;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Rearmo el JSON para agregar filtros.
|
|
912
|
+
*
|
|
913
|
+
* @param {object} jsonData
|
|
914
|
+
* @returns {object}
|
|
915
|
+
*/
|
|
916
|
+
_refactorEntries = jsonData => {
|
|
917
|
+
if(!jsonData){
|
|
918
|
+
console.error("No se puede recorrer el script")
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
let entries = [];
|
|
922
|
+
jsonData.forEach(element => {
|
|
923
|
+
let desde = element[this.startDateId];
|
|
924
|
+
let hasta = element[this.endDateId];
|
|
925
|
+
// Si la columna `hasta` viene vacía le copio los datos de `desde`.
|
|
926
|
+
hasta = (hasta.trim() === "" ? desde : hasta);
|
|
927
|
+
|
|
928
|
+
const {pastDates, nextDates} = this.opts.filterStatus;
|
|
929
|
+
const estado = (this._isPastDate(hasta) ? pastDates : nextDates);
|
|
930
|
+
// dates
|
|
931
|
+
const startDate = this._dateParser(desde);
|
|
932
|
+
const endDate = this._dateParser(hasta);
|
|
933
|
+
const startDateTime = startDate.date.getTime();
|
|
934
|
+
const endDateTime = endDate.date.getTime();
|
|
935
|
+
const fingerprint = [startDateTime, endDateTime].join("_");
|
|
936
|
+
|
|
937
|
+
let range = this._dateTimeFormat(startDate);
|
|
938
|
+
if(startDateTime != endDateTime){
|
|
939
|
+
range = `Del ${this._dateTimeFormat(startDate)} al `
|
|
940
|
+
+ `${this._dateTimeFormat(endDate)}`;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// refactor entry
|
|
944
|
+
const entry = {
|
|
945
|
+
...element,
|
|
946
|
+
...{
|
|
947
|
+
"range": range,
|
|
948
|
+
"filtro-status": estado,
|
|
949
|
+
fingerprint,
|
|
950
|
+
desde,
|
|
951
|
+
hasta,
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
entries.push(entry);
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
return entries;
|
|
958
|
+
};
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Compone el template para el item de la agenda
|
|
963
|
+
*
|
|
964
|
+
* @param {string} description Descriptión del item de la agenda.
|
|
965
|
+
* @param {string} date Fecha formato dd/mm/yyyy
|
|
966
|
+
* @param {string} time Horario en formato hh:mm:ss
|
|
967
|
+
* @returns {object}
|
|
968
|
+
*/
|
|
969
|
+
itemTemplate = (description, destinatarios, url,
|
|
970
|
+
destacados, date, time) => {
|
|
971
|
+
const itemContainer = document.createElement("dl");
|
|
972
|
+
|
|
973
|
+
// time
|
|
974
|
+
let timeElement;
|
|
975
|
+
if(time){
|
|
976
|
+
const datetime = this._dateParser(date, time);
|
|
977
|
+
timeElement = document.createElement("time");
|
|
978
|
+
timeElement.setAttribute("datetime", datetime.date.toISOString());
|
|
979
|
+
timeElement.textContent = `${datetime.hours}:`
|
|
980
|
+
+ `${datetime.minutes}hs.`;
|
|
981
|
+
} else {
|
|
982
|
+
timeElement = document.createElement("span");
|
|
983
|
+
timeElement.textContent = "--:--";
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
const data = [
|
|
987
|
+
// Térm, definition, screenreader, dtoff, className
|
|
988
|
+
[
|
|
989
|
+
"Descripción",
|
|
990
|
+
this._markdownConverter(description),
|
|
991
|
+
true, true, "description"],
|
|
992
|
+
[
|
|
993
|
+
this._header(this.criteriaOneId),
|
|
994
|
+
this._markdownConverter(destinatarios),
|
|
995
|
+
false, true, "criteria-one"],
|
|
996
|
+
[
|
|
997
|
+
this._header(this.criteriaThreeId),
|
|
998
|
+
this._markdownConverter(destacados),
|
|
999
|
+
false, true, "criteria-three"],
|
|
1000
|
+
[
|
|
1001
|
+
this._header(this.criteriaTwoId),
|
|
1002
|
+
this._markdownConverter(url),
|
|
1003
|
+
false, true, "criteria-two"],
|
|
1004
|
+
[
|
|
1005
|
+
this._header(this.timeId),
|
|
1006
|
+
timeElement.outerHTML,
|
|
1007
|
+
false, true, "time"],
|
|
1008
|
+
];
|
|
1009
|
+
|
|
1010
|
+
data.forEach( elem => {
|
|
1011
|
+
const [term, definition, srOnly, dtOff, className] = elem;
|
|
1012
|
+
if(!definition){
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
const dt = document.createElement("dt");
|
|
1017
|
+
dt.textContent = term;
|
|
1018
|
+
dt.classList.add("agenda-item__dt", `agenda-item__dt-${className}`);
|
|
1019
|
+
if(srOnly){
|
|
1020
|
+
dt.classList.add("sr-only");
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
const dd = document.createElement("dd");
|
|
1024
|
+
dd.textContent = definition;
|
|
1025
|
+
dd.classList.add("agenda-item__dd", `agenda-item__dd-${className}`);
|
|
1026
|
+
|
|
1027
|
+
if(dtOff){
|
|
1028
|
+
itemContainer.appendChild(dt);
|
|
1029
|
+
}
|
|
1030
|
+
itemContainer.appendChild(dd);
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
if(this.itemClassList.some(f=>f)){
|
|
1034
|
+
itemContainer.classList.add("agenda-item", ...this.itemClassList);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
return itemContainer;
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Reagrupa las entradas dejando, por fecha, las entradas de la categoría.
|
|
1043
|
+
*
|
|
1044
|
+
* @param {object} entries
|
|
1045
|
+
* @returns {object}
|
|
1046
|
+
*/
|
|
1047
|
+
_groupedEntries = entries => {
|
|
1048
|
+
let collect = [];
|
|
1049
|
+
// Nivel mismas fechas
|
|
1050
|
+
Object.values(entries).forEach(ele => {
|
|
1051
|
+
var entry;
|
|
1052
|
+
|
|
1053
|
+
// Nivel ministerio
|
|
1054
|
+
// Cada iteración es un ministerio.
|
|
1055
|
+
Object.values(ele).forEach((element) => {
|
|
1056
|
+
var block = "";
|
|
1057
|
+
var title = "";
|
|
1058
|
+
|
|
1059
|
+
const itemsContainer = document.createElement("div");
|
|
1060
|
+
if(this.itemContClassList.some(f=>f)){
|
|
1061
|
+
itemsContainer.classList.add(...this.itemContClassList);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// Nivel items por ministerio
|
|
1065
|
+
element.forEach(a => {
|
|
1066
|
+
entry = a;
|
|
1067
|
+
if(title != entry[this.groupCategory]){
|
|
1068
|
+
title = entry[this.groupCategory];
|
|
1069
|
+
|
|
1070
|
+
const titleElement = document.createElement("p");
|
|
1071
|
+
if(this.categoryTitleClassList.some(f=>f)){
|
|
1072
|
+
titleElement.classList.add(
|
|
1073
|
+
...this.categoryTitleClassList);
|
|
1074
|
+
titleElement.textContent = title;
|
|
1075
|
+
itemsContainer.appendChild(titleElement);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
const item = this.itemTemplate(
|
|
1080
|
+
a.descripcion, a.destinatarios, a.url,
|
|
1081
|
+
a.destacados, a.desde, a.horario);
|
|
1082
|
+
itemsContainer.appendChild(item);
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
block += itemsContainer.outerHTML;
|
|
1086
|
+
delete entry.fingerprint;
|
|
1087
|
+
let customData={};
|
|
1088
|
+
|
|
1089
|
+
customData[this.descriptionId] = block;
|
|
1090
|
+
collect.push( {...entry, ...customData} );
|
|
1091
|
+
});
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
return collect;
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Valida si poncho tabla está importado
|
|
1100
|
+
* @returns {boolean}
|
|
1101
|
+
*/
|
|
1102
|
+
_ponchoTableExists = () => {
|
|
1103
|
+
if(typeof ponchoTable !== "undefined"){
|
|
1104
|
+
return true;
|
|
1105
|
+
}
|
|
1106
|
+
return false;
|
|
1107
|
+
};
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Imprime la tabla ponchoTable
|
|
1112
|
+
*
|
|
1113
|
+
* @returns {undefined}
|
|
1114
|
+
*/
|
|
1115
|
+
render = () => {
|
|
1116
|
+
if(!this.opts.hasOwnProperty("jsonData")){
|
|
1117
|
+
console.error(
|
|
1118
|
+
"¡Hay un error en los datos pasados "
|
|
1119
|
+
+ "a la función `PonchoAgenda`!");
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
const refactorEntries = this._refactorEntries(this.opts.jsonData);
|
|
1124
|
+
const groupedByDateAndCategory =
|
|
1125
|
+
this._groupByFingerprintAndCategory(refactorEntries);
|
|
1126
|
+
this.opts.jsonData = this._groupedEntries(groupedByDateAndCategory);
|
|
1127
|
+
|
|
1128
|
+
if(this._ponchoTableExists()){
|
|
1129
|
+
ponchoTable( this.opts );
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
if (typeof exports !== "undefined") {
|
|
1136
|
+
module.exports = PonchoAgenda;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* PONCHO TABLE
|
|
1141
|
+
*
|
|
1142
|
+
* @summary PonchoTable con filtros dependientes
|
|
1143
|
+
*
|
|
1144
|
+
* @author Agustín Bouillet <bouilleta@jefatura.gob.ar>
|
|
1145
|
+
* @requires jQuery
|
|
1146
|
+
* @see https://github.com/argob/poncho/blob/master/src/demo/poncho-maps/readme-poncho-maps.md
|
|
1147
|
+
* @see https://datatables.net
|
|
1148
|
+
*
|
|
1149
|
+
*
|
|
1150
|
+
* MIT License
|
|
1151
|
+
*
|
|
1152
|
+
* Copyright (c) 2022 Argentina.gob.ar
|
|
1153
|
+
*
|
|
1154
|
+
* Permission is hereby granted, free of charge, to any person
|
|
1155
|
+
* obtaining a copy of this software and associated documentation
|
|
1156
|
+
* files (the "Software"), to deal in the Software without restriction,
|
|
1157
|
+
* including without limitation the rightsto use, copy, modify, merge,
|
|
1158
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
1159
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
1160
|
+
* subject to the following conditions:
|
|
1161
|
+
*
|
|
1162
|
+
* The above copyright notice and this permission notice shall be
|
|
1163
|
+
* included in all copies or substantial portions of the Software.
|
|
1164
|
+
*
|
|
1165
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
1166
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
1167
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
1168
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
1169
|
+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
1170
|
+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
1171
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1172
|
+
* SOFTWARE.
|
|
1173
|
+
*/
|
|
1174
|
+
const ponchoTableDependant = opt => {
|
|
1175
|
+
var gapi_data;
|
|
1176
|
+
var filtersList = [];
|
|
1177
|
+
var wizard = (opt.hasOwnProperty("wizard") && opt.wizard ?
|
|
1178
|
+
true : false);
|
|
1179
|
+
var emptyLabel = (opt.hasOwnProperty("emptyLabel") && opt.emptyLabel ?
|
|
1180
|
+
opt.emptyLabel : "Todos");
|
|
1181
|
+
var filtro = {};
|
|
1182
|
+
var orderFilter = (opt.hasOwnProperty("orderFilter") && opt.orderFilter ?
|
|
1183
|
+
true : false);
|
|
1184
|
+
var asFilter = {};
|
|
1185
|
+
var allowedTags = ["*"];
|
|
1186
|
+
let markdownOptions = {
|
|
1187
|
+
"tables": true,
|
|
1188
|
+
"simpleLineBreaks": true,
|
|
1189
|
+
"extensions": [
|
|
1190
|
+
"details",
|
|
1191
|
+
"images",
|
|
1192
|
+
"alerts",
|
|
1193
|
+
"numbers",
|
|
1194
|
+
"ejes",
|
|
1195
|
+
"button",
|
|
1196
|
+
"target",
|
|
1197
|
+
"bootstrap-tables",
|
|
1198
|
+
"video"
|
|
1199
|
+
]
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
// Loader
|
|
1203
|
+
document.querySelector("#ponchoTable").classList.add("state-loading");
|
|
1204
|
+
|
|
1205
|
+
if (jQuery.fn.DataTable.isDataTable("#ponchoTable")) {
|
|
1206
|
+
jQuery("#ponchoTable").DataTable().destroy();
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* Ordena alfanuméricamente
|
|
1212
|
+
* @example
|
|
1213
|
+
* // ["Arroz", "zorro"]
|
|
1214
|
+
* ["zorro", "Arroz"].sort(_sortAlphaNumeric)
|
|
1215
|
+
* @return {object}
|
|
1216
|
+
*/
|
|
1217
|
+
const sortAlphaNumeric = (a, b) => {
|
|
1218
|
+
return a.toString().localeCompare(b.toString(), "es", {numeric: true});
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* De acuerdo a las opciones del usuario, ordena el listado o lo deja
|
|
1224
|
+
* en la secuencia en la que llega.
|
|
1225
|
+
*
|
|
1226
|
+
* @summary Alias de sortAlphaNumeric
|
|
1227
|
+
* @param {object} a
|
|
1228
|
+
* @param {object} b
|
|
1229
|
+
* @returns {object}
|
|
1230
|
+
*/
|
|
1231
|
+
const _sortAlphaNumeric = (a, b) => (orderFilter ?
|
|
1232
|
+
sortAlphaNumeric(a, b) : null);
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* Resultados únicos
|
|
1237
|
+
*
|
|
1238
|
+
* @param {object} list Array del que se quiere obtener
|
|
1239
|
+
* resultados únicos.
|
|
1240
|
+
* @returns {object}
|
|
1241
|
+
*/
|
|
1242
|
+
const distinct = list => [... new Set(list)];
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* Select option
|
|
1247
|
+
*
|
|
1248
|
+
* @summary Crea un tag _option_ para un _select_.
|
|
1249
|
+
* @param {integer} parent Índice según el listado de filtros.
|
|
1250
|
+
* @param {string} label Valor para el label o texto visible.
|
|
1251
|
+
* @param {string} value Valor para el attributo _value_.
|
|
1252
|
+
* @param {boolean} selected Si el item debe mostrarse seleccionado.
|
|
1253
|
+
* @return {object}
|
|
1254
|
+
*/
|
|
1255
|
+
const _optionSelect = (parent=0, label, value, selected=false) => {
|
|
1256
|
+
var select_option = document.createElement("option");
|
|
1257
|
+
select_option.value = value.toString().trim();
|
|
1258
|
+
select_option.dataset.column = parent;
|
|
1259
|
+
select_option.textContent = label.toString().trim();
|
|
1260
|
+
if(selected){
|
|
1261
|
+
select_option.setAttribute("selected", "selected");
|
|
1262
|
+
}
|
|
1263
|
+
return select_option;
|
|
1264
|
+
};
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* Prepara el término para ser buscado por REGEX
|
|
1269
|
+
*
|
|
1270
|
+
* @summary Escapa caracteres especiales utilizados en la sintáxis
|
|
1271
|
+
* de expresiones regulares.
|
|
1272
|
+
* @see replaceSpecialChars() en poncho.min.js
|
|
1273
|
+
* @param {string} term Término a buscar.
|
|
1274
|
+
* @example
|
|
1275
|
+
* // return Simbrón \(3\.180\)
|
|
1276
|
+
* _searchTerm("Simbrón (3.180)")
|
|
1277
|
+
* @return {string}
|
|
1278
|
+
*/
|
|
1279
|
+
const _searchTerm = (term="") => {
|
|
1280
|
+
return term.toString().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1281
|
+
};
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* Evita un valor negativo
|
|
1286
|
+
*/
|
|
1287
|
+
const _parentElement = value => (value <= 0 ? 0 : value);
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* Retorna los valores de los filtros
|
|
1292
|
+
*/
|
|
1293
|
+
const _filterValues = () => {
|
|
1294
|
+
return [...document.querySelectorAll("[data-filter]")]
|
|
1295
|
+
.map(e => e.value);
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Showdown habilitado.
|
|
1301
|
+
*
|
|
1302
|
+
* Verifica si la librería _showdown_ está disponible.
|
|
1303
|
+
* @returns {boolean}
|
|
1304
|
+
*/
|
|
1305
|
+
const _isMarkdownEnable = () => {
|
|
1306
|
+
if(typeof showdown !== "undefined" &&
|
|
1307
|
+
showdown.hasOwnProperty("Converter")){
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1310
|
+
return false;
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Verifica si las extensiones showdown están definidas.
|
|
1316
|
+
*
|
|
1317
|
+
* @param {object} extensions
|
|
1318
|
+
* @returns {boolean}
|
|
1319
|
+
*/
|
|
1320
|
+
const _isShowdownExtensionEnable = () => {
|
|
1321
|
+
const markdownOptions = _markdownOptions();
|
|
1322
|
+
const r = markdownOptions.extensions.every(e => {
|
|
1323
|
+
try {
|
|
1324
|
+
showdown.extension(e);
|
|
1325
|
+
return true;
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
return r;
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Opciones para el componente showdonwjs
|
|
1336
|
+
*
|
|
1337
|
+
* @summary Si el usuario asigno opciones y extensiones, las usa; de otro
|
|
1338
|
+
* modo, usa las que están por defecto.
|
|
1339
|
+
* @returns {object}
|
|
1340
|
+
*/
|
|
1341
|
+
const _markdownOptions = () => {
|
|
1342
|
+
if(opt.hasOwnProperty("markdownOptions") &&
|
|
1343
|
+
opt.markdownOptions === "object"){
|
|
1344
|
+
return opt.markdownOptions;
|
|
1345
|
+
}
|
|
1346
|
+
return markdownOptions;
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* Convierte un string con sintaxis markdown
|
|
1352
|
+
* @param {stirng} str Cadena de texto a convertir
|
|
1353
|
+
* @returns {string}
|
|
1354
|
+
*/
|
|
1355
|
+
const _markdownConvert = str => {
|
|
1356
|
+
if( typeof str !== "string" ){
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
if( !_isMarkdownEnable() ){
|
|
1360
|
+
return str;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
let converter;
|
|
1364
|
+
if(_isShowdownExtensionEnable()){
|
|
1365
|
+
converter = new showdown.Converter( _markdownOptions() );
|
|
1366
|
+
return converter.makeHtml(str);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
converter = new showdown.Converter();
|
|
1370
|
+
return converter.makeHtml(str);
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Botón poncho
|
|
1376
|
+
*
|
|
1377
|
+
* @summary Imprime un botón bootstrap.
|
|
1378
|
+
* @param {string} label Label para el botón.
|
|
1379
|
+
* @param {string} value Href para el botón
|
|
1380
|
+
* @return {undefined}
|
|
1381
|
+
*/
|
|
1382
|
+
const button = (label, value) => {
|
|
1383
|
+
const btn = document.createElement("a");
|
|
1384
|
+
btn.setAttribute("aria-label", label);
|
|
1385
|
+
btn.classList.add(
|
|
1386
|
+
"btn", "btn-primary", "btn-sm", "margin-btn");
|
|
1387
|
+
btn.target = "_blank";
|
|
1388
|
+
btn.href = value;
|
|
1389
|
+
btn.textContent = label;
|
|
1390
|
+
btn.setAttribute("rel", "noopener noreferrer");
|
|
1391
|
+
return btn.outerHTML;
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Formato de fecha
|
|
1397
|
+
*
|
|
1398
|
+
* @summary Agrega una etiqueta datetime para mejorar la indexación
|
|
1399
|
+
* y el ordenamiento.
|
|
1400
|
+
* @return {undefined}
|
|
1401
|
+
*/
|
|
1402
|
+
const tdDate = value => {
|
|
1403
|
+
const dateSplit = value.split("/");
|
|
1404
|
+
const finalDateIso = new Date(
|
|
1405
|
+
dateSplit[2], dateSplit[1] - 1, dateSplit[0]
|
|
1406
|
+
);
|
|
1407
|
+
|
|
1408
|
+
const datetime = finalDateIso.toISOString().split("T")[0];
|
|
1409
|
+
|
|
1410
|
+
const hiddenSpan = document.createElement("span");
|
|
1411
|
+
hiddenSpan.style.display = "none";
|
|
1412
|
+
hiddenSpan.textContent = datetime;
|
|
1413
|
+
|
|
1414
|
+
const time = document.createElement("time");
|
|
1415
|
+
time.setAttribute("datetime", datetime);
|
|
1416
|
+
time.textContent = value;
|
|
1417
|
+
|
|
1418
|
+
return hiddenSpan.outerHTML + time.outerHTML;
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Imprime los filtros
|
|
1424
|
+
*
|
|
1425
|
+
* @param {object} gapi_data Objeto con la información separada del
|
|
1426
|
+
* documento Google Sheet
|
|
1427
|
+
*/
|
|
1428
|
+
const _createFilters = gapi_data => {
|
|
1429
|
+
// Contenedor
|
|
1430
|
+
const tableFiltroCont = document.querySelector("#ponchoTableFiltro");
|
|
1431
|
+
tableFiltroCont.innerHTML = "";
|
|
1432
|
+
|
|
1433
|
+
// Imprime cada uno de los filtros
|
|
1434
|
+
Object.keys(filtro).forEach((f, key) => {
|
|
1435
|
+
const columna = filtro[f][0].columna ? filtro[f][0].columna : 0;
|
|
1436
|
+
const list_filter = filtro[f]
|
|
1437
|
+
.map(e => e.value)
|
|
1438
|
+
.sort(_sortAlphaNumeric);
|
|
1439
|
+
|
|
1440
|
+
const tplCol = document.createElement("div");
|
|
1441
|
+
|
|
1442
|
+
if(opt.hasOwnProperty("filterClassList")){
|
|
1443
|
+
const classList = (typeof opt.filterClassList === "string" ?
|
|
1444
|
+
opt.filterClassList.split(" ") : opt.filterClassList);
|
|
1445
|
+
tplCol.classList.add(...classList);
|
|
1446
|
+
} else {
|
|
1447
|
+
const cols = Math.floor(12 / Object.keys(filtro).length);
|
|
1448
|
+
tplCol.classList.add("col-sm-12", `col-md-${cols}`);
|
|
1449
|
+
}
|
|
1450
|
+
tplCol.dataset.index = key;
|
|
1451
|
+
tplCol.dataset.filterName = f;
|
|
1452
|
+
|
|
1453
|
+
// If wizzard
|
|
1454
|
+
if(wizard && key > 0){
|
|
1455
|
+
tplCol.style.display = "none";
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
const tplForm = document.createElement("div");
|
|
1459
|
+
tplForm.className = "form-group";
|
|
1460
|
+
|
|
1461
|
+
const formLabel = document.createElement("label");
|
|
1462
|
+
formLabel.setAttribute("for", f);
|
|
1463
|
+
formLabel.textContent = gapi_data.headers[`filtro-${f}`];
|
|
1464
|
+
|
|
1465
|
+
const select = document.createElement("select");
|
|
1466
|
+
select.classList.add("form-control");
|
|
1467
|
+
select.dataset.filter = 1;
|
|
1468
|
+
select.name = f;
|
|
1469
|
+
select.id = f;
|
|
1470
|
+
select.appendChild(_optionSelect(columna, emptyLabel, "", true));
|
|
1471
|
+
list_filter.forEach(item => {
|
|
1472
|
+
if(!item){
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
select.appendChild(_optionSelect(columna, item, item, false));
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
tplForm.appendChild(formLabel);
|
|
1479
|
+
tplForm.appendChild(select);
|
|
1480
|
+
tplCol.appendChild(tplForm);
|
|
1481
|
+
tableFiltroCont.appendChild(tplCol);
|
|
1482
|
+
// }
|
|
1483
|
+
});
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Imprime la tabla
|
|
1489
|
+
*
|
|
1490
|
+
* @param {object} gapi_data Objeto con la información separada del
|
|
1491
|
+
* documento Google Sheet
|
|
1492
|
+
*/
|
|
1493
|
+
const _createTable = gapi_data => {
|
|
1494
|
+
// Table thead > th
|
|
1495
|
+
const thead = document.querySelector("#ponchoTable thead");
|
|
1496
|
+
thead.innerHTML = "";
|
|
1497
|
+
|
|
1498
|
+
const theadTr = document.createElement("tr");
|
|
1499
|
+
Object.keys(gapi_data.headers).forEach((header, key) => {
|
|
1500
|
+
const th = document.createElement("th");
|
|
1501
|
+
th.textContent = gapi_data.headers[header];
|
|
1502
|
+
th.setAttribute("scope", "col");
|
|
1503
|
+
theadTr.appendChild(th);
|
|
1504
|
+
});
|
|
1505
|
+
thead.appendChild(theadTr);
|
|
1506
|
+
|
|
1507
|
+
// Table caption
|
|
1508
|
+
const tableCaption = document.querySelector("#ponchoTable caption");
|
|
1509
|
+
tableCaption.innerHTML = "";
|
|
1510
|
+
tableCaption.textContent = opt.tituloTabla;
|
|
1511
|
+
|
|
1512
|
+
// Tbody instance
|
|
1513
|
+
const tableTbody = document.querySelector("#ponchoTable tbody");
|
|
1514
|
+
tableTbody.innerHTML = "";
|
|
1515
|
+
|
|
1516
|
+
// CONTENIDO FILAS
|
|
1517
|
+
gapi_data.entries.forEach((entry, key) => {
|
|
1518
|
+
|
|
1519
|
+
if(!Object.values(entry).some(f => String(f).trim())){
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// si se desea modificar la entrada desde opciones
|
|
1524
|
+
entry = (typeof opt.customEntry === "function" &&
|
|
1525
|
+
opt.customEntry !== null ? opt.customEntry(entry) : entry);
|
|
1526
|
+
|
|
1527
|
+
// Inserta el row.
|
|
1528
|
+
const tbodyRow = tableTbody.insertRow();
|
|
1529
|
+
tbodyRow.id = "id_" + key;
|
|
1530
|
+
|
|
1531
|
+
// Recorro cada uno de los títulos
|
|
1532
|
+
Object.keys(gapi_data.headers).forEach(header => {
|
|
1533
|
+
let filas = entry[header];
|
|
1534
|
+
|
|
1535
|
+
if (header.startsWith("btn-") && filas != "") {
|
|
1536
|
+
const label = header.replace("btn-", "").replace("-", " ");
|
|
1537
|
+
filas = button(label, filas);
|
|
1538
|
+
} else if (header.startsWith("fecha-") && filas != "") {
|
|
1539
|
+
filas = tdDate(filas);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
const cell = tbodyRow.insertCell();
|
|
1543
|
+
cell.dataset.title = gapi_data.headers[header];
|
|
1544
|
+
if (filas == ""){
|
|
1545
|
+
cell.className = "hidden-xs";
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// Si showdown está incluido lo uso
|
|
1549
|
+
// @todo Usar showdown fuera de la función. Usarlo en options.
|
|
1550
|
+
let allowed_tags = (opt.hasOwnProperty("allowedTags") ?
|
|
1551
|
+
opt.allowedTags : allowedTags);
|
|
1552
|
+
|
|
1553
|
+
// Las etiquetas `<a>` y `<time>` junto con `<span>`, están
|
|
1554
|
+
// permitidas si existen los prefijos _btn-_ y _fecha-_
|
|
1555
|
+
// respectivamente.
|
|
1556
|
+
if(header.startsWith("btn-") && filas != ""){
|
|
1557
|
+
allowed_tags = [...allowed_tags, "a"];
|
|
1558
|
+
} else if(header.startsWith("fecha-") && filas != ""){
|
|
1559
|
+
allowed_tags = [...allowed_tags, "span", "time"];
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
const cleannedText = secureHTML(filas, allowed_tags);
|
|
1563
|
+
if(_isMarkdownEnable()){
|
|
1564
|
+
cell.innerHTML = _markdownConvert(cleannedText);
|
|
1565
|
+
} else {
|
|
1566
|
+
cell.innerHTML = cleannedText;
|
|
1567
|
+
}
|
|
1568
|
+
});
|
|
1569
|
+
});
|
|
1570
|
+
};
|
|
1571
|
+
|
|
1572
|
+
|
|
1573
|
+
/**
|
|
1574
|
+
* Matriz filtro
|
|
1575
|
+
*
|
|
1576
|
+
* @summary Reune los filtros y por cada uno de ellos guarda los
|
|
1577
|
+
* datos —únicos—, de esa entrada.
|
|
1578
|
+
* @param {object} gapi_data Objeto con la información separada del
|
|
1579
|
+
* documento Google Sheet
|
|
1580
|
+
* @example
|
|
1581
|
+
* {
|
|
1582
|
+
* nombre_filtro : [
|
|
1583
|
+
* {
|
|
1584
|
+
* columna: 0,
|
|
1585
|
+
* value: "elemento"
|
|
1586
|
+
* },
|
|
1587
|
+
* ...
|
|
1588
|
+
* ]
|
|
1589
|
+
* }
|
|
1590
|
+
* @return {object}
|
|
1591
|
+
*/
|
|
1592
|
+
const flterMatrix = (gapi_data, filtersList) => {
|
|
1593
|
+
let filters = {};
|
|
1594
|
+
filtersList.forEach((filter, key) => {
|
|
1595
|
+
let entiresByFilter = [];
|
|
1596
|
+
if(asFilter.hasOwnProperty(filtersList[key])){
|
|
1597
|
+
entiresByFilter = asFilter[filtersList[key]];
|
|
1598
|
+
} else {
|
|
1599
|
+
entiresByFilter = gapi_data.entries.map(entry => entry[filter]);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
const uniqueEntries = distinct(entiresByFilter);
|
|
1603
|
+
uniqueEntries.sort(_sortAlphaNumeric);
|
|
1604
|
+
filter = filter.replace("filtro-", "");
|
|
1605
|
+
filters[filter] = [];
|
|
1606
|
+
uniqueEntries.forEach(entry => {
|
|
1607
|
+
filters[filter].push({"columna": key, "value": entry});
|
|
1608
|
+
});
|
|
1609
|
+
});
|
|
1610
|
+
return filters;
|
|
1611
|
+
};
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
/* HELPERS FILTRO DEPENDIENTE */
|
|
1615
|
+
/**
|
|
1616
|
+
* Valida los parents
|
|
1617
|
+
*
|
|
1618
|
+
* @param {integer} parent Índice (filtro) seleccionado.
|
|
1619
|
+
* @return {boolean}
|
|
1620
|
+
*/
|
|
1621
|
+
const _validateSteps = (parent, entry, label, values) => {
|
|
1622
|
+
// Verifico que por cada entrada el valor(label), se
|
|
1623
|
+
// encuentre en cada uno de los parents.
|
|
1624
|
+
// El bucle termina cuando llega al índice seleccionado.
|
|
1625
|
+
const range = [...Array(_parentElement(parent + 1)).keys()];
|
|
1626
|
+
const results = range.map(i => {
|
|
1627
|
+
// Chequeo si el valor del select es igual al parent o
|
|
1628
|
+
// si en su defecto, está vacío.
|
|
1629
|
+
if(
|
|
1630
|
+
(
|
|
1631
|
+
(entry[filtersList[_parentElement(parent-1)]] ==
|
|
1632
|
+
values[_parentElement(parent-1)]) &&
|
|
1633
|
+
(entry[filtersList[_parentElement(parent)]] == label)
|
|
1634
|
+
) || values[_parentElement(parent-1)] == "")
|
|
1635
|
+
{
|
|
1636
|
+
return true;
|
|
1637
|
+
}
|
|
1638
|
+
return false;
|
|
1639
|
+
});
|
|
1640
|
+
return results.every(e => e);
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Trae todos los elementos de un filtro en base a su parent.
|
|
1646
|
+
*
|
|
1647
|
+
* @param {integer} parent Indice de filtro seleccionado.
|
|
1648
|
+
* @param {integer} children Indice del hijo del seleccionado.
|
|
1649
|
+
* @param {string} label value del filtro seleccionado.
|
|
1650
|
+
* @return {object} Listado de elementos únicos para el select.
|
|
1651
|
+
*/
|
|
1652
|
+
const _allFromParent = (parent, children, label) => {
|
|
1653
|
+
const filterList = gapi_data.entries.flatMap(e => {
|
|
1654
|
+
const evaluatedEntry = e[filtersList[_parentElement(children)]];
|
|
1655
|
+
if(e[filtersList[_parentElement(parent)]] == label || label == ""){
|
|
1656
|
+
if(_isCustomFilter(children, filtro)){
|
|
1657
|
+
const customFilters = _customFilter(children, filtro)
|
|
1658
|
+
.filter(e => {
|
|
1659
|
+
return _toCompareString(evaluatedEntry)
|
|
1660
|
+
.includes(_toCompareString(e));
|
|
1661
|
+
});
|
|
1662
|
+
return customFilters;
|
|
1663
|
+
}
|
|
1664
|
+
return evaluatedEntry;
|
|
1665
|
+
}
|
|
1666
|
+
return false;
|
|
1667
|
+
|
|
1668
|
+
}).filter(f => f);
|
|
1669
|
+
|
|
1670
|
+
const uniqueList = distinct(filterList);
|
|
1671
|
+
uniqueList.sort(_sortAlphaNumeric);
|
|
1672
|
+
return uniqueList;
|
|
1673
|
+
};
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
/**
|
|
1677
|
+
* Prepara un string para una comparación case sensitive y sin
|
|
1678
|
+
* caracteres especiales.
|
|
1679
|
+
* @param {string} value Valor a comparar.
|
|
1680
|
+
* @returns {boolean}
|
|
1681
|
+
*/
|
|
1682
|
+
const _toCompareString = value => replaceSpecialChars(value.toLowerCase());
|
|
1683
|
+
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* Lista los valores que deben ir en un filtro según su parent.
|
|
1687
|
+
*
|
|
1688
|
+
* @param {integer} parent Indice de filtro seleccionado.
|
|
1689
|
+
* @param {string} label value del filtro seleccionado.
|
|
1690
|
+
* @param {integer} children Indice del hijo del seleccionado.
|
|
1691
|
+
*/
|
|
1692
|
+
const _filterOptionList = (parent, children, label) => {
|
|
1693
|
+
children = (children == filtersList.length ? children - 1 : children);
|
|
1694
|
+
const values = _filterValues();
|
|
1695
|
+
|
|
1696
|
+
// Recorro todas las entradas del JSON
|
|
1697
|
+
const items = gapi_data.entries.flatMap(entry => {
|
|
1698
|
+
const range = _validateSteps(parent, entry, label, values);
|
|
1699
|
+
if(
|
|
1700
|
+
(entry[filtersList[_parentElement(children - 1)]] == label) &&
|
|
1701
|
+
(range)){
|
|
1702
|
+
const evaluatedEntry = entry[filtersList[_parentElement(children)]];
|
|
1703
|
+
if(_isCustomFilter(children, filtro)){
|
|
1704
|
+
const customFilters = _customFilter(children, filtro)
|
|
1705
|
+
.filter(e => {
|
|
1706
|
+
return _toCompareString(evaluatedEntry)
|
|
1707
|
+
.includes(_toCompareString(e));
|
|
1708
|
+
});
|
|
1709
|
+
return customFilters;
|
|
1710
|
+
} else {
|
|
1711
|
+
return evaluatedEntry;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
}
|
|
1715
|
+
return;
|
|
1716
|
+
}).filter(f => f);
|
|
1717
|
+
|
|
1718
|
+
const uniqueList = distinct(items);
|
|
1719
|
+
uniqueList.sort(_sortAlphaNumeric);
|
|
1720
|
+
return uniqueList;
|
|
1721
|
+
};
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Tiene filtros personalizados
|
|
1726
|
+
* @param {integer} key Indice de filtro
|
|
1727
|
+
* @returns {boolean}
|
|
1728
|
+
*/
|
|
1729
|
+
const _isCustomFilter = key => {
|
|
1730
|
+
const filtersKeys = Object.keys(filtro);
|
|
1731
|
+
if(asFilter.hasOwnProperty(`filtro-${filtersKeys[key]}`)){
|
|
1732
|
+
return true
|
|
1733
|
+
}
|
|
1734
|
+
return false;
|
|
1735
|
+
};
|
|
1736
|
+
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* Listado de filtros personalizado
|
|
1740
|
+
* @param {integer} key Indice de filtro
|
|
1741
|
+
* @returns {object}
|
|
1742
|
+
*/
|
|
1743
|
+
const _customFilter = key => {
|
|
1744
|
+
const filtersKeys = Object.keys(filtro);
|
|
1745
|
+
if(asFilter.hasOwnProperty(`filtro-${filtersKeys[key]}`)){
|
|
1746
|
+
return asFilter[`filtro-${filtersKeys[key]}`];
|
|
1747
|
+
}
|
|
1748
|
+
return [];
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* Filtra select hijos en base a un item del padre.
|
|
1754
|
+
*
|
|
1755
|
+
* @param {integer} filterIndex Índice de filtro o número de filtro.
|
|
1756
|
+
* @param {string} label Label del indice seleccionado
|
|
1757
|
+
* @return {void}
|
|
1758
|
+
*/
|
|
1759
|
+
const _dependantFilters = (filterIndex, label) => {
|
|
1760
|
+
const filtros = Object.keys(filtro);
|
|
1761
|
+
const filterValues = _filterValues();
|
|
1762
|
+
// Redibujo los _option_ por cada `select` (filtro).
|
|
1763
|
+
// Hago un `for()` iniciando en el hijo de filterIndex.
|
|
1764
|
+
for(let i = filterIndex + 1; i <= filtros.length; i++){
|
|
1765
|
+
if(filtros.length == i ){
|
|
1766
|
+
break;
|
|
1767
|
+
}
|
|
1768
|
+
let itemList = _filterOptionList(filterIndex, i, label);
|
|
1769
|
+
if(itemList.length == 0){
|
|
1770
|
+
itemList = _allFromParent(filterIndex, i, label);
|
|
1771
|
+
}
|
|
1772
|
+
const select = document.querySelector(`#${filtros[i]}`);
|
|
1773
|
+
select.innerHTML = "";
|
|
1774
|
+
|
|
1775
|
+
select.appendChild(_optionSelect(i, emptyLabel, "", true));
|
|
1776
|
+
itemList.forEach(e => {
|
|
1777
|
+
if(!e.trim()){
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
// Mantengo el filtro del hijo si existe en el
|
|
1781
|
+
// listado filtrado.
|
|
1782
|
+
let checked = (filterValues[i] == e ? true : false);
|
|
1783
|
+
select.appendChild(_optionSelect(i, e, e, checked));
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* Asigna selectores al contenedor de los filtros.
|
|
1791
|
+
* @returns {undefined}
|
|
1792
|
+
*/
|
|
1793
|
+
const _filtersContainerClassList = () =>{
|
|
1794
|
+
if(opt.hasOwnProperty("filterContClassList") && opt.filterContClassList){
|
|
1795
|
+
const fc = document.getElementById("ponchoTableFiltroCont");
|
|
1796
|
+
fc.removeAttribute("class");
|
|
1797
|
+
fc.classList.add(...opt.filterContClassList);
|
|
1798
|
+
}
|
|
1799
|
+
};
|
|
1800
|
+
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* Asigna selectores al contenedor del buscador.
|
|
1804
|
+
* @returns {undefined}
|
|
1805
|
+
*/
|
|
1806
|
+
const _searchContainerClassList = () =>{
|
|
1807
|
+
if(opt.hasOwnProperty("searchContClassList") && opt.searchContClassList){
|
|
1808
|
+
const element = document.getElementById("ponchoTableSearchCont");
|
|
1809
|
+
element.removeAttribute("class");
|
|
1810
|
+
element.classList.add(...opt.searchContClassList)
|
|
1811
|
+
}
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
* Si la URL tiene un valor por _hash_ lo obtiene considerandolo su id.
|
|
1817
|
+
* @returns {void}
|
|
1818
|
+
*/
|
|
1819
|
+
const hasHash = () => {
|
|
1820
|
+
let hash = window.location.hash.replace("#", "");
|
|
1821
|
+
return hash || false;
|
|
1822
|
+
};
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
/**
|
|
1826
|
+
* Visualización de la tabla
|
|
1827
|
+
*
|
|
1828
|
+
* @param {boolean} visibility Oculta y muestra la tabla.
|
|
1829
|
+
* @returns {undefined}
|
|
1830
|
+
*/
|
|
1831
|
+
_hideTable = (visibility=true) => {
|
|
1832
|
+
const display = (visibility ? "none" : "block");
|
|
1833
|
+
const reverseDisplay = (visibility ? "block" : "none");
|
|
1834
|
+
document
|
|
1835
|
+
.querySelectorAll(
|
|
1836
|
+
`[data-visible-as-table="true"],#ponchoTable_wrapper`)
|
|
1837
|
+
.forEach(element => element.style.display = display);
|
|
1838
|
+
|
|
1839
|
+
document
|
|
1840
|
+
.querySelectorAll(`[data-visible-as-table="false"]`)
|
|
1841
|
+
.forEach(element => element.style.display = reverseDisplay);
|
|
1842
|
+
};
|
|
1843
|
+
|
|
1844
|
+
|
|
1845
|
+
/**
|
|
1846
|
+
* Inicializa DataTable() y modifica elementos para adaptarlos a
|
|
1847
|
+
* GoogleSheets y requerimientos de ArGob.
|
|
1848
|
+
*/
|
|
1849
|
+
const initDataTable = () => {
|
|
1850
|
+
const searchType = jQuery.fn.DataTable.ext.type.search;
|
|
1851
|
+
searchType.string = data => {
|
|
1852
|
+
return (!data ?
|
|
1853
|
+
"" :
|
|
1854
|
+
(typeof data === "string" ?
|
|
1855
|
+
replaceSpecialChars(data) :
|
|
1856
|
+
data));
|
|
1857
|
+
};
|
|
1858
|
+
|
|
1859
|
+
searchType.html = data => {
|
|
1860
|
+
return (!data ?
|
|
1861
|
+
"" :
|
|
1862
|
+
(typeof data === "string" ?
|
|
1863
|
+
replaceSpecialChars(data.replace( /<.*?>/g, "")) :
|
|
1864
|
+
data));
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* Instacia DataTable()
|
|
1869
|
+
*/
|
|
1870
|
+
let tabla = jQuery("#ponchoTable").DataTable({
|
|
1871
|
+
"initComplete" : (settings, json) => {
|
|
1872
|
+
if(wizard){
|
|
1873
|
+
_hideTable();
|
|
1874
|
+
}
|
|
1875
|
+
},
|
|
1876
|
+
"lengthChange": false,
|
|
1877
|
+
"autoWidth": false,
|
|
1878
|
+
"pageLength": opt.cantidadItems,
|
|
1879
|
+
"columnDefs": [
|
|
1880
|
+
{ "type": "html-num", "targets": opt.tipoNumero },
|
|
1881
|
+
{ "targets": opt.ocultarColumnas, "visible": false }
|
|
1882
|
+
],
|
|
1883
|
+
"ordering": opt.orden,
|
|
1884
|
+
"order": [
|
|
1885
|
+
[opt.ordenColumna - 1, opt.ordenTipo]
|
|
1886
|
+
],
|
|
1887
|
+
"dom": "<\"row\"<\"col-sm-6\"l><\"col-sm-6\"f>>" +
|
|
1888
|
+
"<\"row\"<\"col-sm-12\"i>>" +
|
|
1889
|
+
"<\"row\"<\"col-sm-12\"tr>>" +
|
|
1890
|
+
"<\"row\"<\"col-md-offset-3 col-md-6 "
|
|
1891
|
+
+ "col-sm-offset-2 col-sm-8\"p>>",
|
|
1892
|
+
"language": {
|
|
1893
|
+
"sProcessing": "Procesando...",
|
|
1894
|
+
"sLengthMenu": "Mostrar _MENU_ registros",
|
|
1895
|
+
"sZeroRecords": "No se encontraron resultados",
|
|
1896
|
+
"sEmptyTable": "Ningún dato disponible en esta tabla",
|
|
1897
|
+
"sInfo": "_TOTAL_ resultados",
|
|
1898
|
+
"sInfoEmpty": "No hay resultados",
|
|
1899
|
+
//"sInfoFiltered": "(filtrado de un total de _MAX_ registros)",
|
|
1900
|
+
"sInfoFiltered": "",
|
|
1901
|
+
"sInfoPostFix": "",
|
|
1902
|
+
"sSearch": "Buscar:",
|
|
1903
|
+
"sUrl": "",
|
|
1904
|
+
"sInfoThousands": ".",
|
|
1905
|
+
"sLoadingRecords": "Cargando...",
|
|
1906
|
+
"oPaginate": {
|
|
1907
|
+
"sFirst": "<<",
|
|
1908
|
+
"sLast": ">>",
|
|
1909
|
+
"sNext": ">",
|
|
1910
|
+
"sPrevious": "<"
|
|
1911
|
+
},
|
|
1912
|
+
"oAria": {
|
|
1913
|
+
"sSortAscending":
|
|
1914
|
+
": Activar para ordenar la columna "
|
|
1915
|
+
+ "de manera ascendente",
|
|
1916
|
+
"sSortDescending":
|
|
1917
|
+
": Activar para ordenar la columna de "
|
|
1918
|
+
+ "manera descendente",
|
|
1919
|
+
"paginate": {
|
|
1920
|
+
"first": "Ir a la primera página",
|
|
1921
|
+
"previous": "Ir a la página anterior",
|
|
1922
|
+
"next": "Ir a la página siguiente",
|
|
1923
|
+
"last": "Ir a la última página"
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
|
|
1929
|
+
/**
|
|
1930
|
+
* Buscador por palabra
|
|
1931
|
+
* @summary Ejecuta la búsqueda en cada keyup.
|
|
1932
|
+
*/
|
|
1933
|
+
jQuery("#ponchoTableSearch").keyup(function() {
|
|
1934
|
+
tabla
|
|
1935
|
+
.search(jQuery.fn.DataTable.ext.type.search.string(this.value))
|
|
1936
|
+
.draw();
|
|
1937
|
+
});
|
|
1938
|
+
|
|
1939
|
+
|
|
1940
|
+
// REMUEVE LOS FILTROS
|
|
1941
|
+
jQuery("#ponchoTable_filter").parent().parent().remove();
|
|
1942
|
+
|
|
1943
|
+
// MUESTRA FILTRO PERSONALIZADO
|
|
1944
|
+
const ponchoTableOption =
|
|
1945
|
+
document.querySelectorAll("#ponchoTableFiltro option");
|
|
1946
|
+
if (ponchoTableOption.length > 1) {
|
|
1947
|
+
document
|
|
1948
|
+
.querySelector("#ponchoTableFiltroCont")
|
|
1949
|
+
.style.display = "block";
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
|
|
1953
|
+
/**
|
|
1954
|
+
* Valida si un componente select tiene options con value.
|
|
1955
|
+
*
|
|
1956
|
+
* @summary El objeto de éste método es evitar traer selects que tengan
|
|
1957
|
+
* options vacíos.
|
|
1958
|
+
* @param {string} selector Selector del elemento select
|
|
1959
|
+
* @returns {boolean}
|
|
1960
|
+
*/
|
|
1961
|
+
const _selectHasValues = selector => {
|
|
1962
|
+
const options = document.querySelectorAll(`${selector} option`);
|
|
1963
|
+
const result = Object.values(options).map(m => m.value).some(s => s);
|
|
1964
|
+
return result;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
|
|
1968
|
+
/**
|
|
1969
|
+
* Modo wizard para los filtros.
|
|
1970
|
+
*
|
|
1971
|
+
* @param {object} filters Listado de filtros.
|
|
1972
|
+
* @param {interger} column Indice de columna.
|
|
1973
|
+
* @param {string} valFilter Value del select
|
|
1974
|
+
* @returns {undefined}
|
|
1975
|
+
*/
|
|
1976
|
+
const _wizardFilters = (filters, column=0, valFilter="") => {
|
|
1977
|
+
let tableStatus = false;
|
|
1978
|
+
|
|
1979
|
+
filters.forEach((filter, key) => {
|
|
1980
|
+
const selectHasValues = _selectHasValues(`#${filter}`);
|
|
1981
|
+
let displayStatus = "none";
|
|
1982
|
+
|
|
1983
|
+
if(selectHasValues && valFilter && key <= column + 1){
|
|
1984
|
+
displayStatus = "block";
|
|
1985
|
+
|
|
1986
|
+
} else if(selectHasValues && !valFilter && key <= column + 1){
|
|
1987
|
+
const nextFilter = document
|
|
1988
|
+
.querySelectorAll(`#${filters[column + 1]}`)
|
|
1989
|
+
nextFilter.forEach(element => element.innerHTML = "");
|
|
1990
|
+
displayStatus = "block";
|
|
1991
|
+
tableStatus = false;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
const currentFilter = document
|
|
1995
|
+
.querySelectorAll(`[data-filter-name="${filter}"]`)
|
|
1996
|
+
currentFilter
|
|
1997
|
+
.forEach(element => element.style.display = displayStatus);
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
if(
|
|
2001
|
+
_selectHasValues(`#${filters[column]}`) &&
|
|
2002
|
+
valFilter &&
|
|
2003
|
+
!_selectHasValues(`#${filters[column + 1]}`)
|
|
2004
|
+
){
|
|
2005
|
+
tableStatus = true;
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
|
|
2009
|
+
if(tableStatus){
|
|
2010
|
+
_hideTable(false);
|
|
2011
|
+
} else {
|
|
2012
|
+
_hideTable();
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
2015
|
+
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* Filtro en el change de cada select (filtro).
|
|
2019
|
+
*
|
|
2020
|
+
* @summary Por por cada interacción con un filtro, obtiene el índice de
|
|
2021
|
+
* columna y lo pasa con el valor del select a _dependantFilters(). Ésta
|
|
2022
|
+
* funciión redibuja los filtros en de forma dependiente según el valor
|
|
2023
|
+
* de la elección.
|
|
2024
|
+
* @see replaceSpecialChars() on poncho.min.js
|
|
2025
|
+
* @return {undefined}
|
|
2026
|
+
*/
|
|
2027
|
+
jQuery("select[data-filter]").change(function() {
|
|
2028
|
+
const column = jQuery(this).find("option:selected").data("column");
|
|
2029
|
+
const valFilter = jQuery(this).find("option:selected").val();
|
|
2030
|
+
|
|
2031
|
+
_dependantFilters(column, valFilter);
|
|
2032
|
+
|
|
2033
|
+
// Restablece los datos en la tabla
|
|
2034
|
+
tabla.columns().search("").columns().search("").draw();
|
|
2035
|
+
|
|
2036
|
+
const filters = Object.keys(filtro);
|
|
2037
|
+
const filterValues = _filterValues();
|
|
2038
|
+
const filterIndex = filter => {
|
|
2039
|
+
return Object
|
|
2040
|
+
.keys(gapi_data.headers)
|
|
2041
|
+
.indexOf(`filtro-${filter}`);
|
|
2042
|
+
};
|
|
448
2043
|
|
|
2044
|
+
filterValues.forEach((f, k) => {
|
|
2045
|
+
const columnIndex = filterIndex(filters[k]);
|
|
2046
|
+
const term = _searchTerm(filterValues[k]);
|
|
2047
|
+
const cleanTerm = _searchTerm(
|
|
2048
|
+
replaceSpecialChars(filterValues[k]));
|
|
449
2049
|
|
|
450
|
-
|
|
2050
|
+
if(_isCustomFilter(k, filtro)){
|
|
2051
|
+
tabla.columns(columnIndex)
|
|
2052
|
+
.search(_toCompareString(filterValues[k]));
|
|
2053
|
+
} else {
|
|
2054
|
+
tabla
|
|
2055
|
+
.columns(columnIndex)
|
|
2056
|
+
.search(
|
|
2057
|
+
(filterValues[k] ? `^(${term}|${cleanTerm})$` : ""),
|
|
2058
|
+
true, false, true
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
tabla.draw();
|
|
2063
|
+
if(wizard){
|
|
2064
|
+
_wizardFilters(filters, column, valFilter);
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
451
2067
|
|
|
452
|
-
/**
|
|
453
|
-
* Impide que se impriman etiquetas HTML.
|
|
454
|
-
*
|
|
455
|
-
* @summary Impide que se impriman etiquetas HTML exceptuando aquellas
|
|
456
|
-
* asignadas en el parámetro exclude.
|
|
457
|
-
* @param {string} str Cadena de texto a remplazar.
|
|
458
|
-
* @param {object} exclude Etiquetas que deben preservarse.
|
|
459
|
-
* @example
|
|
460
|
-
* // returns <h1>Hello world!</h1> <a href="#">Link</a>
|
|
461
|
-
* secureHTML('<h1>Hello world!</h1> <a href="#">Link</a>', ["a"])
|
|
462
|
-
*
|
|
463
|
-
* @returns {string} Texto remplazado.
|
|
464
|
-
*/
|
|
465
|
-
const secureHTML = (str, exclude=[]) => {
|
|
466
|
-
if(exclude.some(e => e === "*")){
|
|
467
|
-
return str;
|
|
468
|
-
}
|
|
469
2068
|
|
|
470
|
-
|
|
471
|
-
.
|
|
472
|
-
|
|
2069
|
+
// Si está habilitada la búsqueda por hash.
|
|
2070
|
+
if(opt.hasOwnProperty("hash") && opt.hash){
|
|
2071
|
+
const term = hasHash();
|
|
2072
|
+
const searchTerm = (term ? decodeURIComponent(term) : "");
|
|
2073
|
+
const element = document.querySelectorAll("#ponchoTableSearch");
|
|
2074
|
+
element.forEach(ele => {
|
|
2075
|
+
ele.value = searchTerm;
|
|
2076
|
+
tabla
|
|
2077
|
+
.search(jQuery.fn.DataTable.ext.type.search.string(searchTerm))
|
|
2078
|
+
.draw();
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
} // end initDataTable
|
|
473
2082
|
|
|
474
|
-
// let replaceString = str.toString()
|
|
475
|
-
// .replace(/<(?=[a-zA-Z])([^<>]*)>/gm, "<$1>")
|
|
476
|
-
// .replace(/<\/(?=[a-zA-Z])([^<>]*)>/gm, "</$1>");
|
|
477
2083
|
|
|
2084
|
+
/**
|
|
2085
|
+
* Permite definir el orden de los headers.
|
|
2086
|
+
* @param {*} headers {object}
|
|
2087
|
+
* @param {*} order
|
|
2088
|
+
* @returns
|
|
2089
|
+
*/
|
|
2090
|
+
const _headersOrder = (headers) => {
|
|
2091
|
+
if(opt.hasOwnProperty("headersOrder") && opt.headersOrder.length > 0){
|
|
2092
|
+
let refactorHeaders = {};
|
|
2093
|
+
for(i of opt.headersOrder){
|
|
2094
|
+
if( headers.hasOwnProperty(i) ){
|
|
2095
|
+
refactorHeaders[i] = headers[i];
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
return refactorHeaders;
|
|
2099
|
+
}
|
|
2100
|
+
return headers;
|
|
2101
|
+
};
|
|
478
2102
|
|
|
479
|
-
if(exclude.length > 0){
|
|
480
|
-
const regexStart = new RegExp(
|
|
481
|
-
"<(" + exclude.join("|") + ")(.*?)>", "g");
|
|
482
|
-
const regexEnd = new RegExp(
|
|
483
|
-
"<\/(" + exclude.join("|") + ")(.*?)>", "g");
|
|
484
2103
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
2104
|
+
/**
|
|
2105
|
+
* Imprime DataTable
|
|
2106
|
+
*
|
|
2107
|
+
* @param {object} data JSON data
|
|
2108
|
+
*/
|
|
2109
|
+
const render = data => {
|
|
2110
|
+
// Defino la variable global
|
|
2111
|
+
gapi_data = data;
|
|
2112
|
+
// Defino las entradas
|
|
2113
|
+
gapi_data.entries = (
|
|
2114
|
+
typeof opt.refactorEntries === "function" &&
|
|
2115
|
+
opt.refactorEntries !== null ?
|
|
2116
|
+
opt.refactorEntries(gapi_data.entries) : gapi_data.entries
|
|
2117
|
+
);
|
|
2118
|
+
// Defino los headers que se van a utilizar
|
|
2119
|
+
gapi_data.headers = (opt.hasOwnProperty("headers") && opt.headers ?
|
|
2120
|
+
opt.headers : gapi_data.headers);
|
|
491
2121
|
|
|
2122
|
+
gapi_data.headers = _headersOrder(gapi_data.headers, opt.headersOrder);
|
|
492
2123
|
|
|
2124
|
+
// Listado de filtros
|
|
2125
|
+
filtersList = Object
|
|
2126
|
+
.keys(gapi_data.headers)
|
|
2127
|
+
.filter(e => e.startsWith("filtro-"));
|
|
493
2128
|
|
|
494
|
-
|
|
2129
|
+
asFilter = (opt.asFilter ? opt.asFilter(gapi_data.entries) : {});
|
|
2130
|
+
filtro = flterMatrix(gapi_data, filtersList);
|
|
495
2131
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
document
|
|
501
|
-
.querySelectorAll("select[id=ponchoTableFiltro]")
|
|
502
|
-
.forEach(element => {
|
|
503
|
-
// const node = element.closest(".form-group");
|
|
504
|
-
const node = element.parentElement;
|
|
505
|
-
// Creo un contenedor
|
|
506
|
-
const newElement = document.createElement("div");
|
|
507
|
-
newElement.id = "ponchoTableFiltro";
|
|
508
|
-
newElement.classList.add("row");
|
|
509
|
-
node.parentElement.appendChild(newElement);
|
|
510
|
-
// Borro el viejo elemento
|
|
511
|
-
node.remove();
|
|
512
|
-
});
|
|
513
|
-
};
|
|
2132
|
+
_filtersContainerClassList();
|
|
2133
|
+
_searchContainerClassList();
|
|
2134
|
+
_createTable(gapi_data);
|
|
2135
|
+
_createFilters(gapi_data);
|
|
514
2136
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
2137
|
+
document.querySelector("#ponchoTableSearchCont")
|
|
2138
|
+
.style.display = "block";
|
|
2139
|
+
document.querySelector("#ponchoTable")
|
|
2140
|
+
.classList.remove("state-loading");
|
|
519
2141
|
|
|
2142
|
+
initDataTable();
|
|
2143
|
+
};
|
|
520
2144
|
|
|
521
|
-
/**
|
|
522
|
-
* PONCHO TABLE
|
|
523
|
-
*
|
|
524
|
-
* @summary PonchoTable con filtros dependientes
|
|
525
|
-
*
|
|
526
|
-
* @author Agustín Bouillet <bouilleta@jefatura.gob.ar>
|
|
527
|
-
* @requires jQuery
|
|
528
|
-
* @see https://github.com/argob/poncho/blob/master/src/demo/poncho-maps/readme-poncho-maps.md
|
|
529
|
-
* @see https://datatables.net
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
* MIT License
|
|
533
|
-
*
|
|
534
|
-
* Copyright (c) 2022 Argentina.gob.ar
|
|
535
|
-
*
|
|
536
|
-
* Permission is hereby granted, free of charge, to any person
|
|
537
|
-
* obtaining a copy of this software and associated documentation
|
|
538
|
-
* files (the "Software"), to deal in the Software without restriction,
|
|
539
|
-
* including without limitation the rightsto use, copy, modify, merge,
|
|
540
|
-
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
541
|
-
* and to permit persons to whom the Software is furnished to do so,
|
|
542
|
-
* subject to the following conditions:
|
|
543
|
-
*
|
|
544
|
-
* The above copyright notice and this permission notice shall be
|
|
545
|
-
* included in all copies or substantial portions of the Software.
|
|
546
|
-
*
|
|
547
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
548
|
-
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
549
|
-
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
550
|
-
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
551
|
-
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
552
|
-
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
553
|
-
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
554
|
-
* SOFTWARE.
|
|
555
|
-
*/
|
|
556
|
-
const ponchoTableDependant = opt => {
|
|
557
|
-
var gapi_data;
|
|
558
|
-
var filtersList = [];
|
|
559
|
-
var filtro = {};
|
|
560
|
-
var orderFilter = (opt.hasOwnProperty("orderFilter") && opt.orderFilter ?
|
|
561
|
-
true : false);
|
|
562
|
-
var asFilter = {};
|
|
563
|
-
var allowedTags = ["*"];
|
|
564
|
-
let markdownOptions = {
|
|
565
|
-
"tables": true,
|
|
566
|
-
"simpleLineBreaks": true,
|
|
567
|
-
"extensions": [
|
|
568
|
-
'details',
|
|
569
|
-
'images',
|
|
570
|
-
'alerts',
|
|
571
|
-
'numbers',
|
|
572
|
-
'ejes',
|
|
573
|
-
'button',
|
|
574
|
-
'target',
|
|
575
|
-
'bootstrap-tables',
|
|
576
|
-
'video'
|
|
577
|
-
]
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
// Loader
|
|
581
|
-
document.querySelector("#ponchoTable").classList.add("state-loading");
|
|
582
|
-
|
|
583
|
-
if (jQuery.fn.DataTable.isDataTable("#ponchoTable")) {
|
|
584
|
-
jQuery("#ponchoTable").DataTable().destroy();
|
|
585
|
-
}
|
|
586
2145
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* De acuerdo a las opciones del usuario, ordena el listado o lo deja
|
|
600
|
-
* en la secuencia en la que llega.
|
|
601
|
-
*
|
|
602
|
-
* @summary Alias de sortAlphaNumeric
|
|
603
|
-
* @param {object} a
|
|
604
|
-
* @param {object} b
|
|
605
|
-
* @returns {object}
|
|
606
|
-
*/
|
|
607
|
-
const _sortAlphaNumeric = (a, b) => (orderFilter ?
|
|
608
|
-
sortAlphaNumeric(a, b) : null);
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* Resultados únicos
|
|
612
|
-
*
|
|
613
|
-
* @param {object} list Array del que se quiere obtener
|
|
614
|
-
* resultados únicos.
|
|
615
|
-
* @returns {object}
|
|
616
|
-
*/
|
|
617
|
-
const distinct = list => [... new Set(list)];
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Select option
|
|
621
|
-
*
|
|
622
|
-
* @summary Crea un tag _option_ para un _select_.
|
|
623
|
-
* @param {integer} parent Índice según el listado de filtros.
|
|
624
|
-
* @param {string} label Valor para el label o texto visible.
|
|
625
|
-
* @param {string} value Valor para el attributo _value_.
|
|
626
|
-
* @param {boolean} selected Si el item debe mostrarse seleccionado.
|
|
627
|
-
* @return {object}
|
|
628
|
-
*/
|
|
629
|
-
const _optionSelect = (parent=0, label, value, selected=false) => {
|
|
630
|
-
var select_option = document.createElement("option");
|
|
631
|
-
select_option.value = value.toString().trim();
|
|
632
|
-
select_option.dataset.column = parent;
|
|
633
|
-
select_option.textContent = label.toString().trim();
|
|
634
|
-
if(selected){
|
|
635
|
-
select_option.setAttribute("selected", "selected");
|
|
636
|
-
}
|
|
637
|
-
return select_option;
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Prepara el término para ser buscado por REGEX
|
|
642
|
-
*
|
|
643
|
-
* @summary Escapa caracteres especiales utilizados en la sintáxis
|
|
644
|
-
* de expresiones regulares.
|
|
645
|
-
* @see replaceSpecialChars() en poncho.min.js
|
|
646
|
-
* @param {string} term Término a buscar.
|
|
647
|
-
* @example
|
|
648
|
-
* // return Simbrón \(3\.180\)
|
|
649
|
-
* _searchTerm("Simbrón (3.180)")
|
|
650
|
-
* @return {string}
|
|
651
|
-
*/
|
|
652
|
-
const _searchTerm = term => {
|
|
653
|
-
return term.toString().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
654
|
-
};
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Evita un valor negativo
|
|
658
|
-
*/
|
|
659
|
-
const _parentElement = value => (value <= 0 ? 0 : value);
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Retorna los valores de los filtros
|
|
663
|
-
*/
|
|
664
|
-
const _filterValues = () => {
|
|
665
|
-
return [...document.querySelectorAll("[data-filter]")].map(e => e.value);
|
|
666
|
-
};
|
|
667
|
-
|
|
668
|
-
/**
|
|
669
|
-
* Showdown habilitado.
|
|
670
|
-
*
|
|
671
|
-
* Verifica si la librería _showdown_ está disponible.
|
|
672
|
-
* @returns {boolean}
|
|
673
|
-
*/
|
|
674
|
-
const _isMarkdownEnable = () => {
|
|
675
|
-
if(typeof showdown !== "undefined" &&
|
|
676
|
-
showdown.hasOwnProperty("Converter")){
|
|
677
|
-
return true;
|
|
678
|
-
}
|
|
679
|
-
return false;
|
|
680
|
-
};
|
|
681
|
-
|
|
682
|
-
/**
|
|
683
|
-
* Verifica si las extensiones showdown están definidas.
|
|
684
|
-
*
|
|
685
|
-
* @param {object} extensions
|
|
686
|
-
* @returns {boolean}
|
|
687
|
-
*/
|
|
688
|
-
const _isShowdownExtensionEnable = extensions =>
|
|
689
|
-
extensions.every(e => {
|
|
690
|
-
try {
|
|
691
|
-
showdown.extension(e);
|
|
692
|
-
return true;
|
|
693
|
-
} catch (error) {
|
|
694
|
-
return false;
|
|
695
|
-
}
|
|
696
|
-
});
|
|
2146
|
+
/**
|
|
2147
|
+
* Obtiene el sheet e inicializa la tabla y filtros.
|
|
2148
|
+
*
|
|
2149
|
+
* @param {string} url URL del dataset JSON
|
|
2150
|
+
*/
|
|
2151
|
+
const getSheetValues = url => {
|
|
2152
|
+
jQuery.getJSON(url, function(data){
|
|
2153
|
+
const gapi = new GapiSheetData();
|
|
2154
|
+
gapi_data = gapi.json_data(data);
|
|
697
2155
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
* @summary Agrega una etiqueta datetime para mejorar la indexación
|
|
722
|
-
* y el ordenamiento.
|
|
723
|
-
* @return {undefined}
|
|
724
|
-
*/
|
|
725
|
-
const tdDate = value => {
|
|
726
|
-
const dateSplit = value.split("/");
|
|
727
|
-
const finalDateIso = new Date(
|
|
728
|
-
dateSplit[2], dateSplit[1] - 1, dateSplit[0]
|
|
729
|
-
);
|
|
730
|
-
|
|
731
|
-
const hiddenSpan = document.createElement("span");
|
|
732
|
-
hiddenSpan.style.display = "none";
|
|
733
|
-
hiddenSpan.textContent = finalDateIso.toISOString().split('T')[0];
|
|
734
|
-
return hiddenSpan.outerHTML + value;
|
|
735
|
-
};
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* Imprime los filtros
|
|
739
|
-
*
|
|
740
|
-
* @param {object} gapi_data Objeto con la información separada del
|
|
741
|
-
* documento Google Sheet
|
|
742
|
-
*/
|
|
743
|
-
const _createFilters = gapi_data => {
|
|
744
|
-
// Contenedor
|
|
745
|
-
const tableFiltroCont = document.querySelector("#ponchoTableFiltro");
|
|
746
|
-
tableFiltroCont.innerHTML = "";
|
|
747
|
-
|
|
748
|
-
// Imprime cada uno de los filtros
|
|
749
|
-
for (f in filtro){
|
|
750
|
-
const columna = filtro[f][0].columna ? filtro[f][0].columna : 0;
|
|
751
|
-
const list_filter = filtro[f]
|
|
752
|
-
.map(e => e.value)
|
|
753
|
-
.sort(_sortAlphaNumeric);
|
|
754
|
-
|
|
755
|
-
const tplCol = document.createElement("div");
|
|
756
|
-
|
|
757
|
-
if(opt.hasOwnProperty("filterClassList")){
|
|
758
|
-
const classList = (typeof opt.filterClassList === "string" ?
|
|
759
|
-
opt.filterClassList.split(" ") : opt.filterClassList);
|
|
760
|
-
tplCol.classList.add(...classList);
|
|
761
|
-
} else {
|
|
762
|
-
const cols = Math.floor(12 / Object.keys(filtro).length);
|
|
763
|
-
tplCol.classList.add("col-sm-12", `col-md-${cols}`);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
const tplForm = document.createElement("div");
|
|
767
|
-
tplForm.className = "form-group";
|
|
768
|
-
|
|
769
|
-
const formLabel = document.createElement("label");
|
|
770
|
-
formLabel.setAttribute("for", f);
|
|
771
|
-
formLabel.textContent = gapi_data.headers[`filtro-${f}`];
|
|
772
|
-
|
|
773
|
-
const select = document.createElement("select");
|
|
774
|
-
select.classList.add("form-control");
|
|
775
|
-
select.dataset.filter = 1;
|
|
776
|
-
select.name = f;
|
|
777
|
-
select.id = f;
|
|
778
|
-
select.appendChild(_optionSelect(columna, "Todos", "", true));
|
|
779
|
-
list_filter.forEach(item => {
|
|
780
|
-
if(!item){
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
select.appendChild(_optionSelect(columna, item, item, false));
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
tplForm.appendChild(formLabel);
|
|
787
|
-
tplForm.appendChild(select);
|
|
788
|
-
tplCol.appendChild(tplForm);
|
|
789
|
-
tableFiltroCont.appendChild(tplCol);
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
|
|
793
|
-
/**
|
|
794
|
-
* Imprime la tabla
|
|
795
|
-
*
|
|
796
|
-
* @param {object} gapi_data Objeto con la información separada del
|
|
797
|
-
* documento Google Sheet
|
|
798
|
-
*/
|
|
799
|
-
const _createTable = gapi_data => {
|
|
800
|
-
// Table thead > th
|
|
801
|
-
const thead = document.querySelector("#ponchoTable thead");
|
|
802
|
-
thead.innerHTML = "";
|
|
803
|
-
|
|
804
|
-
const theadTr = document.createElement("tr");
|
|
805
|
-
Object.keys(gapi_data.headers).forEach((header, key) => {
|
|
806
|
-
const th = document.createElement("th");
|
|
807
|
-
th.textContent = gapi_data.headers[header];
|
|
808
|
-
th.setAttribute("scope", "col");
|
|
809
|
-
theadTr.appendChild(th);
|
|
810
|
-
});
|
|
811
|
-
thead.appendChild(theadTr);
|
|
812
|
-
|
|
813
|
-
// Table caption
|
|
814
|
-
const tableCaption = document.querySelector("#ponchoTable caption");
|
|
815
|
-
tableCaption.innerHTML = "";
|
|
816
|
-
tableCaption.textContent = opt.tituloTabla;
|
|
817
|
-
|
|
818
|
-
// Tbody instance
|
|
819
|
-
const tableTbody = document.querySelector("#ponchoTable tbody");
|
|
820
|
-
tableTbody.innerHTML = "";
|
|
821
|
-
|
|
822
|
-
// CONTENIDO FILAS
|
|
823
|
-
gapi_data.entries.forEach((entry, key) => {
|
|
824
|
-
|
|
825
|
-
if(!Object.values(entry).some(f => String(f).trim())){
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// si se desea modificar la entrada desde opciones
|
|
830
|
-
entry = (typeof opt.customEntry === "function" &&
|
|
831
|
-
opt.customEntry !== null ? opt.customEntry(entry) : entry);
|
|
832
|
-
|
|
833
|
-
// Inserta el row.
|
|
834
|
-
const tbodyRow = tableTbody.insertRow();
|
|
835
|
-
tbodyRow.id = "id_" + key;
|
|
836
|
-
|
|
837
|
-
// Verifico sin las extensiones showdown existen
|
|
838
|
-
let showdownOptions;
|
|
839
|
-
if(_isMarkdownEnable()){
|
|
840
|
-
const registeredOptions = (opt.hasOwnProperty("markdownOptions") ?
|
|
841
|
-
opt.markdownOptions : markdownOptions);
|
|
842
|
-
showdownOptions = (_isShowdownExtensionEnable(
|
|
843
|
-
registeredOptions.extensions) ? registeredOptions : {});
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// Recorro cada uno de los títulos
|
|
847
|
-
Object.keys(gapi_data.headers).forEach(header => {
|
|
848
|
-
filas = entry[header];
|
|
849
|
-
|
|
850
|
-
if (header.startsWith("btn-") && filas != "") {
|
|
851
|
-
filas = button(
|
|
852
|
-
header.replace("btn-", "").replace("-", " "), filas
|
|
853
|
-
);
|
|
854
|
-
} else if (header.startsWith("fecha-") && filas != "") {
|
|
855
|
-
filas = tdDate(filas);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
const cell = tbodyRow.insertCell();
|
|
859
|
-
cell.dataset.title = gapi_data.headers[header];
|
|
860
|
-
if (filas == ""){
|
|
861
|
-
cell.className = "hidden-xs";
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// Si showdown está incluido lo uso
|
|
865
|
-
// @todo Usar showdown fuera de la función. Usarlo en options.
|
|
866
|
-
let allowed_tags = (opt.hasOwnProperty("allowedTags") ?
|
|
867
|
-
opt.allowedTags : allowedTags);
|
|
868
|
-
|
|
869
|
-
// Anchor como filtro está permitido por defecto.
|
|
870
|
-
allowed_tags = ( header.startsWith("btn-") && filas != "" ?
|
|
871
|
-
[...allowed_tags, "a"] : allowed_tags);
|
|
872
|
-
|
|
873
|
-
const cleannedText = secureHTML(filas, allowed_tags);
|
|
874
|
-
if(_isMarkdownEnable()){
|
|
875
|
-
const converter = new showdown.Converter(showdownOptions);
|
|
876
|
-
cell.innerHTML = converter.makeHtml(cleannedText);
|
|
877
|
-
} else {
|
|
878
|
-
cell.innerHTML = cleannedText;
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
});
|
|
882
|
-
};
|
|
883
|
-
|
|
884
|
-
/**
|
|
885
|
-
* Matriz filtro
|
|
886
|
-
*
|
|
887
|
-
* @summary Reune los filtros y por cada uno de ellos guarda los
|
|
888
|
-
* datos —únicos—, de esa entrada.
|
|
889
|
-
* @param {object} gapi_data Objeto con la información separada del
|
|
890
|
-
* documento Google Sheet
|
|
891
|
-
* @example
|
|
892
|
-
* {
|
|
893
|
-
* nombre_filtro : [
|
|
894
|
-
* {
|
|
895
|
-
* columna: 0,
|
|
896
|
-
* value: "elemento"
|
|
897
|
-
* },
|
|
898
|
-
* ...
|
|
899
|
-
* ]
|
|
900
|
-
* }
|
|
901
|
-
* @return {object}
|
|
902
|
-
*/
|
|
903
|
-
const flterMatrix = (gapi_data, filtersList) => {
|
|
904
|
-
let filters = {};
|
|
905
|
-
filtersList.forEach((filter, key) => {
|
|
906
|
-
let entiresByFilter = [];
|
|
907
|
-
if(asFilter.hasOwnProperty(filtersList[key])){
|
|
908
|
-
entiresByFilter = asFilter[filtersList[key]];
|
|
909
|
-
} else {
|
|
910
|
-
entiresByFilter = gapi_data.entries.map(entry => entry[filter]);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
const uniqueEntries = distinct(entiresByFilter);
|
|
914
|
-
uniqueEntries.sort(_sortAlphaNumeric);
|
|
915
|
-
filter = filter.replace("filtro-", "");
|
|
916
|
-
filters[filter] = [];
|
|
917
|
-
uniqueEntries.forEach(entry => {
|
|
918
|
-
filters[filter].push({"columna": key, "value": entry});
|
|
919
|
-
});
|
|
920
|
-
});
|
|
921
|
-
return filters;
|
|
922
|
-
};
|
|
923
|
-
|
|
924
|
-
/* HELPERS FILTRO DEPENDIENTE */
|
|
925
|
-
/**
|
|
926
|
-
* Valida los parents
|
|
927
|
-
*
|
|
928
|
-
* @param {integer} parent Índice (filtro) seleccionado.
|
|
929
|
-
* @return {boolean}
|
|
930
|
-
*/
|
|
931
|
-
const _validateSteps = (parent, entry, label, values) => {
|
|
932
|
-
// Verifico que por cada entrada el valor(label), se
|
|
933
|
-
// encuentre en cada uno de los parents.
|
|
934
|
-
// El bucle termina cuando llega al índice seleccionado.
|
|
935
|
-
const range = [...Array(_parentElement(parent + 1)).keys()];
|
|
936
|
-
const results = range.map(i => {
|
|
937
|
-
// Chequeo si el valor del select es igual al parent o
|
|
938
|
-
// si en su defecto, está vacío.
|
|
939
|
-
if(
|
|
940
|
-
(
|
|
941
|
-
(entry[filtersList[_parentElement(parent-1)]] ==
|
|
942
|
-
values[_parentElement(parent-1)]) &&
|
|
943
|
-
(entry[filtersList[_parentElement(parent)]] == label)
|
|
944
|
-
) || values[_parentElement(parent-1)] == "")
|
|
945
|
-
{
|
|
946
|
-
return true;
|
|
947
|
-
}
|
|
948
|
-
return false;
|
|
949
|
-
});
|
|
950
|
-
return results.every(e => e);
|
|
951
|
-
};
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* Trae todos los elementos de un filtro en base a su parent.
|
|
955
|
-
*
|
|
956
|
-
* @param {integer} parent Indice de filtro seleccionado.
|
|
957
|
-
* @param {integer} children Indice del hijo del seleccionado.
|
|
958
|
-
* @param {string} label value del filtro seleccionado.
|
|
959
|
-
* @return {object} Listado de elementos únicos para el select.
|
|
960
|
-
*/
|
|
961
|
-
const _allFromParent = (parent, children, label) => {
|
|
962
|
-
const filterList = gapi_data.entries.flatMap(e => {
|
|
963
|
-
const evaluatedEntry = e[filtersList[_parentElement(children)]];
|
|
964
|
-
if(e[filtersList[_parentElement(parent)]] == label || label == ""){
|
|
965
|
-
if(_isCustomFilter(children, filtro)){
|
|
966
|
-
const customFilters = _customFilter(children, filtro)
|
|
967
|
-
.filter(e => {
|
|
968
|
-
return _toCompareString(evaluatedEntry)
|
|
969
|
-
.includes(_toCompareString(e));
|
|
970
|
-
});
|
|
971
|
-
return customFilters;
|
|
972
|
-
}
|
|
973
|
-
return evaluatedEntry;
|
|
974
|
-
}
|
|
975
|
-
return false;
|
|
976
|
-
|
|
977
|
-
}).filter(f => f);
|
|
978
|
-
|
|
979
|
-
const uniqueList = distinct(filterList);
|
|
980
|
-
uniqueList.sort(_sortAlphaNumeric);
|
|
981
|
-
return uniqueList;
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
/**
|
|
985
|
-
* Prepara un string para una comparación case sensitive y sin
|
|
986
|
-
* caracteres especiales.
|
|
987
|
-
* @param {string} value Valor a comparar.
|
|
988
|
-
* @returns {boolean}
|
|
989
|
-
*/
|
|
990
|
-
const _toCompareString = value => replaceSpecialChars(value.toLowerCase());
|
|
991
|
-
|
|
992
|
-
/**
|
|
993
|
-
* Lista los valores que deben ir en un filtro según su parent.
|
|
994
|
-
*
|
|
995
|
-
* @param {integer} parent Indice de filtro seleccionado.
|
|
996
|
-
* @param {string} label value del filtro seleccionado.
|
|
997
|
-
* @param {integer} children Indice del hijo del seleccionado.
|
|
998
|
-
*/
|
|
999
|
-
const _filterOptionList = (parent, children, label) => {
|
|
1000
|
-
children = (children == filtersList.length ? children - 1 : children);
|
|
1001
|
-
const values = _filterValues();
|
|
1002
|
-
|
|
1003
|
-
// Recorro todas las entradas del JSON
|
|
1004
|
-
const items = gapi_data.entries.flatMap(entry => {
|
|
1005
|
-
const range = _validateSteps(parent, entry, label, values);
|
|
1006
|
-
if(
|
|
1007
|
-
(entry[filtersList[_parentElement(children - 1)]] == label) &&
|
|
1008
|
-
(range)){
|
|
1009
|
-
const evaluatedEntry = entry[filtersList[_parentElement(children)]];
|
|
1010
|
-
if(_isCustomFilter(children, filtro)){
|
|
1011
|
-
const customFilters = _customFilter(children, filtro)
|
|
1012
|
-
.filter(e => {
|
|
1013
|
-
return _toCompareString(evaluatedEntry)
|
|
1014
|
-
.includes(_toCompareString(e));
|
|
1015
|
-
});
|
|
1016
|
-
return customFilters;
|
|
1017
|
-
} else {
|
|
1018
|
-
return evaluatedEntry;
|
|
1019
|
-
}
|
|
2156
|
+
render(gapi_data);
|
|
2157
|
+
}); // end async
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* Obtiene el sheet por número de hoja y nombre del spread.
|
|
2163
|
+
*
|
|
2164
|
+
* @param {integer} sheetNumber Número de hoja sin iniciar en 0.
|
|
2165
|
+
*/
|
|
2166
|
+
const getSheetName = sheetNumber => {
|
|
2167
|
+
const gapi = new GapiSheetData();
|
|
2168
|
+
const uriApi = [
|
|
2169
|
+
"https://sheets.googleapis.com/v4/spreadsheets/",
|
|
2170
|
+
opt.idSpread, "/?alt=json&key=",
|
|
2171
|
+
gapi.gapi_key].join("");
|
|
2172
|
+
|
|
2173
|
+
jQuery.getJSON(uriApi, function function_name(response) {
|
|
2174
|
+
var sheetName = response.sheets[sheetNumber - 1].properties.title;
|
|
2175
|
+
const uriSheet = gapi.url(sheetName, opt.idSpread);
|
|
2176
|
+
getSheetValues(uriSheet);
|
|
2177
|
+
});
|
|
2178
|
+
};
|
|
1020
2179
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
return true
|
|
1039
|
-
}
|
|
1040
|
-
return false;
|
|
1041
|
-
};
|
|
1042
|
-
|
|
1043
|
-
/**
|
|
1044
|
-
* Listado de filtros personalizado
|
|
1045
|
-
* @param {integer} key Indice de filtro
|
|
1046
|
-
* @returns {object}
|
|
1047
|
-
*/
|
|
1048
|
-
const _customFilter = key => {
|
|
1049
|
-
const filtersKeys = Object.keys(filtro);
|
|
1050
|
-
if(asFilter.hasOwnProperty(`filtro-${filtersKeys[key]}`)){
|
|
1051
|
-
return asFilter[`filtro-${filtersKeys[key]}`];
|
|
1052
|
-
}
|
|
1053
|
-
return [];
|
|
1054
|
-
};
|
|
1055
|
-
|
|
1056
|
-
/**
|
|
1057
|
-
* Filtra select hijos en base a un item del padre.
|
|
1058
|
-
*
|
|
1059
|
-
* @param {integer} filterIndex Índice de filtro o número de filtro.
|
|
1060
|
-
* @param {string} label Label del indice seleccionado
|
|
1061
|
-
* @return {void}
|
|
1062
|
-
*/
|
|
1063
|
-
const _dependantFilters = (filterIndex, label) => {
|
|
1064
|
-
const filtros = Object.keys(filtro);
|
|
1065
|
-
const filterValues = _filterValues();
|
|
1066
|
-
// Redibujo los _option_ por cada `select` (filtro).
|
|
1067
|
-
// Hago un `for()` iniciando en el hijo de filterIndex.
|
|
1068
|
-
for(let i = filterIndex + 1; i <= filtros.length; i++){
|
|
1069
|
-
if(filtros.length == i ){
|
|
1070
|
-
break;
|
|
1071
|
-
}
|
|
1072
|
-
let itemList = _filterOptionList(filterIndex, i, label);
|
|
1073
|
-
if(itemList.length == 0){
|
|
1074
|
-
itemList = _allFromParent(filterIndex, i, label);
|
|
1075
|
-
}
|
|
1076
|
-
const select = document.querySelector(`#${filtros[i]}`);
|
|
1077
|
-
select.innerHTML = "";
|
|
1078
|
-
|
|
1079
|
-
select.appendChild(_optionSelect(i, "Todos", "", true));
|
|
1080
|
-
itemList.forEach(e => {
|
|
1081
|
-
if(!e.trim()){
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
// Mantengo el filtro del hijo si existe en el
|
|
1085
|
-
// listado filtrado.
|
|
1086
|
-
let checked = (filterValues[i] == e ? true : false);
|
|
1087
|
-
select.appendChild(_optionSelect(i, e, e, checked));
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
};
|
|
1091
|
-
|
|
1092
|
-
/**
|
|
1093
|
-
* Asigna selectores al contenedor de los filtros.
|
|
1094
|
-
* @returns {undefined}
|
|
1095
|
-
*/
|
|
1096
|
-
const _filtersContainerClassList = () =>{
|
|
1097
|
-
if(opt.hasOwnProperty("filterContClassList") && opt.filterContClassList){
|
|
1098
|
-
const fc = document.getElementById("ponchoTableFiltroCont");
|
|
1099
|
-
fc.removeAttribute("class");
|
|
1100
|
-
fc.classList.add(...opt.filterContClassList);
|
|
1101
|
-
}
|
|
1102
|
-
};
|
|
1103
|
-
|
|
1104
|
-
/**
|
|
1105
|
-
* Asigna selectores al contenedor del buscador.
|
|
1106
|
-
* @returns {undefined}
|
|
1107
|
-
*/
|
|
1108
|
-
const _searchContainerClassList = () =>{
|
|
1109
|
-
if(opt.hasOwnProperty("searchContClassList") && opt.searchContClassList){
|
|
1110
|
-
const element = document.getElementById("ponchoTableSearchCont");
|
|
1111
|
-
element.removeAttribute("class");
|
|
1112
|
-
element.classList.add(...opt.searchContClassList)
|
|
2180
|
+
// Según el caso en optiones.
|
|
2181
|
+
if (opt.jsonData){
|
|
2182
|
+
const headers = Object.fromEntries(
|
|
2183
|
+
Object.keys(opt.jsonData[0]).map(e => [e,e])
|
|
2184
|
+
);
|
|
2185
|
+
|
|
2186
|
+
const data = {entries: opt.jsonData, headers};
|
|
2187
|
+
render(data);
|
|
2188
|
+
} else if (opt.jsonUrl) {
|
|
2189
|
+
getSheetValues(opt.jsonUrl);
|
|
2190
|
+
} else if(opt.hojaNombre && opt.idSpread){
|
|
2191
|
+
const url = new GapiSheetData().url(opt.hojaNombre, opt.idSpread);
|
|
2192
|
+
getSheetValues(url);
|
|
2193
|
+
} else if(opt.hojaNumero && opt.idSpread){
|
|
2194
|
+
getSheetName(opt.hojaNumero);
|
|
2195
|
+
} else {
|
|
2196
|
+
throw "¡Error! No hay datos suficientes para crear la tabla.";
|
|
1113
2197
|
}
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
/**
|
|
1117
|
-
* Si la URL tiene un valor por _hash_ lo obtiene considerandolo su id.
|
|
1118
|
-
* @returns {void}
|
|
1119
|
-
*/
|
|
1120
|
-
const hasHash = () => {
|
|
1121
|
-
let hash = window.location.hash.replace("#", "");
|
|
1122
|
-
return hash || false;
|
|
1123
|
-
};
|
|
1124
|
-
|
|
1125
|
-
/**
|
|
1126
|
-
* Inicializa DataTable() y modifica elementos para adaptarlos a
|
|
1127
|
-
* GoogleSheets y requerimientos de ArGob.
|
|
1128
|
-
*/
|
|
1129
|
-
const initDataTable = () => {
|
|
1130
|
-
const searchType = jQuery.fn.DataTable.ext.type.search;
|
|
1131
|
-
searchType.string = data => {
|
|
1132
|
-
return (!data ?
|
|
1133
|
-
"" :
|
|
1134
|
-
(typeof data === "string" ?
|
|
1135
|
-
replaceSpecialChars(data) :
|
|
1136
|
-
data));
|
|
1137
|
-
};
|
|
1138
|
-
|
|
1139
|
-
searchType.html = data => {
|
|
1140
|
-
return (!data ?
|
|
1141
|
-
"" :
|
|
1142
|
-
(typeof data === "string" ?
|
|
1143
|
-
replaceSpecialChars(data.replace( /<.*?>/g, "")) :
|
|
1144
|
-
data));
|
|
1145
|
-
};
|
|
1146
|
-
|
|
1147
|
-
/**
|
|
1148
|
-
* Instacia DataTable()
|
|
1149
|
-
*/
|
|
1150
|
-
let tabla = jQuery("#ponchoTable").DataTable({
|
|
1151
|
-
"lengthChange": false,
|
|
1152
|
-
"autoWidth": false,
|
|
1153
|
-
"pageLength": opt.cantidadItems,
|
|
1154
|
-
"columnDefs": [
|
|
1155
|
-
{ "type": "html-num", "targets": opt.tipoNumero },
|
|
1156
|
-
{ "targets": opt.ocultarColumnas, "visible": false }
|
|
1157
|
-
],
|
|
1158
|
-
"ordering": opt.orden,
|
|
1159
|
-
"order": [
|
|
1160
|
-
[opt.ordenColumna - 1, opt.ordenTipo]
|
|
1161
|
-
],
|
|
1162
|
-
"dom": "<'row'<'col-sm-6'l><'col-sm-6'f>>" +
|
|
1163
|
-
"<'row'<'col-sm-12'i>>" +
|
|
1164
|
-
"<'row'<'col-sm-12'tr>>" +
|
|
1165
|
-
"<'row'<'col-md-offset-3 col-md-6 col-sm-offset-2 col-sm-8'p>>",
|
|
1166
|
-
"language": {
|
|
1167
|
-
"sProcessing": "Procesando...",
|
|
1168
|
-
"sLengthMenu": "Mostrar _MENU_ registros",
|
|
1169
|
-
"sZeroRecords": "No se encontraron resultados",
|
|
1170
|
-
"sEmptyTable": "Ningún dato disponible en esta tabla",
|
|
1171
|
-
"sInfo": "_TOTAL_ resultados",
|
|
1172
|
-
"sInfoEmpty": "No hay resultados",
|
|
1173
|
-
//"sInfoFiltered": "(filtrado de un total de _MAX_ registros)",
|
|
1174
|
-
"sInfoFiltered": "",
|
|
1175
|
-
"sInfoPostFix": "",
|
|
1176
|
-
"sSearch": "Buscar:",
|
|
1177
|
-
"sUrl": "",
|
|
1178
|
-
"sInfoThousands": ".",
|
|
1179
|
-
"sLoadingRecords": "Cargando...",
|
|
1180
|
-
|
|
1181
|
-
"oPaginate": {
|
|
1182
|
-
"sFirst": "<<",
|
|
1183
|
-
"sLast": ">>",
|
|
1184
|
-
"sNext": ">",
|
|
1185
|
-
"sPrevious": "<"
|
|
1186
|
-
},
|
|
1187
|
-
"oAria": {
|
|
1188
|
-
"sSortAscending":
|
|
1189
|
-
": Activar para ordenar la columna de manera ascendente",
|
|
1190
|
-
"sSortDescending":
|
|
1191
|
-
": Activar para ordenar la columna de manera descendente",
|
|
1192
|
-
"paginate": {
|
|
1193
|
-
"first": 'Ir a la primera página',
|
|
1194
|
-
"previous": 'Ir a la página anterior',
|
|
1195
|
-
"next": 'Ir a la página siguiente',
|
|
1196
|
-
"last": 'Ir a la última página'
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
});
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* Buscador por palabra
|
|
1204
|
-
* @summary Ejecuta la búsqueda en cada keyup.
|
|
1205
|
-
*/
|
|
1206
|
-
jQuery("#ponchoTableSearch").keyup(function() {
|
|
1207
|
-
tabla
|
|
1208
|
-
.search(jQuery.fn.DataTable.ext.type.search.string(this.value))
|
|
1209
|
-
.draw();
|
|
1210
|
-
});
|
|
1211
|
-
|
|
1212
|
-
// REMUEVE LOS FILTROS
|
|
1213
|
-
jQuery("#ponchoTable_filter").parent().parent().remove();
|
|
1214
|
-
|
|
1215
|
-
// MUESTRA FILTRO PERSONALIZADO
|
|
1216
|
-
const ponchoTableOption = document.querySelectorAll("#ponchoTableFiltro option");
|
|
1217
|
-
if (ponchoTableOption.length > 1) {
|
|
1218
|
-
document.querySelector("#ponchoTableFiltroCont").style.display = "block";
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
/**
|
|
1222
|
-
* Filtro en el change de cada select (filtro).
|
|
1223
|
-
*
|
|
1224
|
-
* @summary Por por cada interacción con un filtro, obtiene el índice de
|
|
1225
|
-
* columna y lo pasa con el valor del select a _dependantFilters(). Ésta
|
|
1226
|
-
* funciión redibuja los filtros en de forma dependiente según el valor
|
|
1227
|
-
* de la elección.
|
|
1228
|
-
* @see replaceSpecialChars() on poncho.min.js
|
|
1229
|
-
* @return {undefined}
|
|
1230
|
-
*/
|
|
1231
|
-
jQuery("select[data-filter]").change(function() {
|
|
1232
|
-
const column = jQuery(this).find("option:selected").data("column");
|
|
1233
|
-
const valFilter = jQuery(this).find("option:selected").val();
|
|
1234
|
-
|
|
1235
|
-
_dependantFilters(column, valFilter);
|
|
1236
|
-
|
|
1237
|
-
// Restablece los datos en la tabla
|
|
1238
|
-
tabla.columns().search("").columns().search("").draw();
|
|
1239
|
-
|
|
1240
|
-
const filters = Object.keys(filtro);
|
|
1241
|
-
const filterValues = _filterValues();
|
|
1242
|
-
const filterIndex = filter => {
|
|
1243
|
-
return Object
|
|
1244
|
-
.keys(gapi_data.headers)
|
|
1245
|
-
.indexOf(`filtro-${filter}`);
|
|
1246
|
-
};
|
|
1247
|
-
|
|
1248
|
-
filterValues.forEach((f, k) => {
|
|
1249
|
-
const columnIndex = filterIndex(filters[k]);
|
|
1250
|
-
const term = _searchTerm(filterValues[k]);
|
|
1251
|
-
const cleanTerm = _searchTerm(
|
|
1252
|
-
replaceSpecialChars(filterValues[k]));
|
|
1253
|
-
if(_isCustomFilter(k, filtro)){
|
|
1254
|
-
tabla.columns(columnIndex)
|
|
1255
|
-
.search(_toCompareString(filterValues[k]));
|
|
1256
|
-
} else {
|
|
1257
|
-
tabla
|
|
1258
|
-
.columns(columnIndex)
|
|
1259
|
-
.search(
|
|
1260
|
-
(filterValues[k] ? `^(${term}|${cleanTerm})$` : ""),
|
|
1261
|
-
true, false, true
|
|
1262
|
-
);
|
|
1263
|
-
}
|
|
1264
|
-
});
|
|
1265
|
-
tabla.draw();
|
|
1266
|
-
});
|
|
1267
|
-
|
|
1268
|
-
// Si está habilitada la búsqueda por hash.
|
|
1269
|
-
if(opt.hasOwnProperty("hash") && opt.hash){
|
|
1270
|
-
const term = hasHash();
|
|
1271
|
-
const searchTerm = (term ? decodeURIComponent(term) : "");
|
|
1272
|
-
const element = document.querySelector("#ponchoTableSearch");
|
|
1273
|
-
element.value = searchTerm;
|
|
1274
|
-
tabla
|
|
1275
|
-
.search(jQuery.fn.DataTable.ext.type.search.string(searchTerm))
|
|
1276
|
-
.draw();
|
|
1277
|
-
|
|
1278
|
-
}
|
|
1279
|
-
} // end initDataTable
|
|
1280
|
-
|
|
1281
|
-
/**
|
|
1282
|
-
* Imprime DataTable
|
|
1283
|
-
*
|
|
1284
|
-
* @param {object} data JSON data
|
|
1285
|
-
*/
|
|
1286
|
-
const render = data => {
|
|
1287
|
-
// Defino la variable global
|
|
1288
|
-
gapi_data = data;
|
|
1289
|
-
// Defino las entradas
|
|
1290
|
-
gapi_data.entries = (
|
|
1291
|
-
typeof opt.refactorEntries === "function" &&
|
|
1292
|
-
opt.refactorEntries !== null ?
|
|
1293
|
-
opt.refactorEntries(gapi_data.entries) : gapi_data.entries
|
|
1294
|
-
);
|
|
1295
|
-
// Defino los headers que se van a utilizar
|
|
1296
|
-
gapi_data.headers = (opt.hasOwnProperty("headers") && opt.headers ?
|
|
1297
|
-
opt.headers : gapi_data.headers);
|
|
1298
|
-
// Listado de filtros
|
|
1299
|
-
filtersList = Object
|
|
1300
|
-
.keys(gapi_data.headers)
|
|
1301
|
-
.filter(e => e.startsWith("filtro-"));
|
|
1302
|
-
|
|
1303
|
-
asFilter = (opt.asFilter ? opt.asFilter(gapi_data.entries) : {});
|
|
1304
|
-
filtro = flterMatrix(gapi_data, filtersList);
|
|
1305
|
-
|
|
1306
|
-
_filtersContainerClassList();
|
|
1307
|
-
_searchContainerClassList();
|
|
1308
|
-
_createTable(gapi_data);
|
|
1309
|
-
_createFilters(gapi_data);
|
|
1310
|
-
|
|
1311
|
-
document.querySelector("#ponchoTableSearchCont")
|
|
1312
|
-
.style.display = "block";
|
|
1313
|
-
document.querySelector("#ponchoTable")
|
|
1314
|
-
.classList.remove("state-loading");
|
|
1315
|
-
initDataTable();
|
|
1316
|
-
};
|
|
1317
|
-
|
|
1318
|
-
/**
|
|
1319
|
-
* Obtiene el sheet e inicializa la tabla y filtros.
|
|
1320
|
-
*
|
|
1321
|
-
* @param {string} url URL del dataset JSON
|
|
1322
|
-
*/
|
|
1323
|
-
const getSheetValues = url => {
|
|
1324
|
-
jQuery.getJSON(url, function(data){
|
|
1325
|
-
const gapi = new GapiSheetData();
|
|
1326
|
-
gapi_data = gapi.json_data(data);
|
|
1327
|
-
|
|
1328
|
-
render(gapi_data);
|
|
1329
|
-
}); // end async
|
|
1330
|
-
};
|
|
1331
|
-
|
|
1332
|
-
/**
|
|
1333
|
-
* Obtiene el sheet por número de hoja y nombre del spread.
|
|
1334
|
-
*
|
|
1335
|
-
* @param {integer} sheetNumber Número de hoja sin iniciar en 0.
|
|
1336
|
-
*/
|
|
1337
|
-
const getSheetName = sheetNumber => {
|
|
1338
|
-
const gapi = new GapiSheetData();
|
|
1339
|
-
const uriApi = [
|
|
1340
|
-
'https://sheets.googleapis.com/v4/spreadsheets/',
|
|
1341
|
-
opt.idSpread, '/?alt=json&key=',
|
|
1342
|
-
gapi.gapi_key].join("");
|
|
1343
|
-
|
|
1344
|
-
jQuery.getJSON(uriApi, function function_name(response) {
|
|
1345
|
-
var sheetName = response.sheets[sheetNumber - 1].properties.title;
|
|
1346
|
-
const uriSheet = gapi.url(sheetName, opt.idSpread);
|
|
1347
|
-
getSheetValues(uriSheet);
|
|
1348
|
-
});
|
|
1349
|
-
};
|
|
1350
|
-
|
|
1351
|
-
// Según el caso en optiones.
|
|
1352
|
-
if (opt.jsonData){
|
|
1353
|
-
const headers = Object.fromEntries(
|
|
1354
|
-
Object.keys(opt.jsonData[0]).map(e => [e,e])
|
|
1355
|
-
);
|
|
1356
|
-
const data = {entries: opt.jsonData, headers: headers};
|
|
1357
|
-
render(data);
|
|
1358
|
-
} else if (opt.jsonUrl) {
|
|
1359
|
-
getSheetValues(opt.jsonUrl);
|
|
1360
|
-
} else if(opt.hojaNombre && opt.idSpread){
|
|
1361
|
-
const url = new GapiSheetData().url(opt.hojaNombre, opt.idSpread);
|
|
1362
|
-
getSheetValues(url);
|
|
1363
|
-
} else if(opt.hojaNumero && opt.idSpread){
|
|
1364
|
-
getSheetName(opt.hojaNumero);
|
|
1365
|
-
} else {
|
|
1366
|
-
throw "¡Error! No hay datos suficientes para crear la tabla.";
|
|
1367
|
-
}
|
|
1368
2198
|
|
|
1369
2199
|
};
|
|
1370
2200
|
|
|
@@ -2878,6 +3708,14 @@ function ponchoChart(opt) {
|
|
|
2878
3708
|
*/
|
|
2879
3709
|
const gapi_legacy = (response) => {
|
|
2880
3710
|
|
|
3711
|
+
if (!response || !response.values || response.values.length === 0) {
|
|
3712
|
+
throw new TypeError("Invalid response format");
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3715
|
+
if (!Array.isArray(response.values) || !Array.isArray(response.values[0])) {
|
|
3716
|
+
throw new TypeError("Invalid response format: values should be arrays");
|
|
3717
|
+
}
|
|
3718
|
+
|
|
2881
3719
|
const keys = response.values[0];
|
|
2882
3720
|
const regex = / |\/|_/ig;
|
|
2883
3721
|
let entry = [];
|
|
@@ -2897,7 +3735,9 @@ const gapi_legacy = (response) => {
|
|
|
2897
3735
|
};
|
|
2898
3736
|
|
|
2899
3737
|
|
|
2900
|
-
|
|
3738
|
+
if (typeof exports !== "undefined") {
|
|
3739
|
+
module.exports = gapi_legacy;
|
|
3740
|
+
}
|
|
2901
3741
|
|
|
2902
3742
|
/**
|
|
2903
3743
|
* PONCHO MAP
|
|
@@ -2944,6 +3784,7 @@ class PonchoMap {
|
|
|
2944
3784
|
no_info: false,
|
|
2945
3785
|
title: false,
|
|
2946
3786
|
id: "id",
|
|
3787
|
+
id_mixing: [],
|
|
2947
3788
|
template: false,
|
|
2948
3789
|
template_structure: {
|
|
2949
3790
|
// lead: [],
|
|
@@ -2959,11 +3800,27 @@ class PonchoMap {
|
|
|
2959
3800
|
definition_tag: "dd",
|
|
2960
3801
|
term_classlist: ["h6", "m-b-0"],
|
|
2961
3802
|
term_tag: "dt",
|
|
2962
|
-
title_classlist: ["h4","
|
|
3803
|
+
title_classlist: ["h4","pm-color-primary","m-t-0"]
|
|
2963
3804
|
},
|
|
3805
|
+
fit_bounds_onevent: true,
|
|
2964
3806
|
allowed_tags: [],
|
|
2965
3807
|
template_innerhtml: false,
|
|
2966
3808
|
template_markdown: false,
|
|
3809
|
+
theme_ui: false,
|
|
3810
|
+
theme_map: false,
|
|
3811
|
+
theme_tool: true,
|
|
3812
|
+
map_opacity: 1,
|
|
3813
|
+
map_background: "#DDD",
|
|
3814
|
+
theme: "default",
|
|
3815
|
+
default_themes: [
|
|
3816
|
+
["default", "Original"],
|
|
3817
|
+
["contrast", "Alto contraste"],
|
|
3818
|
+
["dark", "Oscuro"],
|
|
3819
|
+
["grayscale", "Gris"],
|
|
3820
|
+
// ["sepia", "Sepia"],
|
|
3821
|
+
// ["blue", "Azul"],
|
|
3822
|
+
["relax", "Relax"]
|
|
3823
|
+
],
|
|
2967
3824
|
markdown_options: {
|
|
2968
3825
|
extensions :[
|
|
2969
3826
|
"details",
|
|
@@ -2994,28 +3851,38 @@ class PonchoMap {
|
|
|
2994
3851
|
map_anchor_zoom: 16,
|
|
2995
3852
|
map_zoom: 4,
|
|
2996
3853
|
min_zoom: 2,
|
|
3854
|
+
map_init_options: {
|
|
3855
|
+
// zoomSnap: .2,
|
|
3856
|
+
// zoomControl: false,
|
|
3857
|
+
// scrollWheelZoom: false,
|
|
3858
|
+
// touchZoom: false,
|
|
3859
|
+
// doubleClickZoom: false,
|
|
3860
|
+
// scrollWheelZoom: false,
|
|
3861
|
+
// boxZoom: false,
|
|
3862
|
+
// dragging:false
|
|
3863
|
+
},
|
|
2997
3864
|
reset_zoom: true,
|
|
2998
3865
|
latitud: "latitud",
|
|
2999
3866
|
longitud: "longitud",
|
|
3000
3867
|
marker: "azul",
|
|
3001
3868
|
tooltip: false,
|
|
3002
3869
|
tooltip_options:{
|
|
3003
|
-
|
|
3870
|
+
permanent: false,
|
|
3004
3871
|
className: "leaflet-tooltip-own",
|
|
3005
3872
|
direction: "auto",
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3873
|
+
offset: [13,-18],
|
|
3874
|
+
sticky: false,
|
|
3875
|
+
opacity: 1,
|
|
3009
3876
|
},
|
|
3010
3877
|
marker_cluster_options: {
|
|
3011
|
-
spiderfyOnMaxZoom:
|
|
3878
|
+
spiderfyOnMaxZoom: true,
|
|
3012
3879
|
showCoverageOnHover: false,
|
|
3013
3880
|
zoomToBoundsOnClick: true,
|
|
3014
|
-
maxClusterRadius:
|
|
3015
|
-
spiderfyDistanceMultiplier:
|
|
3881
|
+
maxClusterRadius: 30,
|
|
3882
|
+
spiderfyDistanceMultiplier: 0.5,
|
|
3016
3883
|
spiderLegPolylineOptions: {
|
|
3017
3884
|
weight: 1,
|
|
3018
|
-
color: "#
|
|
3885
|
+
color: "#666666",
|
|
3019
3886
|
opacity: 0.5,
|
|
3020
3887
|
"fill-opacity": 0.5
|
|
3021
3888
|
}
|
|
@@ -3045,7 +3912,9 @@ class PonchoMap {
|
|
|
3045
3912
|
this.header_icons = opts.header_icons;
|
|
3046
3913
|
this.hash = opts.hash;
|
|
3047
3914
|
this.scroll = opts.scroll;
|
|
3915
|
+
this.fit_bounds_onevent = opts.fit_bounds_onevent;
|
|
3048
3916
|
this.map_view = opts.map_view;
|
|
3917
|
+
this.map_init_options = opts.map_init_options;
|
|
3049
3918
|
this.anchor_delay = opts.anchor_delay;
|
|
3050
3919
|
this.map_zoom = opts.map_zoom;
|
|
3051
3920
|
this.min_zoom = opts.min_zoom;
|
|
@@ -3055,7 +3924,16 @@ class PonchoMap {
|
|
|
3055
3924
|
this.marker_cluster_options = opts.marker_cluster_options;
|
|
3056
3925
|
this.marker_color = opts.marker;
|
|
3057
3926
|
this.id = opts.id;
|
|
3927
|
+
this.id_mixing = opts.id_mixing;
|
|
3058
3928
|
this.title = opts.title;
|
|
3929
|
+
this.map_background = opts.map_background;
|
|
3930
|
+
this.theme = opts.theme;
|
|
3931
|
+
this.theme_tool = opts.theme_tool;
|
|
3932
|
+
this.default_themes = opts.default_themes;
|
|
3933
|
+
this.temes_not_visibles = [["transparent", "Transparent"]];
|
|
3934
|
+
this.theme_ui = opts.theme_ui;
|
|
3935
|
+
this.theme_map = opts.theme_map;
|
|
3936
|
+
this.map_opacity = opts.map_opacity;
|
|
3059
3937
|
this.latitude = opts.latitud;
|
|
3060
3938
|
this.longitude = opts.longitud;
|
|
3061
3939
|
this.slider = opts.slider;
|
|
@@ -3067,6 +3945,7 @@ class PonchoMap {
|
|
|
3067
3945
|
this.scope_sufix = `--${this.scope}`;
|
|
3068
3946
|
this.content_selector = (opts.content_selector ?
|
|
3069
3947
|
opts.content_selector : `.js-content${this.scope_sufix}`);
|
|
3948
|
+
this.content_outside = (this.content_selector !== `.js-content${this.scope_sufix}` ? true : false);
|
|
3070
3949
|
this.data = this.formatInput(data);
|
|
3071
3950
|
this.geometryTypes = [
|
|
3072
3951
|
"Point",
|
|
@@ -3087,9 +3966,13 @@ class PonchoMap {
|
|
|
3087
3966
|
this.geojson;
|
|
3088
3967
|
|
|
3089
3968
|
// OSM
|
|
3090
|
-
this.map = new L.map(this.map_selector, {
|
|
3969
|
+
this.map = new L.map(this.map_selector, {
|
|
3970
|
+
renderer: L.svg(),
|
|
3971
|
+
...this.map_init_options
|
|
3972
|
+
}
|
|
3091
3973
|
).setView(this.map_view, this.map_zoom);
|
|
3092
|
-
this.titleLayer = new L.tileLayer("https://mapa-ign.argentina.gob.ar/osm/{z}/{x}/{-y}.png",
|
|
3974
|
+
this.titleLayer = new L.tileLayer("https://mapa-ign.argentina.gob.ar/osm/{z}/{x}/{-y}.png",
|
|
3975
|
+
{
|
|
3093
3976
|
attribution: ("Contribuidores: "
|
|
3094
3977
|
+ "<a href=\"https://www.ign.gob.ar/AreaServicios/Argenmap/Introduccion\" "
|
|
3095
3978
|
+ "target=\"_blank\">"
|
|
@@ -3102,6 +3985,243 @@ class PonchoMap {
|
|
|
3102
3985
|
this.ponchoLoaderTimeout;
|
|
3103
3986
|
}
|
|
3104
3987
|
|
|
3988
|
+
|
|
3989
|
+
//
|
|
3990
|
+
// TEMA PARA EL MAPA
|
|
3991
|
+
//
|
|
3992
|
+
|
|
3993
|
+
/**
|
|
3994
|
+
* Modifica la opacidad del mapa
|
|
3995
|
+
* @param {double|string} value Número _(double)_, o porcentaje de valor
|
|
3996
|
+
* @example
|
|
3997
|
+
* mapOpacity(0.5)
|
|
3998
|
+
* mapOpacity("50%")
|
|
3999
|
+
* @returns {undefined}
|
|
4000
|
+
*/
|
|
4001
|
+
mapOpacity = (value=false) => {
|
|
4002
|
+
const opacity = (value ? value : this.map_opacity);
|
|
4003
|
+
document
|
|
4004
|
+
.querySelectorAll(
|
|
4005
|
+
`${this.scope_selector} .leaflet-pane .leaflet-tile-pane`)
|
|
4006
|
+
.forEach(e => e.style.opacity=opacity);
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
|
|
4010
|
+
/**
|
|
4011
|
+
* Define el color de fondo para el mapa.
|
|
4012
|
+
* @param {string} value Color en hexadecimal o cualquier sistema de color
|
|
4013
|
+
* aceptado por html.
|
|
4014
|
+
* @example
|
|
4015
|
+
* // #ffcc00
|
|
4016
|
+
* // Se representará como: style="background-color:#ffcc00;"
|
|
4017
|
+
* mapBackgroundColor("#ffcc00")
|
|
4018
|
+
* @returns {undefined}
|
|
4019
|
+
*/
|
|
4020
|
+
mapBackgroundColor = (value=false) => {
|
|
4021
|
+
const color = (value ? value : this.map_background);
|
|
4022
|
+
document
|
|
4023
|
+
.querySelectorAll(`${this.scope_selector} .leaflet-container`)
|
|
4024
|
+
.forEach(e => e.style.backgroundColor = color);
|
|
4025
|
+
};
|
|
4026
|
+
|
|
4027
|
+
|
|
4028
|
+
/**
|
|
4029
|
+
* Crea el menú para cambiar de temas
|
|
4030
|
+
* @returns {undefined}
|
|
4031
|
+
*/
|
|
4032
|
+
_menuTheme = () => {
|
|
4033
|
+
if(!this.theme_tool){
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
document
|
|
4037
|
+
.querySelectorAll(`#themes-tool${this.scope_sufix}`)
|
|
4038
|
+
.forEach(ele => ele.remove());
|
|
4039
|
+
|
|
4040
|
+
const navContainer = document.createElement("ul");
|
|
4041
|
+
navContainer.classList.add(
|
|
4042
|
+
"pm-list-unstyled", "pm-list",
|
|
4043
|
+
"pm-tools",
|
|
4044
|
+
`js-themes-tool${this.scope_sufix}`
|
|
4045
|
+
);
|
|
4046
|
+
|
|
4047
|
+
|
|
4048
|
+
const item = document.createElement("li");
|
|
4049
|
+
item.setAttribute("tabindex", "-1");
|
|
4050
|
+
item.dataset.toggle="true";
|
|
4051
|
+
|
|
4052
|
+
const icon = document.createElement("i");
|
|
4053
|
+
icon.setAttribute("aria-hidden", "true");
|
|
4054
|
+
icon.classList.add("pmi", "pmi-adjust");
|
|
4055
|
+
|
|
4056
|
+
const button = document.createElement("button");
|
|
4057
|
+
button.title = "Cambiar tema";
|
|
4058
|
+
button.tabIndex = "0";
|
|
4059
|
+
button.classList.add("pm-btn", "pm-btn-rounded-circle");
|
|
4060
|
+
button.appendChild(icon);
|
|
4061
|
+
button.setAttribute("role", "button");
|
|
4062
|
+
button.setAttribute("aria-label", "Abre el panel de temas");
|
|
4063
|
+
|
|
4064
|
+
const list = document.createElement("ul");
|
|
4065
|
+
list.classList.add(
|
|
4066
|
+
"pm-container", "pm-list", "pm-list-unstyled",
|
|
4067
|
+
"pm-p-1", "pm-caret", "pm-caret-b", "pm-toggle");
|
|
4068
|
+
|
|
4069
|
+
// Botón para restablecer el mapa
|
|
4070
|
+
const restart = document.createElement("button");
|
|
4071
|
+
restart.textContent = "Restablecer";
|
|
4072
|
+
restart.classList.add("pm-item-link", "js-reset-theme");
|
|
4073
|
+
const li = document.createElement("li");
|
|
4074
|
+
li.classList.add("pm-item-separator");
|
|
4075
|
+
li.appendChild(restart);
|
|
4076
|
+
list.appendChild(li);
|
|
4077
|
+
|
|
4078
|
+
this.default_themes.map(m => m[0]).forEach((value, key) => {
|
|
4079
|
+
const buttonTheme = document.createElement("button");
|
|
4080
|
+
buttonTheme.dataset.theme = value;
|
|
4081
|
+
buttonTheme.textContent = this.default_themes[key][1];
|
|
4082
|
+
buttonTheme.classList.add("js-set-theme", "pm-item-link");
|
|
4083
|
+
|
|
4084
|
+
const li = document.createElement("li");
|
|
4085
|
+
li.appendChild(buttonTheme);
|
|
4086
|
+
|
|
4087
|
+
list.appendChild(li);
|
|
4088
|
+
});
|
|
4089
|
+
|
|
4090
|
+
item.appendChild(button);
|
|
4091
|
+
item.appendChild(list);
|
|
4092
|
+
navContainer.appendChild(item)
|
|
4093
|
+
|
|
4094
|
+
const element = document.querySelectorAll(this.scope_selector);
|
|
4095
|
+
element.forEach(e => e.appendChild(navContainer));
|
|
4096
|
+
|
|
4097
|
+
// listeners
|
|
4098
|
+
document
|
|
4099
|
+
.querySelectorAll(".js-reset-theme")
|
|
4100
|
+
.forEach(ele => ele.addEventListener(
|
|
4101
|
+
"click", () => {
|
|
4102
|
+
localStorage.removeItem("mapTheme");
|
|
4103
|
+
this._removeThemes();
|
|
4104
|
+
this._setThemes();
|
|
4105
|
+
})
|
|
4106
|
+
);
|
|
4107
|
+
|
|
4108
|
+
document
|
|
4109
|
+
.querySelectorAll(".js-set-theme")
|
|
4110
|
+
.forEach(ele => ele.addEventListener(
|
|
4111
|
+
"click", () => {
|
|
4112
|
+
const th = ele.dataset.theme;
|
|
4113
|
+
this.useTheme(th);
|
|
4114
|
+
localStorage.setItem("mapTheme", th);
|
|
4115
|
+
})
|
|
4116
|
+
);
|
|
4117
|
+
};
|
|
4118
|
+
|
|
4119
|
+
|
|
4120
|
+
/**
|
|
4121
|
+
* Compone los estilos según la elección del usuario.
|
|
4122
|
+
* @param {string} theme Nombre del tema
|
|
4123
|
+
* @param {object} prefix Lista de prefijos. ui o map
|
|
4124
|
+
* @returns {object} Array con los estilos definidos.
|
|
4125
|
+
*/
|
|
4126
|
+
_setThemeStyles = (theme=false, prefix=["ui", "map"]) => prefix.map(m => {
|
|
4127
|
+
return (["ui", "map"].includes(m) ? `${m}-${theme}` : false);
|
|
4128
|
+
});
|
|
4129
|
+
|
|
4130
|
+
|
|
4131
|
+
/**
|
|
4132
|
+
* Remueve los estilos de tema
|
|
4133
|
+
* @param {object} prefix Lista de prefijos. ui o map
|
|
4134
|
+
* @returns {undefined}
|
|
4135
|
+
*/
|
|
4136
|
+
_removeThemes = (prefix=["ui", "map"]) => {
|
|
4137
|
+
const element = document.querySelectorAll(this.scope_selector);
|
|
4138
|
+
element.forEach(ele => {
|
|
4139
|
+
[
|
|
4140
|
+
...this.default_themes,
|
|
4141
|
+
...this.temes_not_visibles
|
|
4142
|
+
].map(m => m[0]).forEach(th => {
|
|
4143
|
+
ele.classList.remove(...this._setThemeStyles(th, prefix));
|
|
4144
|
+
});
|
|
4145
|
+
});
|
|
4146
|
+
};
|
|
4147
|
+
|
|
4148
|
+
|
|
4149
|
+
/**
|
|
4150
|
+
* Agrega un tema en el mapa e interfase.
|
|
4151
|
+
* @param {string} theme Nombre del tema
|
|
4152
|
+
* @param {object} prefix Lista de prefijos. ui o map
|
|
4153
|
+
* @returns {undefined}
|
|
4154
|
+
*/
|
|
4155
|
+
_setTheme = (theme, prefix) => {
|
|
4156
|
+
const element = document.querySelectorAll(this.scope_selector);
|
|
4157
|
+
this._removeThemes(prefix);
|
|
4158
|
+
element.forEach(ele => {
|
|
4159
|
+
ele.classList.add( ...this._setThemeStyles(theme, prefix) );
|
|
4160
|
+
});
|
|
4161
|
+
}
|
|
4162
|
+
|
|
4163
|
+
|
|
4164
|
+
/**
|
|
4165
|
+
* Permite setear un tema completo
|
|
4166
|
+
* @param {string} theme Nombre del tema
|
|
4167
|
+
* @returns {undefined}
|
|
4168
|
+
*/
|
|
4169
|
+
useTheme = (theme = false) => {
|
|
4170
|
+
const useTheme = (theme ? theme : this.theme);
|
|
4171
|
+
this._setTheme(useTheme, ["ui", "map"]);
|
|
4172
|
+
}
|
|
4173
|
+
|
|
4174
|
+
|
|
4175
|
+
/**
|
|
4176
|
+
* Setea un tema para el mapa
|
|
4177
|
+
* @param {string} theme Nombre del tema
|
|
4178
|
+
* @returns {undefined}
|
|
4179
|
+
*/
|
|
4180
|
+
useMapTheme = theme => this._setTheme(theme, ["map"]);
|
|
4181
|
+
|
|
4182
|
+
|
|
4183
|
+
/**
|
|
4184
|
+
* Setea un tema para el mapa
|
|
4185
|
+
* @param {string} theme Nombre del tema
|
|
4186
|
+
* @returns {undefined}
|
|
4187
|
+
*/
|
|
4188
|
+
useUiTheme = theme => this._setTheme(theme, ["ui"]);
|
|
4189
|
+
|
|
4190
|
+
|
|
4191
|
+
/**
|
|
4192
|
+
* Setea el tema elegido por el usuario o el que lleva por defecto.
|
|
4193
|
+
* @returns {undefined}
|
|
4194
|
+
*/
|
|
4195
|
+
_setThemes = () => {
|
|
4196
|
+
if(localStorage.hasOwnProperty("mapTheme")){
|
|
4197
|
+
this._setTheme(localStorage.getItem("mapTheme"), ["ui", "map"]);
|
|
4198
|
+
return;
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4201
|
+
if(!this.theme_ui && !this.theme_map){
|
|
4202
|
+
this.useTheme();
|
|
4203
|
+
return;
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4206
|
+
if(this.theme_ui){
|
|
4207
|
+
this._setTheme(this.theme_ui, ["ui"]);
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
if(this.theme_map){
|
|
4211
|
+
this._setTheme(this.theme_map, ["map"]);
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
|
|
4216
|
+
/**
|
|
4217
|
+
* Alias de sluglify
|
|
4218
|
+
*
|
|
4219
|
+
* @param {string} val Texto a formatear
|
|
4220
|
+
* @returns {string}
|
|
4221
|
+
*/
|
|
4222
|
+
_slugify = val => slugify(val);
|
|
4223
|
+
|
|
4224
|
+
|
|
3105
4225
|
/**
|
|
3106
4226
|
* Es un geoJSON
|
|
3107
4227
|
*
|
|
@@ -3117,6 +4237,7 @@ class PonchoMap {
|
|
|
3117
4237
|
return false;
|
|
3118
4238
|
};
|
|
3119
4239
|
|
|
4240
|
+
|
|
3120
4241
|
/**
|
|
3121
4242
|
* JSON input
|
|
3122
4243
|
*
|
|
@@ -3126,6 +4247,7 @@ class PonchoMap {
|
|
|
3126
4247
|
return this.data.features;
|
|
3127
4248
|
}
|
|
3128
4249
|
|
|
4250
|
+
|
|
3129
4251
|
/**
|
|
3130
4252
|
* Retrona las entradas en formato geoJSON
|
|
3131
4253
|
*/
|
|
@@ -3185,7 +4307,7 @@ class PonchoMap {
|
|
|
3185
4307
|
);
|
|
3186
4308
|
|
|
3187
4309
|
const title = document.createElement("h2");
|
|
3188
|
-
title.classList.add("h6", "title", "
|
|
4310
|
+
title.classList.add("h6", "title", "pm-visually-hidden");
|
|
3189
4311
|
title.textContent = "¡Se produjo un error!";
|
|
3190
4312
|
|
|
3191
4313
|
container.appendChild(mapIcon);
|
|
@@ -3282,6 +4404,42 @@ class PonchoMap {
|
|
|
3282
4404
|
};
|
|
3283
4405
|
|
|
3284
4406
|
|
|
4407
|
+
/**
|
|
4408
|
+
* El indice id_mixing ¿Está siendo usado?
|
|
4409
|
+
* @returns {boolean}
|
|
4410
|
+
*/
|
|
4411
|
+
_isIdMixing = () => (Array.isArray(this.id_mixing) &&
|
|
4412
|
+
this.id_mixing > 0 || typeof this.id_mixing === 'function');
|
|
4413
|
+
|
|
4414
|
+
|
|
4415
|
+
/**
|
|
4416
|
+
* Array con valores a concatenar en el id.
|
|
4417
|
+
*
|
|
4418
|
+
* @summary Dependiendo de la opción que haya elegido el usario, retorna
|
|
4419
|
+
* una array de valors pasado por funcion o _array object_.
|
|
4420
|
+
* @param {object} entry Objeto con una entrada del geoJson
|
|
4421
|
+
* @returns {object} Array con los valores a concatenar.
|
|
4422
|
+
*/
|
|
4423
|
+
_idMixing = entry => {
|
|
4424
|
+
if(!this._isIdMixing()){
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
|
|
4428
|
+
if(typeof this.id_mixing === "function"){
|
|
4429
|
+
return this.id_mixing(this, entry).join('');
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
const values = this.id_mixing.map(val => {
|
|
4433
|
+
if(entry.properties[val]){
|
|
4434
|
+
return entry.properties[val].toString();
|
|
4435
|
+
}
|
|
4436
|
+
return val;
|
|
4437
|
+
});
|
|
4438
|
+
|
|
4439
|
+
return this._slugify(values.join("-"));
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
|
|
3285
4443
|
/**
|
|
3286
4444
|
* Crea una entrada ID autonumerada si no posee una.
|
|
3287
4445
|
*
|
|
@@ -3293,21 +4451,30 @@ class PonchoMap {
|
|
|
3293
4451
|
* @return {object}
|
|
3294
4452
|
*/
|
|
3295
4453
|
_setIdIfNotExists = (entries) => {
|
|
3296
|
-
const
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
const auto_id = k + 1;
|
|
3304
|
-
const use_title = (this.title && v.properties[this.title] ?
|
|
3305
|
-
`-${slugify(v.properties[this.title])}` : "");
|
|
3306
|
-
v.properties.id = auto_id + use_title;
|
|
3307
|
-
return v;
|
|
3308
|
-
});
|
|
3309
|
-
entries.features = new_entries;
|
|
4454
|
+
const hasId = entries.features
|
|
4455
|
+
.filter((_, k) => k === 0)
|
|
4456
|
+
.every(e => e.properties.hasOwnProperty("id"));
|
|
4457
|
+
|
|
4458
|
+
// Si no se configuró id_mixing y el json tiene id.
|
|
4459
|
+
if(!this._isIdMixing() && hasId){
|
|
4460
|
+
return entries;
|
|
3310
4461
|
}
|
|
4462
|
+
|
|
4463
|
+
const newEntries = entries.features.map((entry, k) => {
|
|
4464
|
+
if(this._isIdMixing()){
|
|
4465
|
+
// Procesa la opción de id_mixing
|
|
4466
|
+
entry.properties.id = this._idMixing(entry);
|
|
4467
|
+
} else {
|
|
4468
|
+
// Genera un ID automático
|
|
4469
|
+
const autoId = k + 1;
|
|
4470
|
+
const useTitle = (this.title && entry.properties[this.title] ?
|
|
4471
|
+
this._slugify(entry.properties[this.title]) : "");
|
|
4472
|
+
entry.properties.id = [autoId, useTitle].filter(f=>f).join('-');
|
|
4473
|
+
}
|
|
4474
|
+
|
|
4475
|
+
return entry;
|
|
4476
|
+
});
|
|
4477
|
+
entries.features = newEntries;
|
|
3311
4478
|
return entries;
|
|
3312
4479
|
};
|
|
3313
4480
|
|
|
@@ -3319,9 +4486,16 @@ class PonchoMap {
|
|
|
3319
4486
|
* @return {undefined}
|
|
3320
4487
|
*/
|
|
3321
4488
|
addHash = (value) => {
|
|
3322
|
-
|
|
3323
|
-
|
|
4489
|
+
|
|
4490
|
+
if (typeof value !== "string" && !value) {
|
|
4491
|
+
console.error('Invalid value provided to update hash');
|
|
4492
|
+
return;
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4495
|
+
if (!this.hash || this.no_info) {
|
|
4496
|
+
return;
|
|
3324
4497
|
}
|
|
4498
|
+
|
|
3325
4499
|
window.location.hash = `#${value}`;
|
|
3326
4500
|
};
|
|
3327
4501
|
|
|
@@ -3333,9 +4507,16 @@ class PonchoMap {
|
|
|
3333
4507
|
* @return {object}
|
|
3334
4508
|
*/
|
|
3335
4509
|
entry = (id) => {
|
|
3336
|
-
return this.entries.find(e =>
|
|
4510
|
+
return this.entries.find(e => {
|
|
4511
|
+
if(e?.properties && e.properties[this.id] === id &&
|
|
4512
|
+
e.properties?.["pm-interactive"] !== "n"){
|
|
4513
|
+
return true;
|
|
4514
|
+
}
|
|
4515
|
+
return false;
|
|
4516
|
+
});
|
|
3337
4517
|
}
|
|
3338
4518
|
|
|
4519
|
+
|
|
3339
4520
|
/**
|
|
3340
4521
|
* Busca un término en un listado de entradas.
|
|
3341
4522
|
*
|
|
@@ -3355,6 +4536,7 @@ class PonchoMap {
|
|
|
3355
4536
|
return entries;
|
|
3356
4537
|
};
|
|
3357
4538
|
|
|
4539
|
+
|
|
3358
4540
|
/**
|
|
3359
4541
|
* Busca un término en cada uno de los indices de una entrada.
|
|
3360
4542
|
*/
|
|
@@ -3597,7 +4779,7 @@ class PonchoMap {
|
|
|
3597
4779
|
* Crea el bloque html para el slider.
|
|
3598
4780
|
*/
|
|
3599
4781
|
_renderSlider = () => {
|
|
3600
|
-
if(!this.render_slider){
|
|
4782
|
+
if(!this.render_slider || this.content_outside){
|
|
3601
4783
|
return;
|
|
3602
4784
|
} else if(this.no_info){
|
|
3603
4785
|
return;
|
|
@@ -3612,7 +4794,7 @@ class PonchoMap {
|
|
|
3612
4794
|
close_button.title = "Cerrar panel";
|
|
3613
4795
|
close_button.setAttribute("role", "button");
|
|
3614
4796
|
close_button.setAttribute("aria-label", "Cerrar panel de información");
|
|
3615
|
-
close_button.innerHTML = "<span class=\"
|
|
4797
|
+
close_button.innerHTML = "<span class=\"pm-visually-hidden\">Cerrar</span>✕";
|
|
3616
4798
|
|
|
3617
4799
|
const anchor = document.createElement("a");
|
|
3618
4800
|
|
|
@@ -3632,7 +4814,7 @@ class PonchoMap {
|
|
|
3632
4814
|
container.setAttribute("role", "region");
|
|
3633
4815
|
container.setAttribute("aria-live", "polite");
|
|
3634
4816
|
container.setAttribute("aria-label", "Panel de información");
|
|
3635
|
-
container.classList.add("slider",`js-slider${this.scope_sufix}`);
|
|
4817
|
+
container.classList.add("pm-container", "slider",`js-slider${this.scope_sufix}`);
|
|
3636
4818
|
container.id = `slider${this.scope_sufix}`;
|
|
3637
4819
|
container.appendChild(close_button);
|
|
3638
4820
|
container.appendChild(anchor);
|
|
@@ -3643,14 +4825,26 @@ class PonchoMap {
|
|
|
3643
4825
|
};
|
|
3644
4826
|
|
|
3645
4827
|
|
|
4828
|
+
_removeTooltips = () => {
|
|
4829
|
+
let _this = this;
|
|
4830
|
+
this.map.eachLayer(function(layer) {
|
|
4831
|
+
if(layer.options.pane === "tooltipPane") {
|
|
4832
|
+
layer.removeFrom(_this.map);
|
|
4833
|
+
}
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4837
|
+
|
|
3646
4838
|
/**
|
|
3647
4839
|
* Proyecta el slider y hace zoom en el marker.
|
|
3648
4840
|
*/
|
|
3649
|
-
_showSlider =
|
|
4841
|
+
_showSlider = layer => {
|
|
4842
|
+
this._removeTooltips();
|
|
4843
|
+
|
|
3650
4844
|
if(layer.hasOwnProperty("_latlng")){
|
|
3651
4845
|
this.map.setView(layer._latlng, this.map_anchor_zoom);
|
|
3652
|
-
} else {
|
|
3653
|
-
this.map.fitBounds(layer.getBounds());
|
|
4846
|
+
} else if(this.fit_bounds_onevent) {
|
|
4847
|
+
this.map.fitBounds(layer.getBounds().pad(0.005));
|
|
3654
4848
|
}
|
|
3655
4849
|
layer.fireEvent("click");
|
|
3656
4850
|
};
|
|
@@ -3665,7 +4859,7 @@ class PonchoMap {
|
|
|
3665
4859
|
layer.openPopup();
|
|
3666
4860
|
});
|
|
3667
4861
|
} else {
|
|
3668
|
-
this.map.fitBounds(layer.getBounds());
|
|
4862
|
+
this.map.fitBounds(layer.getBounds().pad(0.005));
|
|
3669
4863
|
layer.openPopup();
|
|
3670
4864
|
}
|
|
3671
4865
|
};
|
|
@@ -3703,26 +4897,33 @@ class PonchoMap {
|
|
|
3703
4897
|
|
|
3704
4898
|
/**
|
|
3705
4899
|
* Muestra un marker
|
|
4900
|
+
*
|
|
3706
4901
|
* @param {string|integer} id Valor identificador del marker.
|
|
4902
|
+
* @returns {undefined}
|
|
3707
4903
|
*/
|
|
3708
|
-
gotoEntry =
|
|
4904
|
+
gotoEntry = id => {
|
|
3709
4905
|
const entry = this.entry(id);
|
|
3710
4906
|
const setAction = (layer, id, entry) => {
|
|
4907
|
+
|
|
3711
4908
|
if(!layer.options.hasOwnProperty("id")){
|
|
3712
4909
|
return;
|
|
3713
4910
|
}
|
|
4911
|
+
|
|
3714
4912
|
if(layer.options.id == id){
|
|
3715
4913
|
this._setSelectedMarker(id, layer);
|
|
4914
|
+
|
|
3716
4915
|
if(this.hash){
|
|
3717
4916
|
this.addHash(id);
|
|
3718
4917
|
}
|
|
3719
|
-
|
|
4918
|
+
|
|
4919
|
+
if(this.slider){
|
|
3720
4920
|
this._showSlider(layer, entry);
|
|
3721
4921
|
} else {
|
|
3722
4922
|
this._showPopup(layer);
|
|
3723
4923
|
}
|
|
3724
4924
|
}
|
|
3725
4925
|
};
|
|
4926
|
+
|
|
3726
4927
|
this.markers.eachLayer(layer => setAction(layer, id, entry));
|
|
3727
4928
|
this.map.eachLayer(layer => {
|
|
3728
4929
|
if(layer.hasOwnProperty("feature") &&
|
|
@@ -3739,20 +4940,22 @@ class PonchoMap {
|
|
|
3739
4940
|
* que evaluar el tipo de objeto geoJSON.
|
|
3740
4941
|
* @param {object} layer
|
|
3741
4942
|
*/
|
|
3742
|
-
_setClickeable =
|
|
4943
|
+
_setClickeable = layer => {
|
|
3743
4944
|
layer.on("keypress click", (e) => {
|
|
3744
4945
|
document
|
|
3745
4946
|
.querySelectorAll(".marker--active")
|
|
3746
4947
|
.forEach(e => e.classList.remove("marker--active"));
|
|
3747
4948
|
|
|
3748
|
-
|
|
4949
|
+
|
|
4950
|
+
["_icon", "_path"].forEach(ele => {
|
|
3749
4951
|
if(!e.sourceTarget.hasOwnProperty(ele)){
|
|
3750
4952
|
return;
|
|
3751
4953
|
}
|
|
3752
4954
|
e.sourceTarget[ele].classList.add("marker--active");
|
|
3753
4955
|
});
|
|
4956
|
+
|
|
3754
4957
|
const content = this.entries.find(e => {
|
|
3755
|
-
return e.properties[this.id]
|
|
4958
|
+
return (e?.properties && e.properties[this.id]===layer.options.id);
|
|
3756
4959
|
});
|
|
3757
4960
|
this.setContent(content.properties);
|
|
3758
4961
|
});
|
|
@@ -3764,7 +4967,7 @@ class PonchoMap {
|
|
|
3764
4967
|
* @param {object} layer Objeto Feature GeoJSON.
|
|
3765
4968
|
* @returns {boolean}
|
|
3766
4969
|
*/
|
|
3767
|
-
isFeature =
|
|
4970
|
+
isFeature = layer => {
|
|
3768
4971
|
if(!layer.hasOwnProperty("feature")){
|
|
3769
4972
|
return false;
|
|
3770
4973
|
}
|
|
@@ -3784,6 +4987,8 @@ class PonchoMap {
|
|
|
3784
4987
|
layer.feature.geometry.type == "Point" ||
|
|
3785
4988
|
layer.feature.geometry.type == "MultiPoint"){
|
|
3786
4989
|
return;
|
|
4990
|
+
} else if(layer?.feature?.properties["pm-interactive"] == "n"){
|
|
4991
|
+
return;
|
|
3787
4992
|
}
|
|
3788
4993
|
this._setClickeable(layer);
|
|
3789
4994
|
});
|
|
@@ -4034,6 +5239,10 @@ class PonchoMap {
|
|
|
4034
5239
|
key = false, css = "small", style = false
|
|
4035
5240
|
} = this.template_structure.lead;
|
|
4036
5241
|
|
|
5242
|
+
if(!entry[key].trim()){
|
|
5243
|
+
return;
|
|
5244
|
+
}
|
|
5245
|
+
|
|
4037
5246
|
const p = document.createElement("p");
|
|
4038
5247
|
p.textContent = entry[key];
|
|
4039
5248
|
// Style definitions
|
|
@@ -4182,7 +5391,7 @@ class PonchoMap {
|
|
|
4182
5391
|
*/
|
|
4183
5392
|
fitBounds = () => {
|
|
4184
5393
|
try {
|
|
4185
|
-
this.map.fitBounds(this.geojson.getBounds());
|
|
5394
|
+
this.map.fitBounds(this.geojson.getBounds().pad(0.005));
|
|
4186
5395
|
} catch (error) {
|
|
4187
5396
|
console.error(error);
|
|
4188
5397
|
}
|
|
@@ -4198,6 +5407,9 @@ class PonchoMap {
|
|
|
4198
5407
|
return;
|
|
4199
5408
|
}
|
|
4200
5409
|
// función a evaluar. Busca y remueve un botón de reset si existiera.
|
|
5410
|
+
// if( document.querySelector(`.leaflet-control-zoom-reset`) ){
|
|
5411
|
+
// return;
|
|
5412
|
+
// }
|
|
4201
5413
|
document.querySelectorAll(
|
|
4202
5414
|
`.js-reset-view${this.scope_sufix}`).forEach(e => e.remove());
|
|
4203
5415
|
|
|
@@ -4206,7 +5418,7 @@ class PonchoMap {
|
|
|
4206
5418
|
.forEach(ele => {
|
|
4207
5419
|
|
|
4208
5420
|
const icon = document.createElement("i");
|
|
4209
|
-
icon.classList.add("
|
|
5421
|
+
icon.classList.add("pmi", "pmi-expand");
|
|
4210
5422
|
icon.setAttribute("aria-hidden","true");
|
|
4211
5423
|
|
|
4212
5424
|
const button = document.createElement("a");
|
|
@@ -4416,15 +5628,23 @@ class PonchoMap {
|
|
|
4416
5628
|
ele[key].setAttribute(
|
|
4417
5629
|
"aria-label", ele?.feature?.properties?.[this.title]
|
|
4418
5630
|
);
|
|
4419
|
-
|
|
5631
|
+
|
|
4420
5632
|
ele[key].setAttribute("tabindex", 0);
|
|
4421
5633
|
ele[key].dataset.entryId = ele?.feature?.properties?.[this.id];
|
|
5634
|
+
|
|
5635
|
+
if(ele?.feature?.properties?.["pm-interactive"] == "n"){
|
|
5636
|
+
ele[key].dataset.interactive = "n";
|
|
5637
|
+
ele[key].setAttribute("role", "graphics-symbol");
|
|
5638
|
+
} else {
|
|
5639
|
+
ele[key].setAttribute("role", "button");
|
|
5640
|
+
}
|
|
4422
5641
|
ele[key].dataset.leafletId = ele._leaflet_id;
|
|
4423
5642
|
};
|
|
4424
5643
|
|
|
4425
5644
|
this.map.eachLayer(e => setAttributes(e, "_path"));
|
|
4426
5645
|
};
|
|
4427
5646
|
|
|
5647
|
+
|
|
4428
5648
|
/**
|
|
4429
5649
|
* Anclas de salto
|
|
4430
5650
|
*
|
|
@@ -4449,11 +5669,22 @@ class PonchoMap {
|
|
|
4449
5669
|
["role", "region"],
|
|
4450
5670
|
]
|
|
4451
5671
|
],
|
|
5672
|
+
[
|
|
5673
|
+
`.js-themes-tool${this.scope_sufix}`,
|
|
5674
|
+
`themes-tool${this.scope_sufix}`,
|
|
5675
|
+
[
|
|
5676
|
+
["aria-label", "Herramienta para cambiar de tema visual"],
|
|
5677
|
+
["role", "region"],
|
|
5678
|
+
]
|
|
5679
|
+
],
|
|
4452
5680
|
];
|
|
4453
5681
|
anchors.forEach(anchor => {
|
|
4454
|
-
const element = document.
|
|
4455
|
-
element.
|
|
4456
|
-
|
|
5682
|
+
const element = document.querySelectorAll(anchor[0]);
|
|
5683
|
+
element.forEach( ele => {
|
|
5684
|
+
ele.id = anchor[1]
|
|
5685
|
+
anchor[2].forEach(e => ele.setAttribute(e[0], e[1]));
|
|
5686
|
+
} );
|
|
5687
|
+
|
|
4457
5688
|
});
|
|
4458
5689
|
return anchors;
|
|
4459
5690
|
};
|
|
@@ -4477,7 +5708,7 @@ class PonchoMap {
|
|
|
4477
5708
|
*/
|
|
4478
5709
|
_accesibleMenu = () => {
|
|
4479
5710
|
// Remuevo instancias anteriores si existieran.
|
|
4480
|
-
document.querySelectorAll(`${this.scope_selector} .accesible-nav`)
|
|
5711
|
+
document.querySelectorAll(`${this.scope_selector} .pm-accesible-nav`)
|
|
4481
5712
|
.forEach(e => e.remove());
|
|
4482
5713
|
|
|
4483
5714
|
// Anclas que se deben crear.
|
|
@@ -4497,7 +5728,11 @@ class PonchoMap {
|
|
|
4497
5728
|
{
|
|
4498
5729
|
text: "Ir al panel de zoom",
|
|
4499
5730
|
anchor: `#${anchors[1][1]}`
|
|
4500
|
-
}
|
|
5731
|
+
},
|
|
5732
|
+
{
|
|
5733
|
+
text: "Cambiar de tema",
|
|
5734
|
+
anchor: `#${anchors[2][1]}`
|
|
5735
|
+
},
|
|
4501
5736
|
]
|
|
4502
5737
|
values = [
|
|
4503
5738
|
...values,
|
|
@@ -4509,21 +5744,24 @@ class PonchoMap {
|
|
|
4509
5744
|
// Imprimo los enlaces
|
|
4510
5745
|
const icon = document.createElement("i");
|
|
4511
5746
|
icon.classList.add(
|
|
4512
|
-
"
|
|
5747
|
+
"pmi",
|
|
5748
|
+
"pmi-universal-access",
|
|
4513
5749
|
"accesible-nav__icon"
|
|
4514
5750
|
);
|
|
4515
5751
|
icon.setAttribute("aria-hidden", "true");
|
|
4516
5752
|
|
|
4517
5753
|
const nav = document.createElement("div");
|
|
4518
|
-
nav.classList.add("accesible-nav", "top");
|
|
4519
|
-
nav.id = `accesible-nav${this.scope_sufix}`;
|
|
5754
|
+
nav.classList.add("pm-accesible-nav", "top", "pm-list");
|
|
5755
|
+
nav.id = `pm-accesible-nav${this.scope_sufix}`;
|
|
4520
5756
|
nav.setAttribute("aria-label", "Menú para el mapa");
|
|
4521
5757
|
nav.setAttribute("role", "navigation");
|
|
4522
5758
|
nav.tabIndex=0;
|
|
4523
5759
|
|
|
4524
5760
|
const ul = document.createElement("ul");
|
|
5761
|
+
ul.classList.add("pm-list-unstyled");
|
|
4525
5762
|
values.forEach((link, index) => {
|
|
4526
5763
|
const a = document.createElement("a");
|
|
5764
|
+
a.classList.add("pm-item-link", "pm-accesible")
|
|
4527
5765
|
a.textContent = link.text;
|
|
4528
5766
|
a.tabIndex = 0;
|
|
4529
5767
|
a.href = link.anchor;
|
|
@@ -4542,11 +5780,12 @@ class PonchoMap {
|
|
|
4542
5780
|
// enlace de retorno
|
|
4543
5781
|
const back_to_nav = document.createElement("a");
|
|
4544
5782
|
back_to_nav.textContent = "Ir a la navegación del mapa";
|
|
4545
|
-
back_to_nav.
|
|
5783
|
+
back_to_nav.classList.add("pm-item-link", "pm-accesible");
|
|
5784
|
+
back_to_nav.href = `#pm-accesible-nav${this.scope_sufix}`;
|
|
4546
5785
|
back_to_nav.id = `accesible-return-nav${this.scope_sufix}`;
|
|
4547
5786
|
|
|
4548
5787
|
const return_nav = document.createElement("div");
|
|
4549
|
-
return_nav.classList.add("accesible-nav", "bottom");
|
|
5788
|
+
return_nav.classList.add("pm-accesible-nav", "bottom");
|
|
4550
5789
|
return_nav.appendChild(icon.cloneNode(true));
|
|
4551
5790
|
return_nav.appendChild(back_to_nav);
|
|
4552
5791
|
|
|
@@ -4600,7 +5839,8 @@ class PonchoMap {
|
|
|
4600
5839
|
render = () => {
|
|
4601
5840
|
this._hiddenSearchInput();
|
|
4602
5841
|
this._resetViewButton();
|
|
4603
|
-
|
|
5842
|
+
this._setThemes();
|
|
5843
|
+
|
|
4604
5844
|
this.titleLayer.addTo(this.map);
|
|
4605
5845
|
this.markersMap(this.entries);
|
|
4606
5846
|
this._selectedMarker();
|
|
@@ -4623,6 +5863,8 @@ class PonchoMap {
|
|
|
4623
5863
|
setTimeout(this.gotoHashedEntry, this.anchor_delay);
|
|
4624
5864
|
this._setFetureAttributes();
|
|
4625
5865
|
this._accesibleMenu();
|
|
5866
|
+
this.mapOpacity();
|
|
5867
|
+
this.mapBackgroundColor();
|
|
4626
5868
|
};
|
|
4627
5869
|
};
|
|
4628
5870
|
// end class
|
|
@@ -4924,12 +6166,13 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
4924
6166
|
|
|
4925
6167
|
const poncho_map_height = filter_container.offsetParent.offsetHeight;
|
|
4926
6168
|
// Valor tomado de la hoja de estilos
|
|
4927
|
-
const container_position_distance = this._cssVarComputedDistance() *
|
|
6169
|
+
const container_position_distance = this._cssVarComputedDistance() * 3;
|
|
4928
6170
|
const filters_height = poncho_map_height
|
|
4929
6171
|
- filter_container.offsetTop
|
|
4930
6172
|
- filter_button.offsetHeight
|
|
4931
6173
|
- container_position_distance;
|
|
4932
6174
|
|
|
6175
|
+
|
|
4933
6176
|
const pos = document
|
|
4934
6177
|
.querySelector(`.js-poncho-map-filters${this.scope_sufix}`);
|
|
4935
6178
|
pos.style.maxHeight = `${filters_height}px`;
|
|
@@ -5026,19 +6269,33 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5026
6269
|
* o, si se desean todos los checkbox desmarcados.
|
|
5027
6270
|
* ["tipo", false]
|
|
5028
6271
|
*/
|
|
5029
|
-
_fieldsToUse = (
|
|
6272
|
+
_fieldsToUse = (fieldsItems) => {
|
|
5030
6273
|
const {
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
6274
|
+
type = "checkbox",
|
|
6275
|
+
fields: optFields = false,
|
|
6276
|
+
field: optField = false} = fieldsItems;
|
|
6277
|
+
|
|
6278
|
+
if(!optFields && !optField){
|
|
5034
6279
|
this.errorMessage(
|
|
5035
6280
|
"Filters requiere el uso del atributo `field` o `fields`.",
|
|
5036
6281
|
"warning"
|
|
5037
6282
|
);
|
|
5038
6283
|
}
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
6284
|
+
// Evito que a los radio se les asigne un valor checked.
|
|
6285
|
+
if (optField && type === "radio"){
|
|
6286
|
+
optField[1] = false;
|
|
6287
|
+
}
|
|
6288
|
+
|
|
6289
|
+
let fieldsToUse = (optFields ? optFields : this._setFilter(optField));
|
|
6290
|
+
// Hasta que se defina su uso, todos los radio tienen un item `Todos`.
|
|
6291
|
+
if(type === "radio" && optFields === false){
|
|
6292
|
+
const f = fieldsToUse.map(m => m[1]);
|
|
6293
|
+
fieldsToUse = [
|
|
6294
|
+
[fieldsToUse[0][0], "Todos", f, "checked"], ...fieldsToUse
|
|
6295
|
+
];
|
|
6296
|
+
}
|
|
6297
|
+
|
|
6298
|
+
return fieldsToUse;
|
|
5042
6299
|
};
|
|
5043
6300
|
|
|
5044
6301
|
|
|
@@ -5057,8 +6314,9 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5057
6314
|
const field = fields_to_use[key];
|
|
5058
6315
|
const input = document.createElement("input");
|
|
5059
6316
|
input.type = (this.valid_fields.includes(fields_items.type) ?
|
|
5060
|
-
|
|
6317
|
+
fields_items.type : "checkbox");
|
|
5061
6318
|
input.id = `id__${field[0]}__${group}__${key}`;
|
|
6319
|
+
|
|
5062
6320
|
if(fields_items.type == "radio"){
|
|
5063
6321
|
input.name = `${field[0]}__${group}`;
|
|
5064
6322
|
} else {
|
|
@@ -5099,15 +6357,15 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5099
6357
|
_filterButton = () => {
|
|
5100
6358
|
const filter_icon = document.createElement("i");
|
|
5101
6359
|
filter_icon.setAttribute("aria-hidden", "true");
|
|
5102
|
-
filter_icon.classList.add("
|
|
6360
|
+
filter_icon.classList.add("pmi", "pmi-filter");
|
|
5103
6361
|
|
|
5104
6362
|
const button_text = document.createElement("span");
|
|
5105
6363
|
button_text.textContent = "Abre o cierra el filtro de búsqueda";
|
|
5106
|
-
button_text.classList.add("
|
|
6364
|
+
button_text.classList.add("pm-visually-hidden");
|
|
5107
6365
|
|
|
5108
6366
|
const button = document.createElement("button");
|
|
5109
6367
|
button.classList.add(
|
|
5110
|
-
"btn","btn-
|
|
6368
|
+
"pm-btn", "pm-btn-rounded-circle", "pm-my-1",
|
|
5111
6369
|
`js-close-filter${this.scope_sufix}`
|
|
5112
6370
|
);
|
|
5113
6371
|
button.id = `filtrar-busqueda${this.scope_sufix}`
|
|
@@ -5134,7 +6392,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5134
6392
|
|
|
5135
6393
|
|
|
5136
6394
|
/**
|
|
5137
|
-
* Medida definida en la variable CSS --slider-distance
|
|
6395
|
+
* Medida definida en la variable CSS --pm-slider-distance
|
|
5138
6396
|
*
|
|
5139
6397
|
* @summary Esta medida puede ser variable según el estilo que se
|
|
5140
6398
|
* quiera dar al mapa el diseñador.
|
|
@@ -5143,7 +6401,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5143
6401
|
_cssVarComputedDistance = () => {
|
|
5144
6402
|
const container = document.querySelector(".poncho-map");
|
|
5145
6403
|
const computedDistance = getComputedStyle(container)
|
|
5146
|
-
.getPropertyValue('--slider-distance');
|
|
6404
|
+
.getPropertyValue('--pm-slider-distance');
|
|
5147
6405
|
const distance = parseInt(
|
|
5148
6406
|
computedDistance.toString().replace(/[^0-9]*/gm, ""));
|
|
5149
6407
|
return distance || 0;
|
|
@@ -5181,7 +6439,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5181
6439
|
close_button.title = "Cerrar panel";
|
|
5182
6440
|
close_button.setAttribute("role", "button");
|
|
5183
6441
|
close_button.setAttribute("aria-label", "Cerrar panel de filtros");
|
|
5184
|
-
close_button.innerHTML = "<span class=\"
|
|
6442
|
+
close_button.innerHTML = "<span class=\"pm-visually-hidden\">Cerrar </span>✕";
|
|
5185
6443
|
|
|
5186
6444
|
|
|
5187
6445
|
const form = document.createElement("form");
|
|
@@ -5191,7 +6449,10 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5191
6449
|
|
|
5192
6450
|
const container = document.createElement("div");
|
|
5193
6451
|
container.classList.add(
|
|
5194
|
-
`js-poncho-map-filters${this.scope_sufix}`,
|
|
6452
|
+
`js-poncho-map-filters${this.scope_sufix}`,
|
|
6453
|
+
"pm-container",
|
|
6454
|
+
"poncho-map-filters",
|
|
6455
|
+
"pm-caret", "pm-caret-t",
|
|
5195
6456
|
);
|
|
5196
6457
|
container.setAttribute("role", "region");
|
|
5197
6458
|
container.setAttribute("aria-live", "polite");
|
|
@@ -5206,7 +6467,6 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5206
6467
|
const controlZoomSize = this._controlZoomSize();
|
|
5207
6468
|
const styleTop = controlZoomSize.controlHeight
|
|
5208
6469
|
+ controlZoomSize.controlTop
|
|
5209
|
-
+ cssVarComputedDistance
|
|
5210
6470
|
+ "px";
|
|
5211
6471
|
|
|
5212
6472
|
container.appendChild(form);
|
|
@@ -5252,18 +6512,18 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5252
6512
|
* Crea los checkbox para los filtros.
|
|
5253
6513
|
*/
|
|
5254
6514
|
_createFilters = (data) => {
|
|
5255
|
-
// debugger
|
|
5256
6515
|
const form_filters = document
|
|
5257
6516
|
.querySelector(`.js-filters${this.scope_sufix}`);
|
|
5258
6517
|
|
|
5259
6518
|
data.forEach((item, group) => {
|
|
5260
6519
|
let legend = document.createElement("legend");
|
|
5261
6520
|
legend.textContent = item.legend;
|
|
5262
|
-
legend.classList.add("m-b-1", "
|
|
6521
|
+
legend.classList.add("m-b-1", "color-primary", "h6")
|
|
5263
6522
|
|
|
5264
6523
|
let fieldset = document.createElement("fieldset");
|
|
5265
6524
|
fieldset.appendChild(legend);
|
|
5266
|
-
if(item.hasOwnProperty("check_uncheck_all") &&
|
|
6525
|
+
if(item.hasOwnProperty("check_uncheck_all") &&
|
|
6526
|
+
item.check_uncheck_all && item?.type != "radio"){
|
|
5267
6527
|
fieldset.appendChild(this._checkUncheckButtons(item));
|
|
5268
6528
|
}
|
|
5269
6529
|
fieldset.appendChild(this._fields(item, group));
|
|
@@ -5414,7 +6674,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5414
6674
|
i.setAttribute("aria-hidden", "true");
|
|
5415
6675
|
|
|
5416
6676
|
const span = document.createElement("span");
|
|
5417
|
-
span.className = "
|
|
6677
|
+
span.className = "pm-visually-hidden";
|
|
5418
6678
|
span.style.fontWeight = "400";
|
|
5419
6679
|
span.textContent = `${field[1]} elemento${plurals}.`;
|
|
5420
6680
|
|
|
@@ -5508,6 +6768,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5508
6768
|
this._helpText(feed);
|
|
5509
6769
|
this._resetSearch();
|
|
5510
6770
|
this._clickToggleFilter();
|
|
6771
|
+
|
|
5511
6772
|
if(this.slider){
|
|
5512
6773
|
this._renderSlider();
|
|
5513
6774
|
this._clickeableMarkers();
|
|
@@ -5518,6 +6779,7 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5518
6779
|
if(this.hash){
|
|
5519
6780
|
this._urlHash();
|
|
5520
6781
|
}
|
|
6782
|
+
|
|
5521
6783
|
this._setFetureAttributes();
|
|
5522
6784
|
this._accesibleMenu();
|
|
5523
6785
|
};
|
|
@@ -5596,6 +6858,9 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5596
6858
|
this._hiddenSearchInput();
|
|
5597
6859
|
this._resetViewButton();
|
|
5598
6860
|
|
|
6861
|
+
this._menuTheme();
|
|
6862
|
+
this._setThemes();
|
|
6863
|
+
|
|
5599
6864
|
if(this.filters.length > 0){
|
|
5600
6865
|
this._filterButton();
|
|
5601
6866
|
this._filterContainer();
|
|
@@ -5619,6 +6884,8 @@ class PonchoMapFilter extends PonchoMap {
|
|
|
5619
6884
|
if(this.filters_visible){
|
|
5620
6885
|
this._filterContainerHeight();
|
|
5621
6886
|
}
|
|
6887
|
+
this.mapOpacity();
|
|
6888
|
+
this.mapBackgroundColor();
|
|
5622
6889
|
};
|
|
5623
6890
|
};
|
|
5624
6891
|
// end of class
|
|
@@ -5890,6 +7157,342 @@ class PonchoMapSearch {
|
|
|
5890
7157
|
}
|
|
5891
7158
|
};
|
|
5892
7159
|
|
|
7160
|
+
/**
|
|
7161
|
+
* PONCHO MAP FILTRO POR PROVINCIAS
|
|
7162
|
+
*
|
|
7163
|
+
* @summary Assets para configrar poncho map con un geoJSON de provincias.
|
|
7164
|
+
*
|
|
7165
|
+
* @author Agustín Bouillet <bouilleta@jefatura.gob.ar>
|
|
7166
|
+
*
|
|
7167
|
+
*
|
|
7168
|
+
*
|
|
7169
|
+
* MIT License
|
|
7170
|
+
*
|
|
7171
|
+
* Copyright (c) 2023 Argentina.gob.ar
|
|
7172
|
+
*
|
|
7173
|
+
* Permission is hereby granted, free of charge, to any person
|
|
7174
|
+
* obtaining a copy of this software and associated documentation
|
|
7175
|
+
* files (the "Software"), to deal in the Software without restriction,
|
|
7176
|
+
* including without limitation the rightsto use, copy, modify, merge,
|
|
7177
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
7178
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
7179
|
+
* subject to the following conditions:
|
|
7180
|
+
*
|
|
7181
|
+
* The above copyright notice and this permission notice shall be
|
|
7182
|
+
* included in all copies or substantial portions of the Software.
|
|
7183
|
+
*
|
|
7184
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
7185
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
7186
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
7187
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
7188
|
+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
7189
|
+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
7190
|
+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
7191
|
+
* SOFTWARE.
|
|
7192
|
+
*/
|
|
7193
|
+
const PONCHOMAP_GEOJSON_PROVINCES = "/profiles/argentinagobar/"
|
|
7194
|
+
+ "themes/contrib/poncho/resources/jsons/"
|
|
7195
|
+
+ "geo-provincias-argentinas.json";
|
|
7196
|
+
|
|
7197
|
+
|
|
7198
|
+
/**
|
|
7199
|
+
* Junta el geoJSON con el JSON de Google Sheet
|
|
7200
|
+
*
|
|
7201
|
+
* @summary Este objeto no puede estar dentro de la clase porque no se puede
|
|
7202
|
+
* utiliar `this` antes de `super()` en ES6.
|
|
7203
|
+
*
|
|
7204
|
+
* @param {object} geoProvinces GeoJSON
|
|
7205
|
+
* @param {object} entries JSON con entradas por provincia.
|
|
7206
|
+
* @returns {object}
|
|
7207
|
+
*/
|
|
7208
|
+
const ponchoMapProvinceMergeData = (geoProvinces={}, entries={},
|
|
7209
|
+
provinceIndex="provincia") => {
|
|
7210
|
+
|
|
7211
|
+
if(!geoProvinces.hasOwnProperty("features")){
|
|
7212
|
+
throw new Error("Invalid data format");
|
|
7213
|
+
}
|
|
7214
|
+
|
|
7215
|
+
geoProvinces.features.forEach((feature, key) => {
|
|
7216
|
+
const jsonEntry = entries.find(entry =>
|
|
7217
|
+
(entry[provinceIndex] == feature.properties.fna ||
|
|
7218
|
+
entry[provinceIndex] == feature.properties.nam)
|
|
7219
|
+
);
|
|
7220
|
+
// Si no existe la provincia en el JSON, borra el feature.
|
|
7221
|
+
if(!jsonEntry && feature.properties.fna){
|
|
7222
|
+
delete geoProvinces.features[key];
|
|
7223
|
+
return;
|
|
7224
|
+
}
|
|
7225
|
+
// Si hay definido un key _color_, usa el color en el fill.
|
|
7226
|
+
if(jsonEntry?.color && !feature.properties["pm-type"]){
|
|
7227
|
+
geoProvinces
|
|
7228
|
+
.features[key]
|
|
7229
|
+
.properties.stroke = ponchoColor(jsonEntry.color);
|
|
7230
|
+
}
|
|
7231
|
+
// Remuevo la propiedad interactive del json para que no se interponga
|
|
7232
|
+
// con el valor del geoJSON.
|
|
7233
|
+
if(feature.properties["pm-interactive"] === "n" &&
|
|
7234
|
+
jsonEntry?.["pm-interactive"] !== "n"){
|
|
7235
|
+
delete jsonEntry["pm-interactive"];
|
|
7236
|
+
}
|
|
7237
|
+
|
|
7238
|
+
Object.assign(geoProvinces.features[key].properties, jsonEntry);
|
|
7239
|
+
});
|
|
7240
|
+
return geoProvinces;
|
|
7241
|
+
};
|
|
7242
|
+
|
|
7243
|
+
|
|
7244
|
+
/**
|
|
7245
|
+
* Remueve estilos toggle del select y el contenedor del mapa
|
|
7246
|
+
*
|
|
7247
|
+
* @summary Este objeto no puede estar dentro de la clase porque no se puede
|
|
7248
|
+
* utiliar `this` antes de `super()` en ES6.
|
|
7249
|
+
* @returns {undefined}
|
|
7250
|
+
*/
|
|
7251
|
+
const ponchoMapProvinceCssStyles = flag => {
|
|
7252
|
+
if(flag){
|
|
7253
|
+
return;
|
|
7254
|
+
}
|
|
7255
|
+
const s = document.querySelectorAll(
|
|
7256
|
+
".poncho-map-province__toggle-map,"
|
|
7257
|
+
+ ".poncho-map-province__toggle-element"
|
|
7258
|
+
);
|
|
7259
|
+
s.forEach(element => {
|
|
7260
|
+
element.classList.remove(
|
|
7261
|
+
"poncho-map-province__toggle-map",
|
|
7262
|
+
"poncho-map-province__toggle-element"
|
|
7263
|
+
);
|
|
7264
|
+
});
|
|
7265
|
+
};
|
|
7266
|
+
|
|
7267
|
+
|
|
7268
|
+
class PonchoMapProvinces extends PonchoMapFilter {
|
|
7269
|
+
constructor(geoProvinces, entries, options){
|
|
7270
|
+
|
|
7271
|
+
const defaultOptions = {
|
|
7272
|
+
initial_entry: false,
|
|
7273
|
+
random_entry: false,
|
|
7274
|
+
overlay_image: true,
|
|
7275
|
+
overlay_image_bounds: [
|
|
7276
|
+
[-20.56830872133435, -44.91768177759874],
|
|
7277
|
+
[-55.861359445914566, -75.2246121480093]
|
|
7278
|
+
],
|
|
7279
|
+
overlay_image_opacity: 0.8,
|
|
7280
|
+
overlay_image_url: "https://www.argentina.gob.ar/"
|
|
7281
|
+
+ "sites/default/files/map-shadow.png",
|
|
7282
|
+
hide_select: true,
|
|
7283
|
+
province_index: "provincia",
|
|
7284
|
+
fit_bounds: true,
|
|
7285
|
+
// Sobreescribo opciones de PonchoMap
|
|
7286
|
+
map_view:[-40.47815508388363,-60.0045383246273],
|
|
7287
|
+
map_init_options: {
|
|
7288
|
+
zoomSnap: 0.2,
|
|
7289
|
+
zoomControl: true,
|
|
7290
|
+
doubleClickZoom: false,
|
|
7291
|
+
scrollWheelZoom: false,
|
|
7292
|
+
boxZoom: false
|
|
7293
|
+
},
|
|
7294
|
+
map_zoom: 4.4,
|
|
7295
|
+
tooltip_options: {
|
|
7296
|
+
permanent: false,
|
|
7297
|
+
className: "leaflet-tooltip-own",
|
|
7298
|
+
direction: "auto",
|
|
7299
|
+
offset: [0, -3],
|
|
7300
|
+
sticky: true,
|
|
7301
|
+
opacity: 1,
|
|
7302
|
+
},
|
|
7303
|
+
tooltip: true,
|
|
7304
|
+
slider: true
|
|
7305
|
+
};
|
|
7306
|
+
// Merge options
|
|
7307
|
+
let opts = Object.assign({}, defaultOptions, options);
|
|
7308
|
+
|
|
7309
|
+
ponchoMapProvinceCssStyles(opts.hide_select);
|
|
7310
|
+
|
|
7311
|
+
// PonchoMapFilter instance
|
|
7312
|
+
const mergedJSONs = ponchoMapProvinceMergeData(
|
|
7313
|
+
geoProvinces, entries, opts.province_index
|
|
7314
|
+
);
|
|
7315
|
+
|
|
7316
|
+
super(mergedJSONs, opts);
|
|
7317
|
+
|
|
7318
|
+
this.initialEntry = opts.initial_entry;
|
|
7319
|
+
this.randomEntry = opts.random_entry;
|
|
7320
|
+
this.overlayImage = opts.overlay_image;
|
|
7321
|
+
this.overlayImageUrl = opts.overlay_image_url;
|
|
7322
|
+
this.overlayImageBounds = opts.overlay_image_bounds;
|
|
7323
|
+
this.overlayImageOpacity = opts.overlay_image_opacity;
|
|
7324
|
+
this.mapView = opts.map_view;
|
|
7325
|
+
this.hideSelect = opts.hide_select;
|
|
7326
|
+
this.fitToBounds = opts.fit_bounds
|
|
7327
|
+
}
|
|
7328
|
+
|
|
7329
|
+
|
|
7330
|
+
/**
|
|
7331
|
+
* Ordena un array por uno de sus keys.
|
|
7332
|
+
* @param {object} obj Objeto a ordenar.
|
|
7333
|
+
* @param {integer} key Posición del array.
|
|
7334
|
+
* @param {object} obj Objeto ordenado.
|
|
7335
|
+
*/
|
|
7336
|
+
sortObject = (obj, key=0) => obj.sort((a, b) => {
|
|
7337
|
+
const valA = a[key].toUpperCase();
|
|
7338
|
+
const valB = b[key].toUpperCase();
|
|
7339
|
+
if (valA > valB) {
|
|
7340
|
+
return 1;
|
|
7341
|
+
}
|
|
7342
|
+
if (valA < valB) {
|
|
7343
|
+
return -1;
|
|
7344
|
+
}
|
|
7345
|
+
return 0;
|
|
7346
|
+
});
|
|
7347
|
+
|
|
7348
|
+
|
|
7349
|
+
/**
|
|
7350
|
+
* Retorna un valor aleatório.
|
|
7351
|
+
* @param {object} list Listado de provincias
|
|
7352
|
+
* @returns {object}
|
|
7353
|
+
*/
|
|
7354
|
+
_randomEntry = list => {
|
|
7355
|
+
return list[Math.floor(Math.random()*list.length)][0];
|
|
7356
|
+
};
|
|
7357
|
+
|
|
7358
|
+
|
|
7359
|
+
/**
|
|
7360
|
+
* Retorna un array con clave y valor de provincias argentinas
|
|
7361
|
+
* @param {object} geoJSON Objeto geoJSON con los features por provincia
|
|
7362
|
+
* @param {string} idKey Key del propertie que se usa como id.
|
|
7363
|
+
* @returns {object}
|
|
7364
|
+
*/
|
|
7365
|
+
_provincesFromGeoJSON = (geoJSON, idKey) => {
|
|
7366
|
+
let prov = {};
|
|
7367
|
+
geoJSON.features.map(p => {
|
|
7368
|
+
const {
|
|
7369
|
+
name=false,
|
|
7370
|
+
"pm-interactive":pmInteractive=false} = p.properties;
|
|
7371
|
+
|
|
7372
|
+
if(pmInteractive === "n" || !name){
|
|
7373
|
+
return false;
|
|
7374
|
+
}
|
|
7375
|
+
prov[p.properties[idKey]] = name;
|
|
7376
|
+
}).filter(f => f);
|
|
7377
|
+
|
|
7378
|
+
let provincesToList = this.sortObject( Object.entries(prov), 1);
|
|
7379
|
+
return provincesToList;
|
|
7380
|
+
};
|
|
7381
|
+
|
|
7382
|
+
|
|
7383
|
+
/**
|
|
7384
|
+
* Imprime la región según las opciones de precedencia.
|
|
7385
|
+
* @param {string} prov Id de provincia
|
|
7386
|
+
* @returns {undefined}
|
|
7387
|
+
*/
|
|
7388
|
+
_selectedEntry = prov => {
|
|
7389
|
+
const hash = window.location.hash.replace("#", "");
|
|
7390
|
+
let selected = "";
|
|
7391
|
+
if(hash){
|
|
7392
|
+
selected = hash;
|
|
7393
|
+
} else if(this.initialEntry){
|
|
7394
|
+
selected = this.initialEntry;
|
|
7395
|
+
} else if(this.randomEntry){
|
|
7396
|
+
selected = this._randomEntry(prov);
|
|
7397
|
+
}
|
|
7398
|
+
return selected;
|
|
7399
|
+
}
|
|
7400
|
+
|
|
7401
|
+
|
|
7402
|
+
/**
|
|
7403
|
+
* Crea los options para el select de provincias
|
|
7404
|
+
* @param {object} map
|
|
7405
|
+
* @returns {object}
|
|
7406
|
+
*/
|
|
7407
|
+
_setSelectProvinces = map => {
|
|
7408
|
+
const hash = window.location.hash.replace("#", "");
|
|
7409
|
+
const prov = this._provincesFromGeoJSON(map.geoJSON, map.id);
|
|
7410
|
+
const selected = this._selectedEntry(prov);
|
|
7411
|
+
|
|
7412
|
+
// Creo los options
|
|
7413
|
+
const selectProvinces = document.getElementById("id_provincia");
|
|
7414
|
+
const optionsSelect = [["", "Seleccione una provincia"], ...prov];
|
|
7415
|
+
optionsSelect.forEach(province => {
|
|
7416
|
+
const option = document.createElement("option");
|
|
7417
|
+
|
|
7418
|
+
if(province[0] === selected){
|
|
7419
|
+
option.setAttribute("selected", "selected");
|
|
7420
|
+
}
|
|
7421
|
+
option.value = province[0];
|
|
7422
|
+
option.textContent = province[1];
|
|
7423
|
+
selectProvinces.appendChild(option);
|
|
7424
|
+
});
|
|
7425
|
+
return {object: selectProvinces, selected: selected};
|
|
7426
|
+
};
|
|
7427
|
+
|
|
7428
|
+
|
|
7429
|
+
/**
|
|
7430
|
+
* Selected option cuando selecciono un polígono
|
|
7431
|
+
* @param {object} map Objeto return ponchoMap
|
|
7432
|
+
*/
|
|
7433
|
+
_selectedPolygon = map => {
|
|
7434
|
+
map.map.eachLayer(layer => {
|
|
7435
|
+
layer.on("keypress click", (e) => {
|
|
7436
|
+
if( e?.target?.feature?.properties ){
|
|
7437
|
+
const {id} = e.target.feature.properties;
|
|
7438
|
+
document.getElementById("id_provincia").value = id;
|
|
7439
|
+
}
|
|
7440
|
+
});
|
|
7441
|
+
})
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
|
|
7445
|
+
/**
|
|
7446
|
+
* Crea el listener para la interacción del select con el mapa.
|
|
7447
|
+
* @param {object} map
|
|
7448
|
+
*/
|
|
7449
|
+
_selectProvinces = map => {
|
|
7450
|
+
this._selectedPolygon(map);
|
|
7451
|
+
|
|
7452
|
+
// Arma el select con las provincias
|
|
7453
|
+
const selectProvinces = this._setSelectProvinces(map);
|
|
7454
|
+
|
|
7455
|
+
if(selectProvinces.selected){
|
|
7456
|
+
map.gotoEntry(selectProvinces.selected)
|
|
7457
|
+
}
|
|
7458
|
+
|
|
7459
|
+
// cambia los datos de la provincia
|
|
7460
|
+
selectProvinces.object.addEventListener("change", e => {
|
|
7461
|
+
map.gotoEntry(e.target.value);
|
|
7462
|
+
e.value = selectProvinces.selected
|
|
7463
|
+
});
|
|
7464
|
+
};
|
|
7465
|
+
|
|
7466
|
+
|
|
7467
|
+
/**
|
|
7468
|
+
* Implementa una imagen sobre el mapa
|
|
7469
|
+
* @returns {undefined}
|
|
7470
|
+
*/
|
|
7471
|
+
_overlayImage = () => {
|
|
7472
|
+
if(!this.overlayImage){
|
|
7473
|
+
return;
|
|
7474
|
+
}
|
|
7475
|
+
L.imageOverlay(
|
|
7476
|
+
this.overlayImageUrl, this.overlayImageBounds,
|
|
7477
|
+
{opacity: this.overlayImageOpacity}
|
|
7478
|
+
).addTo(this.map);
|
|
7479
|
+
}
|
|
7480
|
+
|
|
7481
|
+
|
|
7482
|
+
/**
|
|
7483
|
+
* imprime el mapa
|
|
7484
|
+
*/
|
|
7485
|
+
renderProvinceMap = () =>{
|
|
7486
|
+
this._overlayImage();
|
|
7487
|
+
this.render(); // Imprime PonchoMapsFilter
|
|
7488
|
+
if(this.fitToBounds){
|
|
7489
|
+
this.fitBounds();
|
|
7490
|
+
}
|
|
7491
|
+
this._selectProvinces(this);
|
|
7492
|
+
};
|
|
7493
|
+
}
|
|
7494
|
+
// end class
|
|
7495
|
+
|
|
5893
7496
|
/**
|
|
5894
7497
|
* Helpers para manejar los json provenientes de Google Sheets.
|
|
5895
7498
|
*
|
|
@@ -5998,7 +7601,9 @@ class GapiSheetData {
|
|
|
5998
7601
|
|
|
5999
7602
|
|
|
6000
7603
|
|
|
6001
|
-
|
|
7604
|
+
if (typeof exports !== "undefined") {
|
|
7605
|
+
module.exports = GapiSheetData;
|
|
7606
|
+
}
|
|
6002
7607
|
|
|
6003
7608
|
/**
|
|
6004
7609
|
* TRANSLATE
|
|
@@ -6034,10 +7639,9 @@ class GapiSheetData {
|
|
|
6034
7639
|
*/
|
|
6035
7640
|
class TranslateHTML {
|
|
6036
7641
|
ATTRIBUTES = [
|
|
6037
|
-
"title", "placeholder", "alt", "value", "href", "src", "lang"
|
|
7642
|
+
"title", "placeholder", "alt", "value", "href", "src", "html.lang"
|
|
6038
7643
|
];
|
|
6039
7644
|
|
|
6040
|
-
|
|
6041
7645
|
/**
|
|
6042
7646
|
* @param {object} dictionary Objeto con diccionario de terminos
|
|
6043
7647
|
* a traducir.
|
|
@@ -6045,11 +7649,33 @@ class TranslateHTML {
|
|
|
6045
7649
|
* a traducir.
|
|
6046
7650
|
*/
|
|
6047
7651
|
constructor(dictionary = [], attributes = []) {
|
|
6048
|
-
this.dictionary = dictionary;
|
|
7652
|
+
this.dictionary = this.sortByLength(dictionary);
|
|
6049
7653
|
this.attributes = (attributes.length ? attributes : this.ATTRIBUTES);
|
|
6050
7654
|
}
|
|
6051
7655
|
|
|
6052
7656
|
|
|
7657
|
+
/**
|
|
7658
|
+
* Ordena los términos
|
|
7659
|
+
*
|
|
7660
|
+
* @summary Ordena el diccionario de mayor a menor según el total de
|
|
7661
|
+
* caracteres de cada término.
|
|
7662
|
+
* @param {object} obj Listado a ordenar
|
|
7663
|
+
* @returns {object} Listado ordenado
|
|
7664
|
+
*/
|
|
7665
|
+
sortByLength = obj => {
|
|
7666
|
+
obj.sort((a, b) => {
|
|
7667
|
+
if (a[0].length > b[0].length) {
|
|
7668
|
+
return -1;
|
|
7669
|
+
} else if (a[0].length < b[0].length) {
|
|
7670
|
+
return 1;
|
|
7671
|
+
} else {
|
|
7672
|
+
return a[0] - b[0];
|
|
7673
|
+
}
|
|
7674
|
+
});
|
|
7675
|
+
return obj;
|
|
7676
|
+
};
|
|
7677
|
+
|
|
7678
|
+
|
|
6053
7679
|
/**
|
|
6054
7680
|
* Traduce atributos html
|
|
6055
7681
|
*
|
|
@@ -6064,13 +7690,21 @@ class TranslateHTML {
|
|
|
6064
7690
|
*/
|
|
6065
7691
|
translateAttributes = (dictionary=false) => {
|
|
6066
7692
|
const dict = (dictionary ? dictionary : this.dictionary);
|
|
6067
|
-
this.attributes.forEach((item) =>
|
|
6068
|
-
|
|
7693
|
+
this.attributes.forEach((item) => {
|
|
7694
|
+
|
|
7695
|
+
const attrDef = item.split(".").slice(-2);
|
|
7696
|
+
const tag = (attrDef.length === 2 ? attrDef[0] : "");
|
|
7697
|
+
const attr = (attrDef.length === 2 ? attrDef[1] : attrDef[0]);
|
|
7698
|
+
|
|
7699
|
+
dict.forEach(translate => {
|
|
7700
|
+
|
|
7701
|
+
console.log(`${tag}[${attr}='${translate[0]}']`, translate[1])
|
|
7702
|
+
|
|
6069
7703
|
document
|
|
6070
|
-
.querySelectorAll(
|
|
6071
|
-
.forEach(
|
|
6072
|
-
)
|
|
6073
|
-
);
|
|
7704
|
+
.querySelectorAll(`${tag}[${attr}='${translate[0]}']`)
|
|
7705
|
+
.forEach(t => (t[attr] = translate[1]));
|
|
7706
|
+
});
|
|
7707
|
+
});
|
|
6074
7708
|
};
|
|
6075
7709
|
|
|
6076
7710
|
|