[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 (function () { 2 'use strict'; 3 4 function _defineProperties(target, props) { 5 for (var i = 0; i < props.length; i++) { 6 var descriptor = props[i]; 7 descriptor.enumerable = descriptor.enumerable || false; 8 descriptor.configurable = true; 9 if ("value" in descriptor) descriptor.writable = true; 10 Object.defineProperty(target, descriptor.key, descriptor); 11 } 12 } 13 14 function _createClass(Constructor, protoProps, staticProps) { 15 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 16 if (staticProps) _defineProperties(Constructor, staticProps); 17 Object.defineProperty(Constructor, "prototype", { 18 writable: false 19 }); 20 return Constructor; 21 } 22 23 function _inheritsLoose(subClass, superClass) { 24 subClass.prototype = Object.create(superClass.prototype); 25 subClass.prototype.constructor = subClass; 26 27 _setPrototypeOf(subClass, superClass); 28 } 29 30 function _getPrototypeOf(o) { 31 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 32 return o.__proto__ || Object.getPrototypeOf(o); 33 }; 34 return _getPrototypeOf(o); 35 } 36 37 function _setPrototypeOf(o, p) { 38 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 39 o.__proto__ = p; 40 return o; 41 }; 42 43 return _setPrototypeOf(o, p); 44 } 45 46 function _isNativeReflectConstruct() { 47 if (typeof Reflect === "undefined" || !Reflect.construct) return false; 48 if (Reflect.construct.sham) return false; 49 if (typeof Proxy === "function") return true; 50 51 try { 52 Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); 53 return true; 54 } catch (e) { 55 return false; 56 } 57 } 58 59 function _construct(Parent, args, Class) { 60 if (_isNativeReflectConstruct()) { 61 _construct = Reflect.construct; 62 } else { 63 _construct = function _construct(Parent, args, Class) { 64 var a = [null]; 65 a.push.apply(a, args); 66 var Constructor = Function.bind.apply(Parent, a); 67 var instance = new Constructor(); 68 if (Class) _setPrototypeOf(instance, Class.prototype); 69 return instance; 70 }; 71 } 72 73 return _construct.apply(null, arguments); 74 } 75 76 function _isNativeFunction(fn) { 77 return Function.toString.call(fn).indexOf("[native code]") !== -1; 78 } 79 80 function _wrapNativeSuper(Class) { 81 var _cache = typeof Map === "function" ? new Map() : undefined; 82 83 _wrapNativeSuper = function _wrapNativeSuper(Class) { 84 if (Class === null || !_isNativeFunction(Class)) return Class; 85 86 if (typeof Class !== "function") { 87 throw new TypeError("Super expression must either be null or a function"); 88 } 89 90 if (typeof _cache !== "undefined") { 91 if (_cache.has(Class)) return _cache.get(Class); 92 93 _cache.set(Class, Wrapper); 94 } 95 96 function Wrapper() { 97 return _construct(Class, arguments, _getPrototypeOf(this).constructor); 98 } 99 100 Wrapper.prototype = Object.create(Class.prototype, { 101 constructor: { 102 value: Wrapper, 103 enumerable: false, 104 writable: true, 105 configurable: true 106 } 107 }); 108 return _setPrototypeOf(Wrapper, Class); 109 }; 110 111 return _wrapNativeSuper(Class); 112 } 113 114 function _assertThisInitialized(self) { 115 if (self === void 0) { 116 throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 117 } 118 119 return self; 120 } 121 122 /** 123 * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> 124 * @license GNU General Public License version 2 or later; see LICENSE.txt 125 */ 126 (function (customElements) { 127 var KEYCODE = { 128 SPACE: 32, 129 ESC: 27, 130 ENTER: 13 131 }; 132 /** 133 * Helper for testing whether a selection modifier is pressed 134 * @param {Event} event 135 * 136 * @returns {boolean|*} 137 */ 138 139 function hasModifier(event) { 140 return event.ctrlKey || event.metaKey || event.shiftKey; 141 } 142 143 var JoomlaFieldSubform = /*#__PURE__*/function (_HTMLElement) { 144 _inheritsLoose(JoomlaFieldSubform, _HTMLElement); 145 146 function JoomlaFieldSubform() { 147 var _this; 148 149 _this = _HTMLElement.call(this) || this; 150 151 var that = _assertThisInitialized(_this); // Get the rows container 152 153 154 _this.containerWithRows = _assertThisInitialized(_this); 155 156 if (_this.rowsContainer) { 157 var allContainers = _this.querySelectorAll(_this.rowsContainer); // Find closest, and exclude nested 158 159 160 Array.from(allContainers).forEach(function (container) { 161 if (container.closest('joomla-field-subform') === _assertThisInitialized(_this)) { 162 _this.containerWithRows = container; 163 } 164 }); 165 } // Keep track of row index, this is important to avoid a name duplication 166 // Note: php side should reset the indexes each time, eg: $value = array_values($value); 167 168 169 _this.lastRowIndex = _this.getRows().length - 1; // Template for the repeating group 170 171 _this.template = ''; // Prepare a row template, and find available field names 172 173 _this.prepareTemplate(); // Bind buttons 174 175 176 if (_this.buttonAdd || _this.buttonRemove) { 177 _this.addEventListener('click', function (event) { 178 var btnAdd = null; 179 var btnRem = null; 180 181 if (that.buttonAdd) { 182 btnAdd = event.target.matches(that.buttonAdd) ? event.target : event.target.closest(that.buttonAdd); 183 } 184 185 if (that.buttonRemove) { 186 btnRem = event.target.matches(that.buttonRemove) ? event.target : event.target.closest(that.buttonRemove); 187 } // Check active, with extra check for nested joomla-field-subform 188 189 190 if (btnAdd && btnAdd.closest('joomla-field-subform') === that) { 191 var row = btnAdd.closest(that.repeatableElement); 192 row = row && row.closest('joomla-field-subform') === that ? row : null; 193 that.addRow(row); 194 event.preventDefault(); 195 } else if (btnRem && btnRem.closest('joomla-field-subform') === that) { 196 var _row = btnRem.closest(that.repeatableElement); 197 198 that.removeRow(_row); 199 event.preventDefault(); 200 } 201 }); 202 203 _this.addEventListener('keydown', function (event) { 204 if (event.keyCode !== KEYCODE.SPACE) return; 205 var isAdd = that.buttonAdd && event.target.matches(that.buttonAdd); 206 var isRem = that.buttonRemove && event.target.matches(that.buttonRemove); 207 208 if ((isAdd || isRem) && event.target.closest('joomla-field-subform') === that) { 209 var row = event.target.closest(that.repeatableElement); 210 row = row && row.closest('joomla-field-subform') === that ? row : null; 211 212 if (isRem && row) { 213 that.removeRow(row); 214 } else if (isAdd) { 215 that.addRow(row); 216 } 217 218 event.preventDefault(); 219 } 220 }); 221 } // Sorting 222 223 224 if (_this.buttonMove) { 225 _this.setUpDragSort(); 226 } 227 228 return _this; 229 } 230 /** 231 * Search for existing rows 232 * @returns {HTMLElement[]} 233 */ 234 235 236 var _proto = JoomlaFieldSubform.prototype; 237 238 _proto.getRows = function getRows() { 239 var _this2 = this; 240 241 var rows = Array.from(this.containerWithRows.children); 242 var result = []; // Filter out the rows 243 244 rows.forEach(function (row) { 245 if (row.matches(_this2.repeatableElement)) { 246 result.push(row); 247 } 248 }); 249 return result; 250 } 251 /** 252 * Prepare a row template 253 */ 254 ; 255 256 _proto.prepareTemplate = function prepareTemplate() { 257 var tmplElement = [].slice.call(this.children).filter(function (el) { 258 return el.classList.contains('subform-repeatable-template-section'); 259 }); 260 261 if (tmplElement[0]) { 262 this.template = tmplElement[0].innerHTML; 263 } 264 265 if (!this.template) { 266 throw new Error('The row template is required for the subform element to work'); 267 } 268 } 269 /** 270 * Add new row 271 * @param {HTMLElement} after 272 * @returns {HTMLElement} 273 */ 274 ; 275 276 _proto.addRow = function addRow(after) { 277 // Count how many we already have 278 var count = this.getRows().length; 279 280 if (count >= this.maximum) { 281 return null; 282 } // Make a new row from the template 283 284 285 var tmpEl; 286 287 if (this.containerWithRows.nodeName === 'TBODY' || this.containerWithRows.nodeName === 'TABLE') { 288 tmpEl = document.createElement('tbody'); 289 } else { 290 tmpEl = document.createElement('div'); 291 } 292 293 tmpEl.innerHTML = this.template; 294 var row = tmpEl.children[0]; // Add to container 295 296 if (after) { 297 after.parentNode.insertBefore(row, after.nextSibling); 298 } else { 299 this.containerWithRows.append(row); 300 } // Add draggable attributes 301 302 303 if (this.buttonMove) { 304 row.setAttribute('draggable', 'false'); 305 row.setAttribute('aria-grabbed', 'false'); 306 row.setAttribute('tabindex', '0'); 307 } // Marker that it is new 308 309 310 row.setAttribute('data-new', '1'); // Fix names and ids, and reset values 311 312 this.fixUniqueAttributes(row, count); // Tell about the new row 313 314 this.dispatchEvent(new CustomEvent('subform-row-add', { 315 detail: { 316 row: row 317 }, 318 bubbles: true 319 })); 320 row.dispatchEvent(new CustomEvent('joomla:updated', { 321 bubbles: true, 322 cancelable: true 323 })); 324 return row; 325 } 326 /** 327 * Remove the row 328 * @param {HTMLElement} row 329 */ 330 ; 331 332 _proto.removeRow = function removeRow(row) { 333 // Count how much we have 334 var count = this.getRows().length; 335 336 if (count <= this.minimum) { 337 return; 338 } // Tell about the row will be removed 339 340 341 this.dispatchEvent(new CustomEvent('subform-row-remove', { 342 detail: { 343 row: row 344 }, 345 bubbles: true 346 })); 347 row.dispatchEvent(new CustomEvent('joomla:removed', { 348 bubbles: true, 349 cancelable: true 350 })); 351 row.parentNode.removeChild(row); 352 } 353 /** 354 * Fix name and id for fields that are in the row 355 * @param {HTMLElement} row 356 * @param {Number} count 357 */ 358 ; 359 360 _proto.fixUniqueAttributes = function fixUniqueAttributes(row, count) { 361 var _this3 = this; 362 363 var countTmp = count || 0; 364 var group = row.getAttribute('data-group'); // current group name 365 366 var basename = row.getAttribute('data-base-name'); 367 var countnew = Math.max(this.lastRowIndex, countTmp); 368 var groupnew = basename + countnew; // new group name 369 370 this.lastRowIndex = countnew + 1; 371 row.setAttribute('data-group', groupnew); // Fix inputs that have a "name" attribute 372 373 var haveName = row.querySelectorAll('[name]'); 374 var ids = {}; // Collect id for fix checkboxes and radio 375 // Filter out nested 376 377 haveName = [].slice.call(haveName).filter(function (el) { 378 if (el.nodeName === 'JOOMLA-FIELD-SUBFORM') { 379 // Skip self in .closest() call 380 return el.parentElement.closest('joomla-field-subform') === _this3; 381 } 382 383 return el.closest('joomla-field-subform') === _this3; 384 }); 385 haveName.forEach(function (elem) { 386 var $el = elem; 387 var name = $el.getAttribute('name'); 388 var aria = $el.getAttribute('aria-describedby'); 389 var id = name.replace(/(\[\]$)/g, '').replace(/(\]\[)/g, '__').replace(/\[/g, '_').replace(/\]/g, ''); // id from name 390 391 var nameNew = name.replace("[" + group + "][", "[" + groupnew + "]["); // New name 392 393 var idNew = id.replace(group, groupnew).replace(/\W/g, '_'); // Count new id 394 395 var countMulti = 0; // count for multiple radio/checkboxes 396 397 var forOldAttr = id; // Fix "for" in the labels 398 399 if ($el.type === 'checkbox' && name.match(/\[\]$/)) { 400 // <input type="checkbox" name="name[]"> fix 401 // Recount id 402 countMulti = ids[id] ? ids[id].length : 0; 403 404 if (!countMulti) { 405 // Set the id for fieldset and group label 406 var fieldset = $el.closest('fieldset.checkboxes'); 407 var elLbl = row.querySelector("label[for=\"" + id + "\"]"); 408 409 if (fieldset) { 410 fieldset.setAttribute('id', idNew); 411 } 412 413 if (elLbl) { 414 elLbl.setAttribute('for', idNew); 415 elLbl.setAttribute('id', idNew + "-lbl"); 416 } 417 } 418 419 forOldAttr += countMulti; 420 idNew += countMulti; 421 } else if ($el.type === 'radio') { 422 // <input type="radio"> fix 423 // Recount id 424 countMulti = ids[id] ? ids[id].length : 0; 425 426 if (!countMulti) { 427 // Set the id for fieldset and group label 428 var _fieldset = $el.closest('fieldset.radio'); 429 430 var _elLbl = row.querySelector("label[for=\"" + id + "\"]"); 431 432 if (_fieldset) { 433 _fieldset.setAttribute('id', idNew); 434 } 435 436 if (_elLbl) { 437 _elLbl.setAttribute('for', idNew); 438 439 _elLbl.setAttribute('id', idNew + "-lbl"); 440 } 441 } 442 443 forOldAttr += countMulti; 444 idNew += countMulti; 445 } // Cache already used id 446 447 448 if (ids[id]) { 449 ids[id].push(true); 450 } else { 451 ids[id] = [true]; 452 } // Replace the name to new one 453 454 455 $el.name = nameNew; 456 457 if ($el.id) { 458 $el.id = idNew; 459 } 460 461 if (aria) { 462 $el.setAttribute('aria-describedby', nameNew + "-desc"); 463 } // Check if there is a label for this input 464 465 466 var lbl = row.querySelector("label[for=\"" + forOldAttr + "\"]"); 467 468 if (lbl) { 469 lbl.setAttribute('for', idNew); 470 lbl.setAttribute('id', idNew + "-lbl"); 471 } 472 }); 473 } 474 /** 475 * Use of HTML Drag and Drop API 476 * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API 477 * https://www.sitepoint.com/accessible-drag-drop/ 478 */ 479 ; 480 481 _proto.setUpDragSort = function setUpDragSort() { 482 var that = this; // Self reference 483 484 var item = null; // Storing the selected item 485 486 var touched = false; // We have a touch events 487 // Find all existing rows and add draggable attributes 488 489 var rows = Array.from(this.getRows()); 490 rows.forEach(function (row) { 491 row.setAttribute('draggable', 'false'); 492 row.setAttribute('aria-grabbed', 'false'); 493 row.setAttribute('tabindex', '0'); 494 }); // Helper method to test whether Handler was clicked 495 496 function getMoveHandler(element) { 497 return !element.form // This need to test whether the element is :input 498 && element.matches(that.buttonMove) ? element : element.closest(that.buttonMove); 499 } // Helper method to move row to selected position 500 501 502 function switchRowPositions(src, dest) { 503 var isRowBefore = false; 504 505 if (src.parentNode === dest.parentNode) { 506 for (var cur = src; cur; cur = cur.previousSibling) { 507 if (cur === dest) { 508 isRowBefore = true; 509 break; 510 } 511 } 512 } 513 514 if (isRowBefore) { 515 dest.parentNode.insertBefore(src, dest); 516 } else { 517 dest.parentNode.insertBefore(src, dest.nextSibling); 518 } 519 } 520 /** 521 * Touch interaction: 522 * 523 * - a touch of "move button" marks a row draggable / "selected", 524 * or deselect previous selected 525 * 526 * - a touch of "move button" in the destination row will move 527 * a selected row to a new position 528 */ 529 530 531 this.addEventListener('touchstart', function (event) { 532 touched = true; // Check for .move button 533 534 var handler = getMoveHandler(event.target); 535 var row = handler ? handler.closest(that.repeatableElement) : null; 536 537 if (!row || row.closest('joomla-field-subform') !== that) { 538 return; 539 } // First selection 540 541 542 if (!item) { 543 row.setAttribute('draggable', 'true'); 544 row.setAttribute('aria-grabbed', 'true'); 545 item = row; 546 } else { 547 // Second selection 548 // Move to selected position 549 if (row !== item) { 550 switchRowPositions(item, row); 551 } 552 553 item.setAttribute('draggable', 'false'); 554 item.setAttribute('aria-grabbed', 'false'); 555 item = null; 556 } 557 558 event.preventDefault(); 559 }); // Mouse interaction 560 // - mouse down, enable "draggable" and allow to drag the row, 561 // - mouse up, disable "draggable" 562 563 this.addEventListener('mousedown', function (_ref) { 564 var target = _ref.target; 565 if (touched) return; // Check for .move button 566 567 var handler = getMoveHandler(target); 568 var row = handler ? handler.closest(that.repeatableElement) : null; 569 570 if (!row || row.closest('joomla-field-subform') !== that) { 571 return; 572 } 573 574 row.setAttribute('draggable', 'true'); 575 row.setAttribute('aria-grabbed', 'true'); 576 item = row; 577 }); 578 this.addEventListener('mouseup', function () { 579 if (item && !touched) { 580 item.setAttribute('draggable', 'false'); 581 item.setAttribute('aria-grabbed', 'false'); 582 item = null; 583 } 584 }); // Keyboard interaction 585 // - "tab" to navigate to needed row, 586 // - modifier (ctr,alt,shift) + "space" select the row, 587 // - "tab" to select destination, 588 // - "enter" to place selected row in to destination 589 // - "esc" to cancel selection 590 591 this.addEventListener('keydown', function (event) { 592 if (event.keyCode !== KEYCODE.ESC && event.keyCode !== KEYCODE.SPACE && event.keyCode !== KEYCODE.ENTER || event.target.form || !event.target.matches(that.repeatableElement)) { 593 return; 594 } 595 596 var row = event.target; // Make sure we handle correct children 597 598 if (!row || row.closest('joomla-field-subform') !== that) { 599 return; 600 } // Space is the selection or unselection keystroke 601 602 603 if (event.keyCode === KEYCODE.SPACE && hasModifier(event)) { 604 // Unselect previously selected 605 if (row.getAttribute('aria-grabbed') === 'true') { 606 row.setAttribute('draggable', 'false'); 607 row.setAttribute('aria-grabbed', 'false'); 608 item = null; 609 } else { 610 // Select new 611 // If there was previously selected 612 if (item) { 613 item.setAttribute('draggable', 'false'); 614 item.setAttribute('aria-grabbed', 'false'); 615 item = null; 616 } // Mark new selection 617 618 619 row.setAttribute('draggable', 'true'); 620 row.setAttribute('aria-grabbed', 'true'); 621 item = row; 622 } // Prevent default to suppress any native actions 623 624 625 event.preventDefault(); 626 } // Escape is the abort keystroke (for any target element) 627 628 629 if (event.keyCode === KEYCODE.ESC && item) { 630 item.setAttribute('draggable', 'false'); 631 item.setAttribute('aria-grabbed', 'false'); 632 item = null; 633 } // Enter, to place selected item in selected position 634 635 636 if (event.keyCode === KEYCODE.ENTER && item) { 637 item.setAttribute('draggable', 'false'); 638 item.setAttribute('aria-grabbed', 'false'); // Do nothing here 639 640 if (row === item) { 641 item = null; 642 return; 643 } // Move the item to selected position 644 645 646 switchRowPositions(item, row); 647 event.preventDefault(); 648 item = null; 649 } 650 }); // dragstart event to initiate mouse dragging 651 652 this.addEventListener('dragstart', function (_ref2) { 653 var dataTransfer = _ref2.dataTransfer; 654 655 if (item) { 656 // We going to move the row 657 dataTransfer.effectAllowed = 'move'; // This need to work in Firefox and IE10+ 658 659 dataTransfer.setData('text', ''); 660 } 661 }); 662 this.addEventListener('dragover', function (event) { 663 if (item) { 664 event.preventDefault(); 665 } 666 }); // Handle drag action, move element to hovered position 667 668 this.addEventListener('dragenter', function (_ref3) { 669 var target = _ref3.target; 670 671 // Make sure the target in the correct container 672 if (!item || target.parentElement.closest('joomla-field-subform') !== that) { 673 return; 674 } // Find a hovered row 675 676 677 var row = target.closest(that.repeatableElement); // One more check for correct parent 678 679 if (!row || row.closest('joomla-field-subform') !== that) return; 680 switchRowPositions(item, row); 681 }); // dragend event to clean-up after drop or abort 682 // which fires whether or not the drop target was valid 683 684 this.addEventListener('dragend', function () { 685 if (item) { 686 item.setAttribute('draggable', 'false'); 687 item.setAttribute('aria-grabbed', 'false'); 688 item = null; 689 } 690 }); 691 }; 692 693 _createClass(JoomlaFieldSubform, [{ 694 key: "buttonAdd", 695 get: // Attribute getters 696 function get() { 697 return this.getAttribute('button-add'); 698 } 699 }, { 700 key: "buttonRemove", 701 get: function get() { 702 return this.getAttribute('button-remove'); 703 } 704 }, { 705 key: "buttonMove", 706 get: function get() { 707 return this.getAttribute('button-move'); 708 } 709 }, { 710 key: "rowsContainer", 711 get: function get() { 712 return this.getAttribute('rows-container'); 713 } 714 }, { 715 key: "repeatableElement", 716 get: function get() { 717 return this.getAttribute('repeatable-element'); 718 } 719 }, { 720 key: "minimum", 721 get: function get() { 722 return this.getAttribute('minimum'); 723 } 724 }, { 725 key: "maximum", 726 get: function get() { 727 return this.getAttribute('maximum'); 728 } 729 }, { 730 key: "name", 731 get: function get() { 732 return this.getAttribute('name'); 733 }, 734 set: function set(value) { 735 // Update the template 736 this.template = this.template.replace(new RegExp(" name=\"" + this.name.replace(/[[\]]/g, '\\$&'), 'g'), " name=\"" + value); 737 this.setAttribute('name', value); 738 } 739 }]); 740 741 return JoomlaFieldSubform; 742 }( /*#__PURE__*/_wrapNativeSuper(HTMLElement)); 743 744 customElements.define('joomla-field-subform', JoomlaFieldSubform); 745 })(customElements); 746 747 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |