1/*! elementor-pro - v4.3.0 - 22-09-2026 */ 2(function() { 3 //#region \0rolldown/runtime.js 4 var __defProp$1 = Object.defineProperty; 5 var __name = (target, value) => __defProp$1(target, "name", { 6 value, 7 configurable: true 8 }); 9 var __esmMin = (fn, res, err) => () => { 10 if (err) throw err[0]; 11 try { 12 return fn && (res = fn(fn = 0)), res; 13 } catch (e) { 14 throw err = [e], e; 15 } 16 }; 17 var __exportAll = (all, no_symbols) => { 18 let target = {}; 19 for (var name in all) __defProp$1(target, name, { 20 get: all[name], 21 enumerable: true 22 }); 23 if (!no_symbols) __defProp$1(target, Symbol.toStringTag, { value: "Module" }); 24 return target; 25 }; 26 //#endregion 27 //#region assets/dev/js/public-path.js 28 __webpack_public_path__ = ElementorProFrontendConfig.urls.assets + "js/"; 29 //#endregion 30 //#region \0@[email protected]/helpers/esm/typeof.js 31 function _typeof(o) { 32 "@babel/helpers - typeof"; 33 return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) { 34 return typeof o; 35 } : function(o) { 36 return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; 37 }, _typeof(o); 38 } 39 //#endregion 40 //#region \0@[email protected]/helpers/esm/toPrimitive.js 41 function toPrimitive(t, r) { 42 if ("object" != _typeof(t) || !t) return t; 43 var e = t[Symbol.toPrimitive]; 44 if (void 0 !== e) { 45 var i = e.call(t, r || "default"); 46 if ("object" != _typeof(i)) return i; 47 throw new TypeError("@@toPrimitive must return a primitive value."); 48 } 49 return ("string" === r ? String : Number)(t); 50 } 51 //#endregion 52 //#region \0@[email protected]/helpers/esm/toPropertyKey.js 53 function toPropertyKey(t) { 54 var i = toPrimitive(t, "string"); 55 return "symbol" == _typeof(i) ? i : i + ""; 56 } 57 //#endregion 58 //#region \0@[email protected]/helpers/esm/defineProperty.js 59 function _defineProperty(e, r, t) { 60 return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, { 61 value: t, 62 enumerable: !0, 63 configurable: !0, 64 writable: !0 65 }) : e[r] = t, e; 66 } 67 //#endregion 68 //#region modules/motion-fx/assets/js/frontend/motion-fx/interactions/base.js 69 var base_default = class extends elementorModules.ViewModule { 70 static { 71 __name(this, "default"); 72 } 73 constructor(..._args) { 74 super(..._args); 75 _defineProperty(this, "onInsideViewport", () => { 76 this.run(); 77 this.animationFrameRequest = requestAnimationFrame(this.onInsideViewport); 78 }); 79 } 80 __construct(options) { 81 this.motionFX = options.motionFX; 82 if (!this.intersectionObservers) this.setElementInViewportObserver(); 83 } 84 setElementInViewportObserver() { 85 this.intersectionObserver = elementorModules.utils.Scroll.scrollObserver({ callback: (event) => { 86 if (event.isInViewport) this.onInsideViewport(); 87 else this.removeAnimationFrameRequest(); 88 } }); 89 const observedElement = "page" === this.motionFX.getSettings("range") ? elementorFrontend.elements.$body[0] : this.motionFX.elements.$parent[0]; 90 this.intersectionObserver.observe(observedElement); 91 } 92 runCallback(...args) { 93 this.getSettings("callback")(...args); 94 } 95 removeIntersectionObserver() { 96 if (this.intersectionObserver) this.intersectionObserver.unobserve(this.motionFX.elements.$parent[0]); 97 } 98 removeAnimationFrameRequest() { 99 if (this.animationFrameRequest) cancelAnimationFrame(this.animationFrameRequest); 100 } 101 destroy() { 102 this.removeAnimationFrameRequest(); 103 this.removeIntersectionObserver(); 104 } 105 onInit() { 106 super.onInit(); 107 } 108 }; 109 //#endregion 110 //#region modules/motion-fx/assets/js/frontend/motion-fx/interactions/scroll.js 111 var scroll_default = class extends base_default { 112 static { 113 __name(this, "default"); 114 } 115 run() { 116 if (pageYOffset === this.windowScrollTop) return false; 117 this.onScrollMovement(); 118 this.windowScrollTop = pageYOffset; 119 } 120 onScrollMovement() { 121 this.updateMotionFxDimensions(); 122 this.updateAnimation(); 123 this.resetTransitionVariable(); 124 } 125 resetTransitionVariable() { 126 this.motionFX.$element.css("--e-transform-transition-duration", "100ms"); 127 } 128 updateMotionFxDimensions() {
129 if (this.motionFX.getSettings().refreshDimensions) this.motionFX.defineDimensions(); 130 } 131 updateAnimation() { 132 let passedRangePercents; 133 if ("page" === this.motionFX.getSettings("range")) passedRangePercents = elementorModules.utils.Scroll.getPageScrollPercentage(); 134 else if (this.motionFX.getSettings("isFixedPosition")) passedRangePercents = elementorModules.utils.Scroll.getPageScrollPercentage({}, window.innerHeight); 135 else passedRangePercents = elementorModules.utils.Scroll.getElementViewportPercentage(this.motionFX.elements.$parent); 136 this.runCallback(passedRangePercents); 137 } 138 }; 139 //#endregion 140 //#region modules/motion-fx/assets/js/frontend/motion-fx/interactions/mouse-move.js 141 var MouseMoveInteraction = class MouseMoveInteraction extends base_default { 142 bindEvents() { 143 if (!MouseMoveInteraction.mouseTracked) { 144 elementorFrontend.elements.$window.on("mousemove", MouseMoveInteraction.updateMousePosition); 145 MouseMoveInteraction.mouseTracked = true; 146 } 147 } 148 run() { 149 const mousePosition = MouseMoveInteraction.mousePosition; 150 const oldMousePosition = this.oldMousePosition; 151 if (oldMousePosition.x === mousePosition.x && oldMousePosition.y === mousePosition.y) return; 152 this.oldMousePosition = { 153 x: mousePosition.x, 154 y: mousePosition.y 155 }; 156 const passedPercentsX = 100 / innerWidth * mousePosition.x; 157 const passedPercentsY = 100 / innerHeight * mousePosition.y; 158 this.runCallback(passedPercentsX, passedPercentsY); 159 } 160 onInit() { 161 this.oldMousePosition = {}; 162 super.onInit(); 163 } 164 }; 165 MouseMoveInteraction.mousePosition = {}; 166 MouseMoveInteraction.updateMousePosition = (event) => { 167 MouseMoveInteraction.mousePosition = { 168 x: event.clientX, 169 y: event.clientY 170 }; 171 }; 172 //#endregion 173 //#region modules/motion-fx/assets/js/frontend/motion-fx/actions.js 174 var actions_default = class extends elementorModules.Module { 175 static { 176 __name(this, "default"); 177 } 178 getMovePointFromPassedPercents(movableRange, passedPercents) { 179 return +(passedPercents / movableRange * 100).toFixed(2); 180 } 181 getEffectValueFromMovePoint(range, movePoint) { 182 return range * movePoint / 100; 183 } 184 getStep(passedPercents, options) { 185 if ("element" === this.getSettings("type")) return this.getElementStep(passedPercents, options); 186 return this.getBackgroundStep(passedPercents, options); 187 } 188 getElementStep(passedPercents, options) { 189 return -(passedPercents - 50) * options.speed; 190 } 191 getBackgroundStep(passedPercents, options) { 192 const movableRange = this.getSettings("dimensions.movable" + options.axis.toUpperCase()); 193 return -this.getEffectValueFromMovePoint(movableRange, passedPercents); 194 } 195 getDirectionMovePoint(passedPercents, direction, range) { 196 let movePoint; 197 if (passedPercents < range.start) if ("out-in" === direction) movePoint = 0; 198 else if ("in-out" === direction) movePoint = 100; 199 else { 200 movePoint = this.getMovePointFromPassedPercents(range.start, passedPercents); 201 if ("in-out-in" === direction) movePoint = 100 - movePoint; 202 } 203 else if (passedPercents < range.end) if ("in-out-in" === direction) movePoint = 0; 204 else if ("out-in-out" === direction) movePoint = 100; 205 else { 206 movePoint = this.getMovePointFromPassedPercents(range.end - range.start, passedPercents - range.start); 207 if ("in-out" === direction) movePoint = 100 - movePoint; 208 } 209 else if ("in-out" === direction) movePoint = 0; 210 else if ("out-in" === direction) movePoint = 100; 211 else { 212 movePoint = this.getMovePointFromPassedPercents(100 - range.end, 100 - passedPercents); 213 if ("in-out-in" === direction) movePoint = 100 - movePoint; 214 } 215 return movePoint; 216 } 217 translateX(actionData, passedPercents) { 218 actionData.axis = "x"; 219 actionData.unit = "px"; 220 this.transform("translateX", passedPercents, actionData); 221 } 222 translateY(actionData, passedPercents) { 223 actionData.axis = "y"; 224 actionData.unit = "px"; 225 this.transform("translateY", passedPercents, actionData); 226 } 227 translateXY(actionData, passedPercentsX, passedPercentsY) { 228 this.translateX(actionData, passedPercentsX); 229 this.translateY(actionData, passedPercentsY); 230 } 231 tilt(actionData, passedPercentsX, passedPercentsY) { 232 const options = { 233 speed: actionData.speed / 10, 234 direction: actionData.direction 235 }; 236 this.rotateX(options, passedPercentsY); 237 this.rotateY(options, 100 - passedPercentsX); 238 } 239 rotateX(actionData, passedPercents) { 240 actionData.axis = "x"; 241 actionData.unit = "deg"; 242 this.transform("rotateX", passedPercents, actionData); 243 } 244 rotateY(actionData, passedPercents) { 245 actionData.axis = "y"; 246 actionData.unit = "deg"; 247 this.transform("rotateY", passedPercents, actionData); 248 } 249 rotateZ(actionData, passedPercents) { 250 actionData.unit = "deg"; 251 this.transform("rotateZ", passedPercents, actionData); 252 } 253 scale(actionData, passedPercents) { 254 const movePoint = this.getDirectionMovePoint(passedPercents, actionData.direction, actionData.range); 255 this.updateRulePart("transform", "scale", 1 + actionData.speed * movePoint / 1e3); 256 } 257 transform(action, passedPercents, actionData) { 258 if (actionData.direction) passedPercents = 100 - passedPercents;
259 this.updateRulePart("transform", action, this.getStep(passedPercents, actionData) + actionData.unit); 260 } 261 setCSSTransformVariables(elementSettings) { 262 this.CSSTransformVariables = []; 263 jQuery.each(elementSettings, (settingKey, settingValue) => { 264 const transformKeyMatches = settingKey.match(/_transform_(.+?)_effect/m); 265 if (transformKeyMatches && settingValue) { 266 if ("perspective" === transformKeyMatches[1]) { 267 this.CSSTransformVariables.unshift(transformKeyMatches[1]); 268 return; 269 } 270 if (this.CSSTransformVariables.includes(transformKeyMatches[1])) return; 271 this.CSSTransformVariables.push(transformKeyMatches[1]); 272 } 273 }); 274 } 275 opacity(actionData, passedPercents) { 276 const movePoint = this.getDirectionMovePoint(passedPercents, actionData.direction, actionData.range); 277 const level = actionData.level / 10; 278 const opacity = 1 - level + this.getEffectValueFromMovePoint(level, movePoint); 279 this.$element.css({ 280 opacity, 281 "will-change": "opacity" 282 }); 283 } 284 blur(actionData, passedPercents) { 285 const movePoint = this.getDirectionMovePoint(passedPercents, actionData.direction, actionData.range); 286 const blur = actionData.level - this.getEffectValueFromMovePoint(actionData.level, movePoint); 287 this.updateRulePart("filter", "blur", blur + "px"); 288 } 289 updateRulePart(ruleName, key, value) { 290 if (!this.rulesVariables[ruleName]) this.rulesVariables[ruleName] = {}; 291 if (!this.rulesVariables[ruleName][key]) { 292 this.rulesVariables[ruleName][key] = true; 293 this.updateRule(ruleName); 294 } 295 const cssVarKey = `--${key}`; 296 this.$element[0].style.setProperty(cssVarKey, value); 297 } 298 updateRule(ruleName) { 299 let value = ""; 300 value += this.concatTransformCSSProperties(ruleName); 301 value += this.concatTransformMotionEffectCSSProperties(ruleName); 302 this.$element.css(ruleName, value); 303 } 304 concatTransformCSSProperties(ruleName) { 305 let value = ""; 306 if ("transform" === ruleName) jQuery.each(this.CSSTransformVariables, (index, variableKey) => { 307 const variableName = variableKey; 308 if (variableKey.startsWith("flip")) variableKey = variableKey.replace("flip", "scale"); 309 const defaultUnit = variableKey.startsWith("rotate") || variableKey.startsWith("skew") ? "deg" : "px"; 310 const defaultValue = variableKey.startsWith("scale") ? 1 : 0 + defaultUnit; 311 value += `${variableKey}(var(--e-transform-${variableName}, ${defaultValue}))`; 312 }); 313 return value; 314 } 315 concatTransformMotionEffectCSSProperties(ruleName) { 316 let value = ""; 317 jQuery.each(this.rulesVariables[ruleName], (variableKey) => { 318 value += `${variableKey}(var(--${variableKey}))`; 319 }); 320 return value; 321 } 322 runAction(actionName, actionData, passedPercents, ...args) { 323 if (actionData.affectedRange) { 324 if (actionData.affectedRange.start > passedPercents) passedPercents = actionData.affectedRange.start; 325 if (actionData.affectedRange.end < passedPercents) passedPercents = actionData.affectedRange.end; 326 } 327 this[actionName](actionData, passedPercents, ...args); 328 } 329 refresh() { 330 this.rulesVariables = {}; 331 this.CSSTransformVariables = []; 332 this.$element.css({ 333 transform: "", 334 filter: "", 335 opacity: "", 336 "will-change": "" 337 }); 338 } 339 onInit() { 340 this.$element = this.getSettings("$targetElement"); 341 this.refresh(); 342 } 343 }; 344 //#endregion 345 //#region modules/motion-fx/assets/js/frontend/motion-fx/motion-fx.js 346 var motion_fx_default = class extends elementorModules.ViewModule { 347 static { 348 __name(this, "default"); 349 } 350 getDefaultSettings() { 351 return { 352 type: "element", 353 $element: null, 354 $dimensionsElement: null, 355 addBackgroundLayerTo: null, 356 interactions: {}, 357 refreshDimensions: false, 358 range: "viewport", 359 classes: { 360 element: "motion-fx-element", 361 parent: "motion-fx-parent", 362 backgroundType: "motion-fx-element-type-background", 363 container: "motion-fx-container", 364 layer: "motion-fx-layer", 365 perspective: "motion-fx-perspective" 366 } 367 }; 368 } 369 bindEvents() { 370 this.defineDimensions = this.defineDimensions.bind(this); 371 elementorFrontend.elements.$window.on("resize elementor-pro/motion-fx/recalc", this.defineDimensions); 372 } 373 unbindEvents() { 374 elementorFrontend.elements.$window.off("resize elementor-pro/motion-fx/recalc", this.defineDimensions); 375 }
376 addBackgroundLayer() { 377 const settings = this.getSettings(); 378 this.elements.$motionFXContainer = jQuery("<div>", { class: settings.classes.container }); 379 this.elements.$motionFXLayer = jQuery("<div>", { class: settings.classes.layer }); 380 this.updateBackgroundLayerSize(); 381 this.elements.$motionFXContainer.prepend(this.elements.$motionFXLayer); 382 (settings.addBackgroundLayerTo ? this.$element.find(settings.addBackgroundLayerTo) : this.$element).prepend(this.elements.$motionFXContainer); 383 } 384 removeBackgroundLayer() { 385 this.elements.$motionFXContainer.remove(); 386 } 387 updateBackgroundLayerSize() { 388 const settings = this.getSettings(); 389 const speed = { 390 x: 0, 391 y: 0 392 }; 393 const mouseInteraction = settings.interactions.mouseMove; 394 const scrollInteraction = settings.interactions.scroll; 395 if (mouseInteraction && mouseInteraction.translateXY) { 396 speed.x = mouseInteraction.translateXY.speed * 10; 397 speed.y = mouseInteraction.translateXY.speed * 10; 398 } 399 if (scrollInteraction) { 400 if (scrollInteraction.translateX) speed.x = scrollInteraction.translateX.speed * 10; 401 if (scrollInteraction.translateY) speed.y = scrollInteraction.translateY.speed * 10; 402 } 403 this.elements.$motionFXLayer.css({ 404 width: 100 + speed.x + "%", 405 height: 100 + speed.y + "%" 406 }); 407 } 408 defineDimensions() { 409 const $dimensionsElement = this.getSettings("$dimensionsElement") || this.$element; 410 const elementOffset = $dimensionsElement.offset(); 411 const dimensions = { 412 elementHeight: $dimensionsElement.outerHeight(), 413 elementWidth: $dimensionsElement.outerWidth(), 414 elementTop: elementOffset.top, 415 elementLeft: elementOffset.left 416 }; 417 dimensions.elementRange = dimensions.elementHeight + innerHeight; 418 this.setSettings("dimensions", dimensions); 419 if ("background" === this.getSettings("type")) this.defineBackgroundLayerDimensions(); 420 } 421 defineBackgroundLayerDimensions() { 422 const dimensions = this.getSettings("dimensions"); 423 dimensions.layerHeight = this.elements.$motionFXLayer.height(); 424 dimensions.layerWidth = this.elements.$motionFXLayer.width(); 425 dimensions.movableX = dimensions.layerWidth - dimensions.elementWidth; 426 dimensions.movableY = dimensions.layerHeight - dimensions.elementHeight; 427 this.setSettings("dimensions", dimensions); 428 } 429 initInteractionsTypes() { 430 this.interactionsTypes = { 431 scroll: scroll_default, 432 mouseMove: MouseMoveInteraction 433 }; 434 } 435 prepareSpecialActions() { 436 const settings = this.getSettings(); 437 const hasTiltEffect = !!(settings.interactions.mouseMove && settings.interactions.mouseMove.tilt); 438 this.elements.$parent.toggleClass(settings.classes.perspective, hasTiltEffect); 439 } 440 cleanSpecialActions() { 441 const settings = this.getSettings(); 442 this.elements.$parent.removeClass(settings.classes.perspective); 443 } 444 runInteractions() { 445 const settings = this.getSettings(); 446 this.actions.setCSSTransformVariables(settings.elementSettings); 447 this.prepareSpecialActions(); 448 jQuery.each(settings.interactions, (interactionName, actions) => { 449 this.interactions[interactionName] = new this.interactionsTypes[interactionName]({ 450 motionFX: this, 451 callback: (...args) => { 452 jQuery.each(actions, (actionName, actionData) => this.actions.runAction(actionName, actionData, ...args)); 453 } 454 }); 455 this.interactions[interactionName].run(); 456 }); 457 } 458 destroyInteractions() { 459 this.cleanSpecialActions(); 460 jQuery.each(this.interactions, (interactionName, interaction) => interaction.destroy()); 461 this.interactions = {}; 462 } 463 refresh() { 464 this.actions.setSettings(this.getSettings()); 465 if ("background" === this.getSettings("type")) {
466 this.updateBackgroundLayerSize(); 467 this.defineBackgroundLayerDimensions(); 468 } 469 this.actions.refresh(); 470 this.destroyInteractions(); 471 this.runInteractions(); 472 } 473 destroy() { 474 this.destroyInteractions(); 475 this.actions.refresh(); 476 const settings = this.getSettings(); 477 this.$element.removeClass(settings.classes.element); 478 this.elements.$parent.removeClass(settings.classes.parent); 479 if ("background" === settings.type) { 480 this.$element.removeClass(settings.classes.backgroundType); 481 this.removeBackgroundLayer(); 482 } 483 } 484 onInit() { 485 super.onInit(); 486 const settings = this.getSettings(); 487 this.$element = settings.$element; 488 this.elements.$parent = this.$element.parent(); 489 this.$element.addClass(settings.classes.element); 490 this.elements.$parent = this.$element.parent(); 491 this.elements.$parent.addClass(settings.classes.parent); 492 if ("background" === settings.type) { 493 this.$element.addClass(settings.classes.backgroundType); 494 this.addBackgroundLayer(); 495 } 496 this.defineDimensions(); 497 settings.$targetElement = "element" === settings.type ? this.$element : this.elements.$motionFXLayer; 498 this.interactions = {}; 499 this.actions = new actions_default(settings); 500 this.initInteractionsTypes(); 501 this.runInteractions(); 502 } 503 }; 504 //#endregion 505 //#region modules/motion-fx/assets/js/frontend/handler.js 506 var handler_default = class extends elementorModules.frontend.handlers.Base { 507 static { 508 __name(this, "default"); 509 } 510 __construct(...args) { 511 super.__construct(...args); 512 this.toggle = elementorFrontend.debounce(this.toggle, 200); 513 } 514 getDefaultSettings() { 515 return { selectors: { container: ".elementor-widget-container" } }; 516 } 517 getDefaultElements() { 518 const selectors = this.getSettings("selectors"); 519 let container = this.$element.find(selectors.container); 520 if (0 === container.length) container = this.$element; 521 return { $container: container }; 522 } 523 bindEvents() { 524 elementorFrontend.elements.$window.on("resize", this.toggle); 525 } 526 unbindEvents() { 527 elementorFrontend.elements.$window.off("resize", this.toggle); 528 } 529 addCSSTransformEvents() { 530 if (this.getElementSettings("motion_fx_motion_fx_scrolling") && !this.isTransitionEventAdded) { 531 this.isTransitionEventAdded = true; 532 this.elements.$container.on("mouseenter", () => { 533 this.elements.$container.css("--e-transform-transition-duration", ""); 534 }); 535 } 536 } 537 initEffects() { 538 this.effects = { 539 translateY: { 540 interaction: "scroll", 541 actions: ["translateY"] 542 }, 543 translateX: { 544 interaction: "scroll", 545 actions: ["translateX"] 546 }, 547 rotateZ: { 548 interaction: "scroll", 549 actions: ["rotateZ"] 550 }, 551 scale: { 552 interaction: "scroll", 553 actions: ["scale"] 554 }, 555 opacity: { 556 interaction: "scroll", 557 actions: ["opacity"] 558 }, 559 blur: { 560 interaction: "scroll", 561 actions: ["blur"] 562 }, 563 mouseTrack: { 564 interaction: "mouseMove", 565 actions: ["translateXY"] 566 }, 567 tilt: { 568 interaction: "mouseMove", 569 actions: ["tilt"] 570 } 571 }; 572 } 573 prepareOptions(name) { 574 const elementSettings = this.getElementSettings(); 575 const type = "motion_fx" === name ? "element" : "background"; 576 const interactions = {}; 577 jQuery.each(elementSettings, (key, value) => { 578 const keyRegex = new RegExp("^" + name + "_(.+?)_effect"); 579 const keyMatches = key.match(keyRegex); 580 if (!keyMatches || !value) return; 581 const options = {}; 582 const effectName = keyMatches[1]; 583 jQuery.each(elementSettings, (subKey, subValue) => { 584 const subKeyRegex = new RegExp(name + "_" + effectName + "_(.+)"); 585 const subKeyMatches = subKey.match(subKeyRegex); 586 if (!subKeyMatches) return; 587 if ("effect" === subKeyMatches[1]) return; 588 if ("object" === typeof subValue) subValue = Object.keys(subValue.sizes).length ? subValue.sizes : subValue.size; 589 options[subKeyMatches[1]] = subValue; 590 }); 591 const effect = this.effects[effectName]; 592 const interactionName = effect.interaction; 593 if (!interactions[interactionName]) interactions[interactionName] = {}; 594 effect.actions.forEach((action) => interactions[interactionName][action] = options); 595 }); 596 let $element = this.$element; 597 let $dimensionsElement; 598 let $childElement; 599 const elementType = this.getElementType(); 600 if ("element" === type && !["section", "container"].includes(elementType)) { 601 $dimensionsElement = $element; 602 let childElementSelector; 603 if ("column" === elementType) childElementSelector = ".elementor-widget-wrap"; 604 else childElementSelector = ".elementor-widget-container"; 605 $childElement = $element.find("> " + childElementSelector); 606 $element = 0 === $childElement.length ? this.$element : $childElement; 607 } 608 const options = { 609 type, 610 interactions, 611 elementSettings, 612 $element, 613 $dimensionsElement, 614 refreshDimensions: this.isEdit, 615 range: elementSettings[name + "_range"], 616 classes: { 617 element: "elementor-motion-effects-element", 618 parent: "elementor-motion-effects-parent", 619 backgroundType: "elementor-motion-effects-element-type-background", 620 container: "elementor-motion-effects-container", 621 layer: "elementor-motion-effects-layer", 622 perspective: "elementor-motion-effects-perspective" 623 } 624 }; 625 if (!options.range && "fixed" === this.getCurrentDeviceSetting("_position")) options.range = "page"; 626 if ("fixed" === this.getCurrentDeviceSetting("_position")) options.isFixedPosition = true; 627 if ("background" === type && "column" === this.getElementType()) options.addBackgroun
627dLayerTo = " > .elementor-element-populated"; 628 return options; 629 } 630 activate(name) { 631 const options = this.prepareOptions(name); 632 if (jQuery.isEmptyObject(options.interactions)) return; 633 this[name] = new motion_fx_default(options); 634 } 635 deactivate(name) { 636 if (this[name]) { 637 this[name].destroy(); 638 delete this[name]; 639 } 640 } 641 toggle() { 642 const currentDeviceMode = elementorFrontend.getCurrentDeviceMode(); 643 const elementSettings = this.getElementSettings(); 644 ["motion_fx", "background_motion_fx"].forEach((name) => { 645 const devices = elementSettings[name + "_devices"]; 646 if ((!devices || -1 !== devices.indexOf(currentDeviceMode)) && (elementSettings[name + "_motion_fx_scrolling"] || elementSettings[name + "_motion_fx_mouse"])) if (this[name]) this.refreshInstance(name); 647 else this.activate(name); 648 else this.deactivate(name); 649 }); 650 } 651 refreshInstance(instanceName) { 652 const instance = this[instanceName]; 653 if (!instance) return; 654 const preparedOptions = this.prepareOptions(instanceName); 655 instance.setSettings(preparedOptions); 656 instance.refresh(); 657 } 658 onInit() { 659 super.onInit(); 660 const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); 661 if (prefersReducedMotion && prefersReducedMotion.matches) return; 662 this.initEffects(); 663 this.addCSSTransformEvents(); 664 this.toggle(); 665 } 666 onElementChange(propertyName) { 667 if (/motion_fx_((scrolling)|(mouse)|(devices))$/.test(propertyName)) { 668 if ("motion_fx_motion_fx_scrolling" === propertyName) this.addCSSTransformEvents(); 669 this.toggle(); 670 return; 671 } 672 const propertyMatches = propertyName.match(".*?(motion_fx|_transform)"); 673 if (propertyMatches) { 674 const instanceName = propertyMatches[0].match("(_transform)") ? "motion_fx" : propertyMatches[0]; 675 this.refreshInstance(instanceName); 676 if (!this[instanceName]) this.activate(instanceName); 677 } 678 if (/^_position/.test(propertyName)) ["motion_fx", "background_motion_fx"].forEach((instanceName) => { 679 this.refreshInstance(instanceName); 680 }); 681 } 682 onDestroy() { 683 super.onDestroy(); 684 ["motion_fx", "background_motion_fx"].forEach((name) => { 685 this.deactivate(name); 686 }); 687 } 688 }; 689 //#endregion 690 //#region modules/motion-fx/assets/js/frontend/frontend.js 691 var frontend_default$5 = class extends elementorModules.Module { 692 static { 693 __name(this, "default"); 694 } 695 constructor() { 696 super(); 697 elementorFrontend.elementsHandler.attachHandler("global", handler_default, null); 698 } 699 }; 700 //#endregion 701 //#region ../elementor/assets/dev/js/frontend/utils/utils.js 702 var isScrollSnapActive = () => { 703 var _a; 704 var _b; 705 return "yes" === (elementorFrontend.isEditMode() ? (_a = elementor.settings.page.model.attributes) == null ? void 0 : _a.scroll_snap : (_b = elementorFrontend.config.settings.page) == null ? void 0 : _b.scroll_snap) ? true : false; 706 }; 707 //#endregion 708 //#region modules/sticky/assets/js/frontend/handlers/sticky.js 709 var sticky_default = elementorModules.frontend.handlers.Base.extend({ 710 currentConfig: {}, 711 debouncedReactivate: null, 712 bindEvents() { 713 elementorFrontend.addListenerOnce(this.getUniqueHandlerID() + "sticky", "resize", this.reactivateOnResize); 714 }, 715 unbindEvents() { 716 elementorFrontend.removeListeners(this.getUniqueHandlerID() + "sticky", "resize", this.reactivateOnResize); 717 }, 718 isStickyInstanceActive() { 719 return void 0 !== this.$element.data("sticky"); 720 }, 721 /** 722 * Get the current active setting value for a responsive control. 723 * 724 * @param {string} setting 725 * @return {any} - Setting value. 726 */ 727 getResponsiveSetting(setting) { 728 const elementSettings = this.getElementSettings(); 729 return elementorFrontend.getCurrentDeviceSetting(elementSettings, setting); 730 }, 731 /** 732 * Return an array of settings names for responsive control (e.g. `settings`, `setting_tablet`, `setting_mobile` ). 733 * 734 * @param {string} setting 735 * @return {string[]} - List of settings. 736 */ 737 getResponsiveSettingList(setting) { 738 return ["", ...Object.keys(elementorFrontend.config.responsive.activeBreakpoints)].map((suffix) => { 739 return suffix ? `${setting}_${suffix}` : setting; 740 }); 741 }, 742 getConfig() { 743 const elementSettings = this.getElementSettings(); 744 const stickyOptions = { 745 to: elementSettings.sticky, 746 offset: this.getResponsiveSetting("sticky_offset"), 747 effectsOffset: this.getResponsiveSetting("sticky_effects_offset"), 748 classes: { 749 sticky: "elementor-sticky", 750 stickyActive: "elementor-sticky--active elementor-section--handles-inside", 751 stickyEffects: "elementor-sticky--effects", 752 spacer: "elementor-sticky__spacer" 753 }, 754 isRTL: elementorFrontend.config.is_rtl, 755 isScrollSnapActive: isScrollSnapActive(), 756 handleScrollbarWidth: elementorFrontend.isEditMode() 757 }; 758 const $wpAdminBar = elementorFrontend.elements.$wpAdminBar; 759 const isParentContainer = this.isContainerElement(this.$element[0]) && !this.isContainerElement(this.$element[0].parentElement); 760 if ($wpAdminBar.length && "top" === elementSettings.sticky && "fixed" === $wpAdminBar.css("position")) stickyOptions.offset += $
760wpAdminBar.height(); 761 if (elementSettings.sticky_parent && !isParentContainer) stickyOptions.parent = ".e-con, .e-con-inner, .elementor-widget-wrap"; 762 return stickyOptions; 763 }, 764 activate() { 765 this.currentConfig = this.getConfig(); 766 this.$element.sticky(this.currentConfig); 767 }, 768 deactivate() { 769 if (!this.isStickyInstanceActive()) return; 770 this.$element.sticky("destroy"); 771 }, 772 run(refresh) { 773 if (!this.getElementSettings("sticky")) { 774 this.deactivate(); 775 return; 776 } 777 var currentDeviceMode = elementorFrontend.getCurrentDeviceMode(); 778 if (-1 !== this.getElementSettings("sticky_on").indexOf(currentDeviceMode)) { 779 if (true === refresh) this.reactivate(); 780 else if (!this.isStickyInstanceActive()) this.activate(); 781 } else this.deactivate(); 782 }, 783 /** 784 * Reactivate the sticky instance on resize only if the new sticky config is different from the current active one, 785 * in order to avoid re-initializing the sticky when not needed, and avoid layout shifts. 786 * The config can be different between devices, so this need to be checked on each screen resize to make sure that 787 * the current screen size uses the appropriate Sticky config. 788 * 789 * @return {void} 790 */ 791 reactivateOnResize() { 792 clearTimeout(this.debouncedReactivate); 793 this.debouncedReactivate = setTimeout(() => { 794 const config = this.getConfig(); 795 if (JSON.stringify(config) !== JSON.stringify(this.currentConfig)) this.run(true); 796 }, 300); 797 }, 798 reactivate() { 799 this.deactivate(); 800 this.activate(); 801 }, 802 onElementChange(settingKey) { 803 if (-1 !== ["sticky", "sticky_on"].indexOf(settingKey)) this.run(true); 804 if (-1 !== [ 805 ...this.getResponsiveSettingList("sticky_offset"), 806 ...this.getResponsiveSettingList("sticky_effects_offset"), 807 "sticky_parent" 808 ].indexOf(settingKey)) this.reactivate(); 809 }, 810 /** 811 * Listen to device mode changes and re-initialize the sticky. 812 * 813 * @return {void} 814 */ 815 onDeviceModeChange() { 816 setTimeout(() => this.run(true)); 817 }, 818 onInit() { 819 elementorModules.frontend.handlers.Base.prototype.onInit.apply(this, arguments); 820 if (elementorFrontend.isEditMode()) elementor.listenTo(elementor.channels.deviceMode, "change", () => this.onDeviceModeChange()); 821 this.run(); 822 }, 823 onDestroy() { 824 elementorModules.frontend.handlers.Base.prototype.onDestroy.apply(this, arguments); 825 this.deactivate(); 826 }, 827 /** 828 * 829 * @param {HTMLElement|null|undefined} element 830 * @return {boolean} Is the passed element a container. 831 */ 832 isContainerElement(element) { 833 return ["e-con", "e-con-inner"].some((containerClass) => { 834 return element === null || element === void 0 ? void 0 : element.classList.contains(containerClass); 835 }); 836 } 837 }); 838 //#endregion 839 //#region modules/sticky/assets/js/frontend/frontend.js 840 var frontend_default$4 = class extends elementorModules.Module { 841 static { 842 __name(this, "default"); 843 } 844 constructor() { 845 super(); 846 elementorFrontend.elementsHandler.attachHandler("section", sticky_default, null); 847 elementorFrontend.elementsHandler.attachHandler("container", sticky_default, null); 848 elementorFrontend.elementsHandler.attachHandler("widget", sticky_default, null); 849 } 850 }; 851 var __vitePreload = function preload(baseModule, deps, importerUrl) { 852 let promise = Promise.resolve(); 853 function handlePreloadError(err) { 854 const e = new Event("vite:preloadError", { cancelable: true }); 855 e.payload = err; 856 window.dispatchEvent(e); 857 if (!e.defaultPrevented) throw err; 858 } 859 return promise.then((res) => { 860 for (const item of res || []) { 861 if (item.status !== "rejected") continue; 862 handlePreloadError(item.reason); 863 } 864 return baseModule().catch(handlePreloadError); 865 }); 866 }; 867 //#endregion 868 //#region modules/code-highlight/assets/js/frontend/handler.js 869 var handler_exports$1 = /* @__PURE__ */ __exportAll({ default: () => codeHighlightHandler }); 870 var codeHighlightHandler; 871 var init_handler$1 = __esmMin((() => { 872 codeHighlightHandler = class extends elementorModules.frontend.handlers.Base { 873 onInit(...args) { 874 super.onInit(...args); 875 Prism.highlightAllUnder(this.$element[0], false); 876 } 877 onElementChange() { 878 Prism.highlightAllUnder(this.$element[0], false); 879 } 880 }; 881 })); 882 //#endregion 883 //#region modules/code-highlight/assets/js/frontend/frontend.js 884 var frontend_default$3 = class extends elementorModules.Module { 885 static { 886 __name(this, "default"); 887 } 888 constructor() { 889 super(); 890 elementorFrontend.elementsHandler.attachHandler("code-highlight", () => __vitePreload(() => Promise.resolve().then(() => (init_handler$1(), handler_exports$1)), void 0)); 891 } 892 }; 893 //#endregion 894 //#region \0@[email protected]/helpers/esm/asyncToGenerator.js 895 function asyncGeneratorStep(n, t, e, r, o, a, c) { 896 try { 897 var i = n[a](c); 898 var u = i.value; 899 } catch (n) { 900 e(n); 901 return; 902 } 903 i.done ? t(u) : Promise.resolve(u).then(r, o); 904 } 905 function _asyncToGenerator(n) { 906 return function() { 907 var t = this; 908 var e = arguments; 909 return new Promise(function(r, o) { 910 var a = n.apply(t, e); 911 function _next(n) { 912 asyncGeneratorStep(a, r, o, _next, _throw, "next", n); 913 } 914 function _throw(n) { 915 asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); 916 } 917 _next(void 0); 918 }); 919 }; 920 } 921 var init_asyncToGenerator = __esmMin((() => {})); 922 //#endregion 923 //#region modules/video-playlist/assets/js/frontend/base-tabs.js 924 var baseTabs; 925 var init_base_tabs = __esmMin((() => { 926 baseTabs = class extends elementorModules.frontend.handlers.Base { 927 getDefaultSettings() { 928 return { 929 selectors: { 930 tablist: "[role=\"tablist\"]", 931 tabTitle: ".e-tab-title", 932 tabContent: ".e-tab-content" 933 }, 934 classes: { active: "e-active" }, 935 showTabFn: "show", 936 hideTabFn: "hide", 937 toggleSelf: true, 938 hidePrevious: true, 939 autoExpand: true, 940 keyDirection: { 941 ArrowLeft: elementorFrontendConfig.is_rtl ? 1 : -1, 942 ArrowUp: -1, 943 ArrowRight: elementorFrontendConfig.is_rtl ? -1 : 1, 944 ArrowDown: 1 945 } 946 }; 947 } 948 getDefaultElements() {
949 const selectors = this.getSettings("selectors"); 950 return { 951 $tabTitles: this.findElement(selectors.tabTitle), 952 $tabContents: this.findElement(selectors.tabContent) 953 }; 954 } 955 activateDefaultTab(videoId) { 956 const settings = this.getSettings(); 957 if (!settings.autoExpand || "editor" === settings.autoExpand && !this.isEdit) return; 958 const defaultActiveTab = this.getEditSettings("activeItemIndex") || videoId || 1; 959 const originalToggleMethods = { 960 showTabFn: settings.showTabFn, 961 hideTabFn: settings.hideTabFn 962 }; 963 this.setSettings({ 964 showTabFn: "show", 965 hideTabFn: "hide" 966 }); 967 this.changeActiveTab(defaultActiveTab); 968 this.setSettings(originalToggleMethods); 969 } 970 handleKeyboardNavigation(event) { 971 const tab = event.currentTarget; 972 const $tabList = jQuery(tab.closest(this.getSettings("selectors").tablist)); 973 const $tabs = $tabList.find(this.getSettings("selectors").tabTitle); 974 const isVertical = "vertical" === $tabList.attr("aria-orientation"); 975 switch (event.key) { 976 case "ArrowLeft": 977 case "ArrowRight": 978 if (isVertical) return; 979 break; 980 case "ArrowUp": 981 case "ArrowDown": 982 if (!isVertical) return; 983 event.preventDefault(); 984 break; 985 case "Home": 986 event.preventDefault(); 987 $tabs.first().trigger("focus"); 988 return; 989 case "End": 990 event.preventDefault(); 991 $tabs.last().trigger("focus"); 992 return; 993 default: return; 994 } 995 const tabIndex = tab.getAttribute("data-tab") - 1; 996 const direction = this.getSettings("keyDirection")[event.key]; 997 const nextTab = $tabs[tabIndex + direction]; 998 if (nextTab) nextTab.focus(); 999 else if (-1 === tabIndex + direction) $tabs.last().trigger("focus"); 1000 else $tabs.first().trigger("focus"); 1001 } 1002 deactivateActiveTab(tabIndex) { 1003 const settings = this.getSettings(); 1004 const activeClass = settings.classes.active; 1005 const activeFilter = tabIndex ? "[data-tab=\"" + tabIndex + "\"]" : "." + activeClass; 1006 const $activeTitle = this.elements.$tabTitles.filter(activeFilter); 1007 const $activeContent = this.elements.$tabContents.filter(activeFilter); 1008 $activeTitle.add($activeContent).removeClass(activeClass); 1009 $activeTitle.attr({ 1010 tabindex: "-1", 1011 "aria-selected": "false" 1012 }); 1013 $activeContent[settings.hideTabFn](); 1014 $activeContent.attr("hidden", "hidden"); 1015 } 1016 activateTab(tabIndex) { 1017 const settings = this.getSettings(); 1018 const activeClass = settings.classes.active; 1019 const $requestedTitle = this.elements.$tabTitles.filter("[data-tab=\"" + tabIndex + "\"]"); 1020 const $requestedContent = this.elements.$tabContents.filter("[data-tab=\"" + tabIndex + "\"]"); 1021 const animationDuration = "show" === settings.showTabFn ? 0 : 400; 1022 $requestedTitle.add($requestedContent).addClass(activeClass); 1023 $requestedTitle.attr({ 1024 tabindex: "0", 1025 "aria-selected": "true" 1026 }); 1027 $requestedContent[settings.showTabFn](animationDuration, () => elementorFrontend.elements.$window.trigger("resize")); 1028 $requestedContent.removeAttr("hidden"); 1029 } 1030 isActiveTab(tabIndex) { 1031 return this.elements.$tabTitles.filter("[data-tab=\"" + tabIndex + "\"]").hasClass(this.getSettings("classes.active")); 1032 } 1033 bindEvents() { 1034 this.elements.$tabTitles.on({ 1035 keydown: (event) => { 1036 if (jQuery(event.target).is("a") && `Enter` === event.key) event.preventDefault(); 1037 if ([ 1038 "End", 1039 "Home", 1040 "ArrowUp", 1041 "ArrowDown" 1042 ].includes(event.key)) this.handleKeyboardNavigation(event); 1043 }, 1044 keyup: (event) => { 1045 switch (event.key) { 1046 case "ArrowLeft": 1047 case "ArrowRight": 1048 this.handleKeyboardNavigation(event); 1049 break; 1050 case "Enter": 1051 case "Space": 1052 event.preventDefault(); 1053 this.changeActiveTab(event.currentTarget.getAttribute("data-tab")); 1054 break; 1055 } 1056 }, 1057 click: (event) => { 1058 event.preventDefault(); 1059 this.changeActiveTab(event.currentTarget.getAttribute("data-tab")); 1060 } 1061 }); 1062 } 1063 onInit(...args) { 1064 super.onInit(...args); 1065 } 1066 changeActiveTab(tabIndex) { 1067 const isActiveTab = this.isActiveTab(tabIndex);
1068 const settings = this.getSettings(); 1069 if ((settings.toggleSelf || !isActiveTab) && settings.hidePrevious) this.deactivateActiveTab(); 1070 if (!settings.hidePrevious && isActiveTab) this.deactivateActiveTab(tabIndex); 1071 if (!isActiveTab) this.activateTab(tabIndex); 1072 } 1073 }; 1074 })); 1075 //#endregion 1076 //#region modules/video-playlist/assets/js/frontend/player-base.js 1077 var PlayerBase; 1078 var init_player_base = __esmMin((() => { 1079 PlayerBase = class { 1080 constructor(playlistItem, videoIndex) { 1081 this.playlistItem = playlistItem; 1082 this.positionInVideoList = videoIndex; 1083 } 1084 formatDuration(duration) { 1085 const dateObj = /* @__PURE__ */ new Date(duration * 1e3); 1086 const hours = dateObj.getUTCHours(); 1087 const minutes = dateObj.getUTCMinutes(); 1088 const seconds = dateObj.getSeconds(); 1089 if (hours !== 0) return `${hours.toString()}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; 1090 return `${minutes.toString()}:${seconds.toString().padStart(2, "0")}`; 1091 } 1092 }; 1093 })); 1094 //#endregion 1095 //#region modules/video-playlist/assets/js/frontend/player-youtube.js 1096 var playerYoutube; 1097 var init_player_youtube = __esmMin((() => { 1098 init_player_base(); 1099 init_asyncToGenerator(); 1100 playerYoutube = class extends PlayerBase { 1101 constructor(playlistItem, videoIndex) { 1102 super(playlistItem, videoIndex); 1103 this.apiProvider = elementorFrontend.utils.youtube; 1104 this.playerObject = null; 1105 this.watchCount = 0; 1106 this.isVideoPlaying = false; 1107 this.isVideoPausedLocal = false;
1108 this.isVideoEnded = false; 1109 this.seekSequenceArray = []; 1110 this.pauseCurrentTime = null; 1111 this.isReady = false; 1112 } 1113 create() { 1114 this.currentVideoID = this.apiProvider.getVideoIDFromURL(this.playlistItem.videoUrl); 1115 return new Promise((resolve) => { 1116 this.apiProvider.onApiReady((apiObject) => { 1117 const playerOptions = { 1118 width: "773", 1119 videoId: this.currentVideoID, 1120 playerVars: { 1121 rel: 0, 1122 showinfo: 0, 1123 ecver: 2 1124 }, 1125 events: { onReady: () => { 1126 this.isReady = true; 1127 resolve(); 1128 } } 1129 }; 1130 this.playerObject = new apiObject.Player(this.playlistItem.tabContent.querySelector("div"), playerOptions); 1131 this.playerObject.addEventListener("onStateChange", (event) => { 1132 if (3 === event.data) if (2 === this.seekSequenceArray[this.seekSequenceArray.length - 1]) this.seekSequenceArray.push(3); 1133 else { 1134 this.seekSequenceArray = []; 1135 clearTimeout(this.seekTimeOut); 1136 } 1137 }); 1138 }); 1139 }); 1140 } 1141 handleEnded(callback) { 1142 this.playerObject.addEventListener("onStateChange", (event) => { 1143 if (0 === event.data) { 1144 this.watchCount++; 1145 this.isVideoEnded = true; 1146 event.target.seekTo(0); 1147 event.target.stopVideo(); 1148 this.isVideoPlaying = false; 1149 callback(); 1150 } 1151 }); 1152 } 1153 handlePaused(callback) { 1154 this.playerObject.addEventListener("onStateChange", (event) => { 1155 if (2 === event.data) { 1156 this.seekSequenceArray = []; 1157 this.seekSequenceArray.push(2); 1158 this.pauseCurrentTime = this.playerObject.playerInfo.currentTime; 1159 this.seekTimeOut = setTimeout(() => { 1160 if (2 === this.seekSequenceArray.length && 2 === this.seekSequenceArray[0] && 3 === this.seekSequenceArray[1]) { 1161 this.seekSequenceArray = []; 1162 clearTimeout(this.seekTimeOut); 1163 } else { 1164 callback(this.positionInVideoList); 1165 this.isVideoPausedLocal = true; 1166 } 1167 }, 1e3); 1168 } 1169 }); 1170 } 1171 handlePlayed(callback) { 1172 this.playerObject.addEventListener("onStateChange", (event) => { 1173 if (1 === event.data && !this.isVideoEnded) { 1174 if (!(2 === this.seekSequenceArray.length && 2 === this.seekSequenceArray[0] && 3 === this.seekSequenceArray[1])) callback(); 1175 } else this.isVideoEnded = false; 1176 }); 1177 } 1178 handleError(callback) { 1179 this.playerObject.addEventListener("onError", () => { 1180 callback(); 1181 }); 1182 } 1183 handleFullScreenChange(callback) { 1184 this.playerObject.h.addEventListener("fullscreenchange", () => { 1185 callback(document.fullscreenElement); 1186 }); 1187 } 1188 getCurrentTime() { 1189 const currentTime = this.pauseCurrentTime ? this.pauseCurrentTime : this.playerObject.playerInfo.currentTime; 1190 this.pauseCurrentTime = null; 1191 return currentTime; 1192 } 1193 play() { 1194 if (!this.isReady) return; 1195 this.isVideoPlaying = true; 1196 this.playerObject.playVideo(); 1197 } 1198 pause() { 1199 if (!this.isReady) return; 1200 this.isVideoPlaying = false; 1201 this.playerObject.pauseVideo(); 1202 } 1203 mute() { 1204 this.playerObject.mute(); 1205 } 1206 setVideoProviderData() { 1207 var _this = this; 1208 return _asyncToGenerator(function* () { 1209 if (!_this.isReady) return; 1210 if (_this.currentVideoID && 11 === _this.currentVideoID.length) { 1211 _this.playlistItem.thumbnail = { url: "https://img.youtube.com/vi/" + _this.playerObject.getVideoData().video_id + "/maxresdefault.jpg" }; 1212 _this.playlistItem.video_title = _this.playerObject.getVideoData().title; 1213 _this.playlistItem.duration = _this.formatDuration(_this.playerObject.getDuration()); 1214 } else { 1215 _this.playlistItem.thumbnail = { url: "" }; 1216 _this.playlistItem.video_title = ""; 1217 _this.playlistItem.duration = ""; 1218 } 1219 })(); 1220 } 1221 }; 1222 })); 1223 //#endregion 1224 //#region modules/video-playlist/assets/js/frontend/player-vimeo.js 1225 var playerVimeo; 1226 var init_player_vimeo = __esmMin((() => { 1227 init_player_base(); 1228 init_asyncToGenerator(); 1229 playerVimeo = class extends PlayerBase { 1230 constructor(playlistItem, videoIndex) { 1231 super(playlistItem, videoIndex); 1232 this.apiProvider = elementorFrontend.utils.vimeo; 1233 this.playerObject = null; 1234 this.watchCount = 0; 1235 this.isVideoInFullScreenChange = false;
1236 this.isReady = false; 1237 } 1238 create() { 1239 this.currentVideoID = this.apiProvider.getVideoIDFromURL(this.playlistItem.videoUrl); 1240 return new Promise((resolve) => { 1241 this.apiProvider.onApiReady((apiObject) => { 1242 const playerOptions = { 1243 id: this.currentVideoID, 1244 autoplay: false 1245 }; 1246 this.playerObject = new apiObject.Player(this.playlistItem.tabContent.querySelector("div"), playerOptions); 1247 this.playerObject.ready().then(() => { 1248 this.isReady = true; 1249 resolve(); 1250 }); 1251 }); 1252 }); 1253 } 1254 handleEnded(callback) { 1255 this.playerObject.on("ended", () => { 1256 this.watchCount++; 1257 callback(this.playlistItem); 1258 }); 1259 } 1260 handlePaused(callback) { 1261 this.playerObject.on("pause", (event) => { 1262 if (0 === event.percent || event.percent >= 1 || this.isVideoInFullScreenChange) return; 1263 callback(this.positionInVideoList); 1264 }); 1265 } 1266 handlePlayed(callback) { 1267 this.playerObject.on("play", () => { 1268 if (this.isVideoInFullScreenChange) { 1269 this.isVideoInFullScreenChange = false; 1270 return; 1271 } 1272 callback(this.playlistItem); 1273 }); 1274 } 1275 handleFullScreenChange(callback) { 1276 this.playerObject.element.addEventListener("fullscreenchange", () => { 1277 callback(document.fullscreenElement); 1278 this.isVideoInFullScreenChange = true; 1279 }); 1280 } 1281 getCurrentTime() { 1282 return this.playerObject.getCurrentTime().then((seconds) => seconds); 1283 } 1284 play() { 1285 if (!this.isReady) return; 1286 this.playerObject.play(); 1287 } 1288 pause() { 1289 if (!this.isReady) return; 1290 this.playerObject.pause(); 1291 } 1292 mute() { 1293 this.playerObject.setMuted(true); 1294 } 1295 setVideoProviderData() { 1296 var _this = this; 1297 return _asyncToGenerator(function* () { 1298 if (!_this.currentVideoID && 9 === !_this.currentVideoID.length) return; 1299 const videoId = yield _this.playerObject.getVideoId(); 1300 const videoData = yield (yield fetch("https://vimeo.com/api/v2/video/" + videoId + ".json")).json(); 1301 _this.playlistItem.duration = _this.formatDuration(videoData[0].duration); 1302 _this.playlistItem.video_title = videoData[0].title; 1303 _this.playlistItem.thumbnail = { url: videoData[0].thumbnail_medium }; 1304 return _this.playlistItem; 1305 })(); 1306 } 1307 }; 1308 })); 1309 //#endregion 1310 //#region modules/video-playlist/assets/js/frontend/player-hosted.js 1311 var playerHosted; 1312 var init_player_hosted = __esmMin((() => { 1313 init_player_base(); 1314 playerHosted = class extends PlayerBase { 1315 constructor(playlistItem, videoIndex) { 1316 super(playlistItem, videoIndex); 1317 this.playerObject = null; 1318 this.watchCount = 0; 1319 this.isVideoPlaying = false; 1320 this.isVideoPausedLocal = false;
1321 this.isVideoSeeking = false; 1322 this.isVideoEnded = false; 1323 this.isReady = false; 1324 } 1325 create() { 1326 return new Promise((resolve) => { 1327 const video = document.createElement("video"); 1328 video.setAttribute("controls", ""); 1329 const text = document.createTextNode("Sorry, your browser doesn't support embedded videos."); 1330 const source = document.createElement("source"); 1331 source.setAttribute("src", this.playlistItem.videoUrl); 1332 source.setAttribute("type", "video/" + this.playlistItem.videoUrl.split(".").pop()); 1333 video.appendChild(source); 1334 video.appendChild(text); 1335 this.playerObject = video; 1336 this.playlistItem.tabContent.querySelector("div").replaceWith(this.playerObject); 1337 this.playerObject.addEventListener("canplay", () => { 1338 this.isReady = true; 1339 resolve(); 1340 }); 1341 this.playerObject.addEventListener("seeked", () => { 1342 this.isVideoSeeking = false; 1343 }); 1344 this.playerObject.addEventListener("seeking", () => { 1345 clearTimeout(this.seekTimeOut); 1346 this.isVideoSeeking = true; 1347 }); 1348 }); 1349 } 1350 handleEnded(callback) { 1351 this.playerObject.addEventListener("ended", () => { 1352 this.watchCount++; 1353 this.isVideoEnded = true; 1354 this.isVideoPlaying = false; 1355 callback(this.playlistItem); 1356 }); 1357 } 1358 handlePaused(callback) { 1359 this.playerObject.addEventListener("pause", () => { 1360 this.seekTimeOut = setTimeout(() => { 1361 if (!this.isVideoSeeking && !this.isVideoEnded) { 1362 callback(this.positionInVideoList); 1363 this.isVideoPausedLocal = true; 1364 } else this.isVideoEnded = false; 1365 }, 30); 1366 }); 1367 } 1368 handlePlayed(callback) { 1369 this.playerObject.addEventListener("play", () => { 1370 if (!this.isVideoSeeking) callback(this.playlistItem); 1371 }); 1372 } 1373 handleFullScreenChange(callback) { 1374 jQuery(this.playerObject).on("webkitfullscreenchange mozfullscreenchange fullscreenchange", () => { 1375 callback(document.fullscreenElement); 1376 }); 1377 } 1378 getCurrentTime() { 1379 return this.playerObject.currentTime; 1380 } 1381 play() { 1382 if (!this.isReady) return; 1383 this.isVideoPlaying = true; 1384 this.playerObject.play(); 1385 } 1386 pause() { 1387 if (!this.isReady) return; 1388 this.isVideoPlaying = false; 1389 this.playerObject.pause(); 1390 } 1391 mute() { 1392 this.playerObject.muted = true; 1393 } 1394 }; 1395 })); 1396 //#endregion 1397 //#region modules/video-playlist/assets/js/frontend/scroll-utils.js 1398 function handleVideosPanelScroll(elements, event) { 1399 if (!event) { 1400 if (elements.$tabsItems[0].offsetHeight < elements.$tabsItems[0].scrollHeight) elements.$tabsWrapper.addClass("bottom-shadow"); 1401 return; 1402 } 1403 if (event.target.scrollTop > 0) elements.$tabsWrapper.addClass("top-shadow"); 1404 else elements.$tabsWrapper.removeClass("top-shadow"); 1405 if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight) elements.$tabsWrapper.removeClass("bottom-shadow"); 1406 else elements.$tabsWrapper.addClass("bottom-shadow"); 1407 } 1408 var init_scroll_utils = __esmMin((() => {})); 1409 //#endregion 1410 //#region modules/video-playlist/assets/js/frontend/playlist-event.js 1411 var PlaylistEvent; 1412 var init_playlist_event = __esmMin((() => { 1413 PlaylistEvent = class { 1414 constructor({ event, tab, playlist, video }) { 1415 this.event = { 1416 type: event.type || "", 1417 time: event.time || 0, 1418 element: event.element, 1419 trigger: event.trigger || "", 1420 watchCount: event.watchCount || 0 1421 }; 1422 this.tab = { 1423 name: tab.name, 1424 index: tab.index 1425 }; 1426 this.playlist = { 1427 name: playlist.name, 1428 currentItem: playlist.currentItem, 1429 amount: playlist.amount 1430 }; 1431 this.video = { 1432 provider: video.provider, 1433 url: video.url, 1434 title: video.title, 1435 duration: video.duration 1436 }; 1437 } 1438 }; 1439 })); 1440 //#endregion 1441 //#region modules/video-playlist/assets/js/frontend/event-trigger.js 1442 function getEventTabsObject(widgetObject) { 1443 const currentInnerTabsTitleElements = widgetObject.elements.$innerTabs.filter(".e-active").find(".e-inner-tabs-wrapper .e-inner-tab-title"); 1444 if (currentInnerTabsTitleElements.length) { 1445 const activeInnerTabTitleElement = currentInnerTabsTitleElements.filter(".e-inner-tab-active"); 1446 return { 1447 name: activeInnerTabTitleElement.text().trim(), 1448 index: activeInnerTabTitleElement.index() + 1 1449 }; 1450 } 1451 return { 1452 name: "none", 1453 index: "none" 1454 }; 1455 }
1456 function getEventPlaylistObject(widgetObject, positionInVideoList) { 1457 const currentVideoIndex = positionInVideoList || widgetObject.currentPlaylistItemIndex; 1458 return { 1459 name: widgetObject.getElementSettings("playlist_title"), 1460 currentItem: currentVideoIndex, 1461 amount: widgetObject.playlistItemsArray.filter((video) => video.videoType !== "section").length 1462 }; 1463 } 1464 function getEventVideoObject(widgetObject, positionInVideoList) { 1465 const currentVideoIndex = positionInVideoList || widgetObject.currentPlaylistItemIndex; 1466 const currentVideo = widgetObject.playlistItemsArray[currentVideoIndex - 1]; 1467 return { 1468 provider: currentVideo.videoType, 1469 url: currentVideo.videoUrl, 1470 title: currentVideo.videoTitle, 1471 duration: currentVideo.videoDuration 1472 }; 1473 } 1474 function getEventEventObject(_x, _x2, _x3, _x4) { 1475 return _getEventEventObject.apply(this, arguments); 1476 } 1477 function _getEventEventObject() { 1478 _getEventEventObject = _asyncToGenerator(function* (widgetObject, eventType, eventTrigger, positionInVideoList) { 1479 const currentVideoIndex = positionInVideoList || widgetObject.currentPlaylistItemIndex; 1480 const currentVideo = widgetObject.playlistItemsArray[currentVideoIndex - 1]; 1481 return { 1482 type: eventType, 1483 time: yield currentVideo.playerInstance.getCurrentTime(), 1484 element: widgetObject.$element, 1485 trigger: eventTrigger, 1486 watchCount: currentVideo.playerInstance.watchCount 1487 }; 1488 }); 1489 return _getEventEventObject.apply(this, arguments); 1490 } 1491 function triggerEvent(_x5, _x6, _x7, _x8) { 1492 return _triggerEvent.apply(this, arguments); 1493 } 1494 function _triggerEvent() { 1495 _triggerEvent = _asyncToGenerator(function* (widgetObject, eventType, eventTrigger, positionInVideoList) { 1496 const currentEvent = new PlaylistEvent({ 1497 event: yield getEventEventObject(widgetObject, eventType, eventTrigger, positionInVideoList), 1498 tab: getEventTabsObject(widgetObject), 1499 playlist: getEventPlaylistObject(widgetObject, positionInVideoList), 1500 video: getEventVideoObject(widgetObject, positionInVideoList) 1501 }); 1502 jQuery("body").trigger("elementor-video-playList", currentEvent); 1503 }); 1504 return _triggerEvent.apply(this, arguments); 1505 } 1506 var init_event_trigger = __esmMin((() => { 1507 init_playlist_event(); 1508 init_asyncToGenerator(); 1509 })); 1510 //#endregion 1511 //#region modules/video-playlist/assets/js/frontend/inner-tabs.js 1512 function toggleInnerTabs(event, clickedTab, widgetObject) { 1513 const activeTabWrapper = event.currentTarget; 1514 const tabTitles = activeTabWrapper.querySelectorAll(".e-inner-tab-title"); 1515 if (clickedTab.hasClass("e-inner-tab-active") || tabTitles.length < 2) return; 1516 const tabsContents = activeTabWrapper.querySelectorAll(".e-inner-tab-content");
1517 tabTitles.forEach((tabTitle) => { 1518 tabTitle.classList.toggle("e-inner-tab-active"); 1519 }); 1520 tabsContents.forEach((tabContent) => { 1521 tabContent.toggleAttribute("hidden"); 1522 tabContent.classList.toggle("e-inner-tab-active"); 1523 }); 1524 handleInnerTabsButtonsDisplay(Array.from(tabsContents), widgetObject.isCollapsible, widgetObject.innerTabsHeightLimit); 1525 triggerEvent(widgetObject, "tabOpened", "click"); 1526 } 1527 function handleInnerTabs(event, widgetObject) { 1528 const clickedTarget = event.target; 1529 const clickedTagType = clickedTarget.tagName; 1530 if (clickedTarget.classList.contains("e-inner-tab-title-text")) { 1531 event.preventDefault(); 1532 toggleInnerTabs(event, jQuery(clickedTarget).parent(".e-inner-tab-title"), widgetObject); 1533 } 1534 if (clickedTarget.classList.contains("e-tab-mobile-title")) toggleInnerTabs(event, jQuery(clickedTarget), widgetObject); 1535 if ("button" === clickedTagType.toLowerCase()) onTabContentButtonsClick(event, widgetObject); 1536 } 1537 function handleInnerTabsButtonsDisplay(tabsContents, isCollapsible, innerTabsHeightLimit) { 1538 if (!isCollapsible) return; 1539 const activeInnerTab = tabsContents.filter((tabsContent) => tabsContent.classList.contains("e-inner-tab-active")); 1540 const innerTabScrollableHeight = activeInnerTab[0].querySelector(".e-inner-tab-text > div").offsetHeight; 1541 const innerTabsLimitHeight = parseInt(innerTabsHeightLimit.size); 1542 if (innerTabsLimitHeight && innerTabScrollableHeight > innerTabsLimitHeight) activeInnerTab[0].classList.add("show-inner-tab-buttons"); 1543 } 1544 function onTabContentButtonsClick(event, widgetObject) { 1545 const $activeTabContent = jQuery(event.currentTarget).find(".e-inner-tab-content").filter(".e-inner-tab-active"); 1546 $activeTabContent.find("button").toggleClass("show-button"); 1547 $activeTabContent.toggleClass("show-full-height"); 1548 triggerEvent(widgetObject, $activeTabContent.hasClass("show-full-height") ? "tabExpanded" : "tabCollapsed", "click"); 1549 } 1550 var init_inner_tabs = __esmMin((() => { 1551 init_event_trigger(); 1552 })); 1553 //#endregion 1554 //#region modules/video-playlist/assets/js/frontend/url-params.js 1555 function handleURLParams(playlistId, playlistItemsArray) { 1556 const params = new URLSearchParams(location.search); 1557 const playlistName = params.get("playlist");
1558 const defaultTabIndex = 1; 1559 if (!playlistName) return false; 1560 if (playlistName === playlistId) { 1561 const videoId = params.get("video"); 1562 const videoItem = playlistItemsArray.find((playlistItem) => videoId === playlistItem.dataItemId); 1563 const tabIndex = videoItem ? videoItem.dataTab : defaultTabIndex; 1564 if (!tabIndex) setVideoParams(playlistId, playlistItemsArray, defaultTabIndex); 1565 return tabIndex || false; 1566 } 1567 } 1568 function setVideoParams(playlistId, playlistItemsArray, videoId) { 1569 const params = new URLSearchParams(location.search); 1570 params.set("playlist", playlistId); 1571 params.set("video", playlistItemsArray[videoId - 1].dataItemId); 1572 history.replaceState({}, "", location.pathname + "?" + params); 1573 } 1574 var init_url_params = __esmMin((() => {})); 1575 //#endregion 1576 //#region modules/video-playlist/assets/js/frontend/handler.js 1577 var handler_exports = /* @__PURE__ */ __exportAll({ default: () => VideoPlaylistHandler }); 1578 var __defProp, __defProps, __getOwnPropDescs, __getOwnPropSymbols, __hasOwnProp, __propIsEnum, __defNormalProp, __spreadValues, __spreadProps, VideoPlaylistHandler; 1579 var init_handler = __esmMin((() => { 1580 init_base_tabs(); 1581 init_player_youtube(); 1582 init_player_vimeo(); 1583 init_player_hosted(); 1584 init_scroll_utils(); 1585 init_inner_tabs(); 1586 init_url_params(); 1587 init_event_trigger(); 1588 __defProp = Object.defineProperty; 1589 __defProps = Object.defineProperties; 1590 __getOwnPropDescs = Object.getOwnPropertyDescriptors; 1591 __getOwnPropSymbols = Object.getOwnPropertySymbols; 1592 __hasOwnProp = Object.prototype.hasOwnProperty; 1593 __propIsEnum = Object.prototype.propertyIsEnumerable; 1594 __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { 1595 enumerable: true, 1596 configurable: true, 1597 writable: true, 1598 value 1599 }) : obj[key] = value; 1600 __spreadValues = (a, b) => { 1601 for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); 1602 if (__getOwnPropSymbols) { 1603 for (var prop of __getOwnPropSymbols(b)) if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); 1604 } 1605 return a; 1606 }; 1607 __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); 1608 VideoPlaylistHandler = class extends baseTabs { 1609 getDefaultSettings() { 1610 const defaultSettings = super.getDefaultSettings(); 1611 return __spreadProps(__spreadValues({}, defaultSettings), { selectors: __spreadValues(__spreadValues({}, defaultSettings.selectors), { 1612 tabsWrapper: ".e-tabs-items-wrapper", 1613 tabsItems: ".e-tabs-items", 1614 toggleVideosDisplayButton: ".e-tabs-toggle-videos-display-button", 1615 videos: ".e-tabs-content-wrapper .e-tab-content", 1616 innerTabs: ".e-tabs-inner-tabs .e-tab-content", 1617 imageOverlay: ".elementor-custom-embed-image-overlay" 1618 }) }); 1619 } 1620 getDefaultElements() { 1621 const elements = super.getDefaultElements(); 1622 const selectors = this.getSettings("selectors"); 1623 return __spreadProps(__spreadValues({}, elements), { 1624 $tabsWrapper: this.findElement(selectors.tabsWrapper), 1625 $tabsItems: this.findElement(selectors.tabsItems), 1626 $toggleVideosDisplayButton: this.findElement(selectors.toggleVideosDisplayButton), 1627 $videos: this.findElement(selectors.videos), 1628 $innerTabs: this.findElement(selectors.innerTabs), 1629 $imageOverlay: this.findElement(selectors.imageOverlay) 1630 }); 1631 } 1632 initEditorListeners() { 1633 super.initEditorListeners(); 1634 this.editorListeners.push({ 1635 event: "elementorPlaylistWidget:fetchVideoData", 1636 to: elementor.channels.editor, 1637 callback: (e) => { 1638 this.getCurrentPlayerSelected().setVideoProviderData().then(() => { 1639 e.currentItem = this.getCurrentItemSelected(); 1640 elementor.channels.editor.trigger("elementorPlaylistWidget:setVideoData", e); 1641 }); 1642 } 1643 }); 1644 } 1645 bindEvents() { 1646 super.bindEvents(); 1647 this.elements.$imageOverlay.on({ click: (e) => { 1648 e.currentTarget.remove(); 1649 this.getCurrentPlayerSelected().play(); 1650 } }); 1651 this.elements.$innerTabs.on({ click: (event) => { 1652 handleInnerTabs(event, this); 1653 } }); 1654 this.elements.$tabsItems.on({ scroll: (event) => { 1655 handleVideosPanelScroll(this.elements, event); 1656 } }); 1657 this.elements.$toggleVideosDisplayButton.on({ click: (event) => { 1658 jQuery(event.target).toggleClass("rotate-up"); 1659 jQuery(event.target).toggleClass("rotate-down"); 1660 this.elements.$tabsWrapper.slideToggle("slow"); 1661 } }); 1662 } 1663 onInit(...args) { 1664 super.onInit(...args); 1665 this.playlistId = this.getID(); 1666 this.storageKey = "watched_videos_" + this.getID(); 1667 const storageObject = elementorFrontend.storage.get(this.storageKey); 1668 if (storageObject) this.watchedVideosArray = JSON.parse(storageObject); 1669 else this.watchedVideosArray = []; 1670 this.watchedIndication = this.getElementSettings("show_watched_indication"); 1671 handleVideosPanelScroll(this.elements); 1672 this.isAutoplayOnLoad = "yes" === this.getElementSettings("autoplay_on_load"); 1673 this.isAutoplayNextUp = "yes" === this.getElementSettings("autoplay_next"); 1674 this.isFirstVideoActivated = true; 1675 this.createPlaylistItems(); 1676 this.isCollapsible = this.getElementSettings("inner_tab_is_content_collapsible"); 1677 this.innerTabsHeightLimit = this.getElementSettings("inner_tab_collapsible_height"); 1678 this.currentPlayingPlaylistItemIndex = 1; 1679 this.activateInitialVideo(); 1680 this.activateInnerTabInEditMode(); 1681 } 1682 onEditSettingsChange(propertyName) { 1683 if ("panel" === propertyName) this.preventTabActivation = true; 1684 if ("activeItemIndex" !== propertyName) return; 1685 if (this.preventTabActivation) { 1686 this.preventTabActivation = false;
1687 return; 1688 } 1689 this.activateDefaultTab(); 1690 } 1691 activateInitialVideo() { 1692 var _a; 1693 this.isPageOnLoad = true; 1694 const isLazyLoad = !!this.getElementSettings("lazy_load"); 1695 const initialTabIndex = handleURLParams(this.playlistId, this.playlistItemsArray); 1696 let isUrlParamsExist = false; 1697 if (initialTabIndex) { 1698 this.currentPlaylistItemIndex = initialTabIndex; 1699 this.currentPlayingPlaylistItemIndex = initialTabIndex; 1700 isUrlParamsExist = true; 1701 } else { 1702 this.currentPlaylistItemIndex = 1; 1703 this.currentPlayingPlaylistItemIndex = 1; 1704 } 1705 if (this.isAutoplayOnLoad && !isUrlParamsExist) setVideoParams(this.playlistId, this.playlistItemsArray, this.currentPlaylistItemIndex); 1706 if (isUrlParamsExist) (_a = this.$element[0]) == null || _a.scrollIntoView({ behavior: "smooth" }); 1707 this.handleFirstVideoActivation(isLazyLoad); 1708 } 1709 handleFirstVideoActivation(isLazyLoad) { 1710 if (!isLazyLoad) { 1711 this.activateDefaultTab(this.currentPlaylistItemIndex); 1712 return; 1713 } 1714 const playlistElement = document.querySelector(".elementor-element-" + this.playlistId + " .e-tabs-main-area"); 1715 const observer = elementorModules.utils.Scroll.scrollObserver({ callback: (event) => { 1716 if (event.isInViewport) { 1717 this.activateDefaultTab(this.currentPlaylistItemIndex); 1718 observer.unobserve(playlistElement); 1719 } 1720 } }); 1721 observer.observe(playlistElement); 1722 } 1723 getCurrentItemSelected() { 1724 return this.playlistItemsArray[this.currentPlaylistItemIndex - 1]; 1725 } 1726 getCurrentPlayerSelected() { 1727 return this.getCurrentItemSelected().playerInstance; 1728 } 1729 getCurrentPlayerPlaying() { 1730 return this.playlistItemsArray[this.currentPlayingPlaylistItemIndex - 1].playerInstance; 1731 } 1732 isVideoShouldBePlayed() { 1733 if (this.currentPlayingPlaylistItemIndex !== this.currentPlaylistItemIndex) { 1734 if (this.getCurrentPlayerPlaying()) this.getCurrentPlayerPlaying().pause(); 1735 this.currentPlayingPlaylistItemIndex = this.currentPlaylistItemIndex; 1736 } else if (this.getCurrentPlayerPlaying().isVideoPlaying) { 1737 this.getCurrentPlayerPlaying().pause(); 1738 return false; 1739 } 1740 return true; 1741 } 1742 activateInnerTabInEditMode() { 1743 if (this.isEdit && this.getEditSettings("innerActiveIndex")) { 1744 const innerTabActivated = this.getEditSettings("innerActiveIndex"); 1745 jQuery(this.elements.$innerTabs.eq(this.currentPlaylistItemIndex - 1).find(".e-inner-tab-title a"))[innerTabActivated].click(); 1746 } 1747 } 1748 handleVideo(playListItem) { 1749 if (playListItem.playerInstance) { 1750 if (this.isVideoShouldBePlayed()) { 1751 if (1 === this.currentPlaylistItemIndex && this.elements.$imageOverlay) this.elements.$imageOverlay.remove(); 1752 this.playVideoAfterCreation(playListItem); 1753 } 1754 } else { 1755 playListItem.playerInstance = new { 1756 youtube: playerYoutube, 1757 vimeo: playerVimeo, 1758 hosted: playerHosted 1759 }[playListItem.videoType](playListItem, this.currentPlaylistItemIndex); 1760 playListItem.playerInstance.create().then(() => { 1761 if (this.isVideoShouldBePlayed()) this.playVideoOnCreation(playListItem); 1762 playListItem.playerInstance.handleFullScreenChange((isEnterFullScreenMode) => { 1763 triggerEvent(this, isEnterFullScreenMode ? "videoFullScreen" : "videoExitFullScreen", "click"); 1764 }); 1765 playListItem.playerInstance.handlePlayed(() => { 1766 const currentPlaylistItem = this.getCurrentItemSelected(); 1767 let videoTrigger = "click"; 1768 if (currentPlaylistItem.isAutoplayOnLoad) { 1769 videoTrigger = "onLoad"; 1770 playListItem.isAutoplayOnLoad = false; 1771 } else if (currentPlaylistItem.isAutoPlayNextUp) videoTrigger = "nextVideo"; 1772 triggerEvent(this, currentPlaylistItem.playerInstance.isVideoPausedLocal ? "videoResume" : "videoStart", videoTrigger); 1773 }); 1774 playListItem.playerInstance.handleEnded(() => { 1775 triggerEvent(this, "videoEnded", "click"); 1776 if (this.watchedIndication) this.elements.$tabTitles.filter(".e-active").addClass("watched-video"); 1777 const endedVideoId = this.getCurrentItemSelected().dataItemId; 1778 if (!this.watchedVideosArray.includes(endedVideoId) && this.watchedIndication) { 1779 this.watchedVideosArray.push(this.getCurrentItemSelected().dataItemId); 1780 elementorFrontend.storage.set(this.storageKey, JSON.stringify(this.watchedVideosArray)); 1781 } 1782 if (this.isAutoplayNextUp) { 1783 if (this.playlistItemsArray.length >= ++this.currentPlaylistItemIndex) { 1784 while ("section" === this.getCurrentItemSelected().videoType) { 1785 this.currentPlaylistItemIndex++; 1786 if (this.playlistItemsArray.length < this.currentPlaylistItemIndex) { 1787 this.currentPlaylistItemIndex = this.playlistItemsArray.length; 1788 return; 1789 } 1790 } 1791 this.changeActiveTab(this.currentPlaylistItemIndex, true); 1792 } 1793 } 1794 }); 1795 playListItem.playerInstance.handlePaused((positionInVideoList) => { 1796 triggerEvent(this, "videoPaused", "click", positionInVideoList); 1797 }); 1798 }); 1799 } 1800 } 1801 playVideoAfterCreation(playListItem) { 1802 playListItem.playerInstance.play(); 1803 } 1804 playVideoOnCreation(playListItem) { 1805 if (this.isAutoplayOnLoad) { 1806 playListItem.isAutoplayOnLoad = true; 1807 playListItem.playerInstance.mute(); 1808 playListItem.playerInstance.play(); 1809 this.isAutoplayOnLoad = false;
1810 } else if (!this.isFirstVideoActivated) { 1811 playListItem.isAutoPlayNextUp = true; 1812 playListItem.playerInstance.play(); 1813 } 1814 this.isFirstVideoActivated = false; 1815 } 1816 createPlaylistItems() { 1817 this.playlistItemsArray = []; 1818 this.elements.$videos.each((index, tabContent) => { 1819 const playListItem = {}; 1820 const $tabContent = jQuery(tabContent); 1821 playListItem.videoUrl = $tabContent.attr("data-video-url"); 1822 playListItem.videoType = $tabContent.attr("data-video-type"); 1823 playListItem.videoTitle = $tabContent.attr("data-video-title"); 1824 playListItem.videoDuration = $tabContent.attr("data-video-duration"); 1825 playListItem.tabContent = tabContent; 1826 playListItem.dataTab = index + 1; 1827 playListItem.dataItemId = this.getElementSettings().tabs[index]._id; 1828 this.playlistItemsArray.push(playListItem); 1829 }); 1830 if (this.watchedVideosArray.length > 0 && this.watchedIndication) this.watchedVideosArray.forEach((watchedVideoId) => { 1831 const watchedPlaylistItem = this.playlistItemsArray.find((playlistItem) => playlistItem.dataItemId === watchedVideoId); 1832 this.elements.$tabTitles.filter("[data-tab=\"" + watchedPlaylistItem.dataTab + "\"]").addClass("watched-video"); 1833 }); 1834 } 1835 changeActiveTab(tabIndex, isVideoSelectedAutomatically) { 1836 super.changeActiveTab(tabIndex); 1837 if (this.playlistItemsArray[tabIndex - 1] && this.playlistItemsArray[tabIndex - 1].videoType !== "section") { 1838 this.currentPlaylistItemIndex = parseInt(tabIndex); 1839 if (isVideoSelectedAutomatically) this.currentPlayingPlaylistItemIndex = this.currentPlaylistItemIndex; 1840 this.handleVideo(this.getCurrentItemSelected(), isVideoSelectedAutomatically); 1841 if (!this.isPageOnLoad) setVideoParams(this.playlistId, this.playlistItemsArray, this.currentPlaylistItemIndex); 1842 this.isPageOnLoad = false; 1843 if (jQuery(this.elements.$innerTabs.eq(tabIndex - 1)).find(".e-inner-tab-content").length > 0) handleInnerTabsButtonsDisplay(this.elements.$innerTabs.filter(".e-active").find(".e-inner-tab-content").toArray(), this.isCollapsible, this.innerTabsHeightLimit); 1844 } 1845 } 1846 }; 1847 })); 1848 //#endregion 1849 //#region modules/video-playlist/assets/js/frontend/frontend.js 1850 init_asyncToGenerator(); 1851 var frontend_default$2 = class extends elementorModules.Module { 1852 static { 1853 __name(this, "default"); 1854 } 1855 constructor() { 1856 super(); 1857 elementorFrontend.hooks.addAction("frontend/element_ready/video-playlist.default", ($element) => { 1858 __vitePreload(_asyncToGenerator(function* () { 1859 const { default: dynamicHandler } = yield Promise.resolve().then(() => (init_handler(), handler_exports)); 1860 return { default: dynamicHandler }; 1861 }), void 0).then(({ default: dynamicHandler }) => { 1862 elementorFrontend.elementsHandler.addHandler(dynamicHandler, { 1863 $element, 1864 toggleSelf: false 1865 }); 1866 }); 1867 }); 1868 } 1869 }; 1870 //#endregion 1871 //#region modules/payments/assets/js/frontend/handlers/paypal-button.js 1872 var paypal_button_exports = /* @__PURE__ */ __exportAll({ default: () => PayPalHandler }); 1873 var PayPalHandler; 1874 var init_paypal_button = __esmMin((() => { 1875 PayPalHandler = class extends elementorModules.frontend.handlers.Base { 1876 getDefaultSettings() { 1877 return { selectors: { 1878 button: ".elementor-button.elementor-paypal-legacy", 1879 errors: ".elementor-message-danger" 1880 } }; 1881 } 1882 getDefaultElements() { 1883 const settings = this.getSettings(); 1884 return { 1885 wrapper: this.$element[0], 1886 button: this.$element[0].querySelector(settings.selectors.button), 1887 errors: this.$element[0].querySelectorAll(settings.selectors.errors) 1888 }; 1889 } 1890 handleClick(event) { 1891 if (0 < this.elements.errors.length) { 1892 event.preventDefault(); 1893 this.elements.errors.forEach((error) => { 1894 error.classList.remove("elementor-hidden"); 1895 }); 1896 } 1897 } 1898 bindEvents() { 1899 this.elements.button.addEventListener("click", this.handleClick.bind(this)); 1900 } 1901 }; 1902 })); 1903 //#endregion 1904 //#region node_modules/dompurify/dist/purify.es.mjs 1905 /*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */ 1906 function _arrayLikeToArray(r, a) { 1907 (null == a || a > r.length) && (a = r.length); 1908 for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; 1909 return n; 1910 } 1911 function _arrayWithHoles(r) { 1912 if (Array.isArray(r)) return r; 1913 } 1914 function _iterableToArrayLimit(r, l) { 1915 var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; 1916 if (null != t) { 1917 var e; 1918 var n; 1919 var i; 1920 var u; 1921 var a = []; 1922 var f = true; 1923 var o = false;
vendor: 9,644 bytes, lines 1924-2165
1924 try { 1925 if (i = (t = t.call(r)).next, 0 === l); 1926 else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); 1927 } catch (r) { 1928 o = true, n = r; 1929 } finally { 1930 try { 1931 if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; 1932 } finally { 1933 if (o) throw n; 1934 } 1935 } 1936 return a; 1937 } 1938 } 1939 function _nonIterableRest() { 1940 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 1941 } 1942 function _slicedToArray(r, e) { 1943 return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); 1944 } 1945 function _unsupportedIterableToArray(r, a) { 1946 if (r) { 1947 if ("string" == typeof r) return _arrayLikeToArray(r, a); 1948 var t = {}.toString.call(r).slice(8, -1); 1949 return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; 1950 } 1951 } 1952 /** 1953 * Creates a new function that calls the given function with a specified thisArg and arguments. 1954 * 1955 * @param func - The function to be wrapped and called. 1956 * @returns A new function that calls the given function with a specified thisArg and arguments. 1957 */ 1958 function unapply(func) { 1959 return function(thisArg) { 1960 if (thisArg instanceof RegExp) thisArg.lastIndex = 0; 1961 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) args[_key3 - 1] = arguments[_key3]; 1962 return apply(func, thisArg, args); 1963 }; 1964 } 1965 /** 1966 * Creates a new function that constructs an instance of the given constructor function with the provided arguments. 1967 * 1968 * @param func - The constructor function to be wrapped and called. 1969 * @returns A new function that constructs an instance of the given constructor function with the provided arguments. 1970 */ 1971 function unconstruct(Func) { 1972 return function() { 1973 for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) args[_key4] = arguments[_key4]; 1974 return construct(Func, args); 1975 }; 1976 } 1977 /** 1978 * Add properties to a lookup table 1979 * 1980 * @param set - The set to which elements will be added. 1981 * @param array - The array containing elements to be added to the set. 1982 * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set. 1983 * @returns The modified set with added elements. 1984 */ 1985 function addToSet(set, array) { 1986 let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase; 1987 if (setPrototypeOf) setPrototypeOf(set, null); 1988 if (!arrayIsArray(array)) return set; 1989 let l = array.length; 1990 while (l--) { 1991 let element = array[l]; 1992 if (typeof element === "string") { 1993 const lcElement = transformCaseFunc(element); 1994 if (lcElement !== element) { 1995 if (!isFrozen(array)) array[l] = lcElement; 1996 element = lcElement; 1997 } 1998 } 1999 set[element] = true; 2000 } 2001 return set; 2002 } 2003 /** 2004 * Clean up an array to harden against CSPP 2005 * 2006 * @param array - The array to be cleaned. 2007 * @returns The cleaned version of the array 2008 */ 2009 function cleanArray(array) { 2010 for (let index = 0; index < array.length; index++) if (!objectHasOwnProperty(array, index)) array[index] = null; 2011 return array; 2012 } 2013 /** 2014 * Shallow clone an object 2015 * 2016 * @param object - The object to be cloned. 2017 * @returns A new object that copies the original. 2018 */ 2019 function clone(object) { 2020 const newObject = create(null); 2021 for (const _ref2 of entries(object)) { 2022 var _ref3 = _slicedToArray(_ref2, 2); 2023 const property = _ref3[0]; 2024 const value = _ref3[1]; 2025 if (objectHasOwnProperty(object, property)) if (arrayIsArray(value)) newObject[property] = cleanArray(value); 2026 else if (value && typeof value === "object" && value.constructor === Object) newObject[property] = clone(value); 2027 else newObject[property] = value; 2028 } 2029 return newObject; 2030 } 2031 /** 2032 * Convert non-node values into strings without depending on direct property access. 2033 * 2034 * @param value - The value to stringify. 2035 * @returns A string representation of the provided value. 2036 */ 2037 function stringifyValue(value) { 2038 switch (typeof value) { 2039 case "string": return value; 2040 case "number": return numberToString(value); 2041 case "boolean": return booleanToString(value); 2042 case "bigint": return bigintToString ? bigintToString(value) : "0"; 2043 case "symbol": return symbolToString ? symbolToString(value) : "Symbol()"; 2044 case "undefined": return objectToString(value); 2045 case "function": 2046 case "object": { 2047 if (value === null) return objectToString(value); 2048 const valueAsRecord = value; 2049 const valueToString = lookupGetter(valueAsRecord, "toString"); 2050 if (typeof valueToString === "function") { 2051 const stringified = valueToString(valueAsRecord); 2052 return typeof stringified === "string" ? stringified : objectToString(stringified); 2053 } 2054 return objectToString(value); 2055 } 2056 default: return objectToString(value); 2057 } 2058 } 2059 /** 2060 * This method automatically checks if the prop is function or getter and behaves accordingly. 2061 * 2062 * @param object - The object to look up the getter function in its prototype chain. 2063 * @param prop - The property name for which to find the getter function. 2064 * @returns The getter function found in the prototype chain or a fallback function. 2065 */ 2066 function lookupGetter(object, prop) { 2067 while (object !== null) { 2068 const desc = getOwnPropertyDescriptor(object, prop); 2069 if (desc) { 2070 if (desc.get) return unapply(desc.get); 2071 if (typeof desc.value === "function") return unapply(desc.value); 2072 } 2073 object = getPrototypeOf(object); 2074 } 2075 function fallbackValue() { 2076 return null; 2077 } 2078 return fallbackValue; 2079 } 2080 function isRegex(value) { 2081 try { 2082 regExpTest(value, ""); 2083 return true; 2084 } catch (_unused) { 2085 return false; 2086 } 2087 } 2088 function createDOMPurify() { 2089 let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); 2090 const DOMPurify = (root) => createDOMPurify(root); 2091 DOMPurify.version = "3.4.11"; 2092 DOMPurify.removed = []; 2093 if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) { 2094 DOMPurify.isSupported = false; 2095 return DOMPurify; 2096 } 2097 let document = window.document; 2098 const originalDocument = document; 2099 const currentScript = originalDocument.currentScript; 2100 window.DocumentFragment; 2101 const HTMLTemplateElement = window.HTMLTemplateElement; 2102 const Node = window.Node; 2103 const Element = window.Element; 2104 const NodeFilter = window.NodeFilter; 2105 window.NamedNodeMap === void 0 && (window.NamedNodeMap || window.MozNamedAttrMap); 2106 window.HTMLFormElement; 2107 const DOMParser = window.DOMParser; 2108 const trustedTypes = window.trustedTypes; 2109 const ElementPrototype = Element.prototype; 2110 const cloneNode = lookupGetter(ElementPrototype, "cloneNode"); 2111 const remove = lookupGetter(ElementPrototype, "remove"); 2112 const getNextSibling = lookupGetter(ElementPrototype, "nextSibling"); 2113 const getChildNodes = lookupGetter(ElementPrototype, "childNodes"); 2114 const getParentNode = lookupGetter(ElementPrototype, "parentNode"); 2115 const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot"); 2116 const getAttributes = lookupGetter(ElementPrototype, "attributes"); 2117 const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null; 2118 const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null; 2119 if (typeof HTMLTemplateElement === "function") { 2120 const template = document.createElement("template"); 2121 if (template.content && template.content.ownerDocument) document = template.content.ownerDocument; 2122 } 2123 let trustedTypesPolicy; 2124 let emptyHTML = ""; 2125 let defaultTrustedTypesPolicy; 2126 let defaultTrustedTypesPolicyResolved = false; 2127 let IN_TRUSTED_TYPES_POLICY = 0; 2128 const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() { 2129 if (IN_TRUSTED_TYPES_POLICY > 0) throw typeErrorCreate("A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted Types\" section of the README."); 2130 }; 2131 const _createTrustedHTML = function _createTrustedHTML(html) { 2132 _assertNotInTrustedTypesPolicy(); 2133 IN_TRUSTED_TYPES_POLICY++; 2134 try { 2135 return trustedTypesPolicy.createHTML(html); 2136 } finally { 2137 IN_TRUSTED_TYPES_POLICY--; 2138 } 2139 }; 2140 const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) { 2141 _assertNotInTrustedTypesPolicy(); 2142 IN_TRUSTED_TYPES_POLICY++; 2143 try { 2144 return trustedTypesPolicy.createScriptURL(scriptUrl); 2145 } finally { 2146 IN_TRUSTED_TYPES_POLICY--; 2147 } 2148 }; 2149 const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() { 2150 if (!defaultTrustedTypesPolicyResolved) { 2151 defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); 2152 defaultTrustedTypesPolicyResolved = true; 2153 } 2154 return defaultTrustedTypesPolicy; 2155 }; 2156 const _document = document; 2157 const implementation = _document.implementation; 2158 const createNodeIterator = _document.createNodeIterator; 2159 const createDocumentFragment = _document.createDocumentFragment; 2160 const getElementsByTagName = _document.getElementsByTagName; 2161 const importNode = originalDocument.importNode; 2162 let hooks = _createHooksMap(); 2163 /** 2164 * Expose whether this browser supports running the full DOMPurify. 2165 */
2166 DOMPurify.isSupported = typeof entries === "function" && typeof getParentNode === "function" && implementation && implementation.createHTMLDocument !== void 0; 2167 const MUSTACHE_EXPR$1 = MUSTACHE_EXPR; 2168 const ERB_EXPR$1 = ERB_EXPR; 2169 const TMPLIT_EXPR$1 = TMPLIT_EXPR; 2170 const DATA_ATTR$1 = DATA_ATTR; 2171 const ARIA_ATTR$1 = ARIA_ATTR; 2172 const IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA; 2173 const ATTR_WHITESPACE$1 = ATTR_WHITESPACE; 2174 const
vendor: 6,772 bytes, lines 2174-2387
2174 CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT; 2175 let IS_ALLOWED_URI$1 = IS_ALLOWED_URI; 2176 /** 2177 * We consider the elements and attributes below to be safe. Ideally 2178 * don't add any new ones but feel free to remove unwanted ones. 2179 */ 2180 let ALLOWED_TAGS = null; 2181 const DEFAULT_ALLOWED_TAGS = addToSet({}, [ 2182 ...html$1, 2183 ...svg$1, 2184 ...svgFilters, 2185 ...mathMl$1, 2186 ...text 2187 ]); 2188 let ALLOWED_ATTR = null; 2189 const DEFAULT_ALLOWED_ATTR = addToSet({}, [ 2190 ...html, 2191 ...svg, 2192 ...mathMl, 2193 ...xml 2194 ]); 2195 let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { 2196 tagNameCheck: { 2197 writable: true, 2198 configurable: false, 2199 enumerable: true, 2200 value: null 2201 }, 2202 attributeNameCheck: { 2203 writable: true, 2204 configurable: false, 2205 enumerable: true, 2206 value: null 2207 }, 2208 allowCustomizedBuiltInElements: { 2209 writable: true, 2210 configurable: false, 2211 enumerable: true, 2212 value: false 2213 } 2214 })); 2215 let FORBID_TAGS = null; 2216 let FORBID_ATTR = null; 2217 const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, { 2218 tagCheck: { 2219 writable: true, 2220 configurable: false, 2221 enumerable: true, 2222 value: null 2223 }, 2224 attributeCheck: { 2225 writable: true, 2226 configurable: false, 2227 enumerable: true, 2228 value: null 2229 } 2230 })); 2231 let ALLOW_ARIA_ATTR = true; 2232 let ALLOW_DATA_ATTR = true; 2233 let ALLOW_UNKNOWN_PROTOCOLS = false; 2234 let ALLOW_SELF_CLOSE_IN_ATTR = true; 2235 let SAFE_FOR_TEMPLATES = false; 2236 let SAFE_FOR_XML = true; 2237 let WHOLE_DOCUMENT = false; 2238 let SET_CONFIG = false; 2239 let SET_CONFIG_ALLOWED_TAGS = null; 2240 let SET_CONFIG_ALLOWED_ATTR = null; 2241 let FORCE_BODY = false; 2242 let RETURN_DOM = false; 2243 let RETURN_DOM_FRAGMENT = false; 2244 let RETURN_TRUSTED_TYPE = false; 2245 let SANITIZE_DOM = true; 2246 let SANITIZE_NAMED_PROPS = false; 2247 const SANITIZE_NAMED_PROPS_PREFIX = "user-content-"; 2248 let KEEP_CONTENT = true; 2249 let IN_PLACE = false; 2250 let USE_PROFILES = {}; 2251 let FORBID_CONTENTS = null; 2252 const DEFAULT_FORBID_CONTENTS = addToSet({}, [ 2253 "annotation-xml", 2254 "audio", 2255 "colgroup", 2256 "desc", 2257 "foreignobject", 2258 "head", 2259 "iframe", 2260 "math", 2261 "mi", 2262 "mn", 2263 "mo", 2264 "ms", 2265 "mtext", 2266 "noembed", 2267 "noframes", 2268 "noscript", 2269 "plaintext", 2270 "script", 2271 "selectedcontent", 2272 "style", 2273 "svg", 2274 "template", 2275 "thead", 2276 "title", 2277 "video", 2278 "xmp" 2279 ]); 2280 let DATA_URI_TAGS = null; 2281 const DEFAULT_DATA_URI_TAGS = addToSet({}, [ 2282 "audio", 2283 "video", 2284 "img", 2285 "source", 2286 "image", 2287 "track" 2288 ]); 2289 let URI_SAFE_ATTRIBUTES = null; 2290 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [ 2291 "alt", 2292 "class", 2293 "for", 2294 "id", 2295 "label", 2296 "name", 2297 "pattern", 2298 "placeholder", 2299 "role", 2300 "summary", 2301 "title", 2302 "value", 2303 "style", 2304 "xmlns" 2305 ]); 2306 const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; 2307 const SVG_NAMESPACE = "http://www.w3.org/2000/svg"; 2308 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; 2309 let NAMESPACE = HTML_NAMESPACE; 2310 let IS_EMPTY_INPUT = false; 2311 let ALLOWED_NAMESPACES = null; 2312 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [ 2313 MATHML_NAMESPACE, 2314 SVG_NAMESPACE, 2315 HTML_NAMESPACE 2316 ], stringToString); 2317 const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze([ 2318 "mi", 2319 "mo", 2320 "mn", 2321 "ms", 2322 "mtext" 2323 ]); 2324 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 2325 const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]); 2326 let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 2327 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [ 2328 "title", 2329 "style", 2330 "font", 2331 "a", 2332 "script" 2333 ]); 2334 let PARSER_MEDIA_TYPE = null; 2335 const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"]; 2336 const DEFAULT_PARSER_MEDIA_TYPE = "text/html"; 2337 let transformCaseFunc = null; 2338 let CONFIG = null; 2339 const formElement = document.createElement("form"); 2340 const isRegexOrFunction = function isRegexOrFunction(testValue) { 2341 return testValue instanceof RegExp || testValue instanceof Function; 2342 }; 2343 /** 2344 * _parseConfig 2345 * 2346 * @param cfg optional config literal 2347 */ 2348 const _parseConfig = function _parseConfig() { 2349 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 2350 if (CONFIG && CONFIG === cfg) return; 2351 if (!cfg || typeof cfg !== "object") cfg = {}; 2352 cfg = clone(cfg); 2353 PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; 2354 transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase; 2355 ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, { transform: transformCaseFunc }); 2356 ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, { transform: transformCaseFunc }); 2357 ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, { transform: stringToString }); 2358 URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, { 2359 transform: transformCaseFunc, 2360 base: DEFAULT_URI_SAFE_ATTRIBUTES 2361 }); 2362 DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, { 2363 transform: transformCaseFunc, 2364 base: DEFAULT_DATA_URI_TAGS 2365 }); 2366 FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, { transform: transformCaseFunc }); 2367 FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), { transform: transformCaseFunc }); 2368 FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), { transform: transformCaseFunc }); 2369 USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false; 2370 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; 2371 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; 2372 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; 2373 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; 2374 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; 2375 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; 2376 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; 2377 RETURN_DOM = cfg.RETURN_DOM || false; 2378 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; 2379 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; 2380 FORCE_BODY = cfg.FORCE_BODY || false; 2381 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; 2382 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; 2383 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; 2384 IN_PLACE = cfg.IN_PLACE || false; 2385 IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; 2386 NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE; 2387 MATHML_TEXT_INTEGRATION_POINTS =
vendor: 7,021 bytes, lines 2387-2517
2387objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 2388 HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 2389 const customElementHandling = objectHasOwnProperty(cfg, "CUSTOM_ELEMENT_HANDLING") && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === "object" ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null); 2390 CUSTOM_ELEMENT_HANDLING = create(null); 2391 if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; 2392 if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; 2393 if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; 2394 seal(CUSTOM_ELEMENT_HANDLING); 2395 if (SAFE_FOR_TEMPLATES) ALLOW_DATA_ATTR = false; 2396 if (RETURN_DOM_FRAGMENT) RETURN_DOM = true; 2397 if (USE_PROFILES) { 2398 ALLOWED_TAGS = addToSet({}, text); 2399 ALLOWED_ATTR = create(null); 2400 if (USE_PROFILES.html === true) { 2401 addToSet(ALLOWED_TAGS, html$1); 2402 addToSet(ALLOWED_ATTR, html); 2403 } 2404 if (USE_PROFILES.svg === true) { 2405 addToSet(ALLOWED_TAGS, svg$1); 2406 addToSet(ALLOWED_ATTR, svg); 2407 addToSet(ALLOWED_ATTR, xml); 2408 } 2409 if (USE_PROFILES.svgFilters === true) { 2410 addToSet(ALLOWED_TAGS, svgFilters); 2411 addToSet(ALLOWED_ATTR, svg); 2412 addToSet(ALLOWED_ATTR, xml); 2413 } 2414 if (USE_PROFILES.mathMl === true) { 2415 addToSet(ALLOWED_TAGS, mathMl$1); 2416 addToSet(ALLOWED_ATTR, mathMl); 2417 addToSet(ALLOWED_ATTR, xml); 2418 } 2419 } 2420 EXTRA_ELEMENT_HANDLING.tagCheck = null; 2421 EXTRA_ELEMENT_HANDLING.attributeCheck = null; 2422 if (objectHasOwnProperty(cfg, "ADD_TAGS")) { 2423 if (typeof cfg.ADD_TAGS === "function") EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS; 2424 else if (arrayIsArray(cfg.ADD_TAGS)) { 2425 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) ALLOWED_TAGS = clone(ALLOWED_TAGS); 2426 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); 2427 } 2428 } 2429 if (objectHasOwnProperty(cfg, "ADD_ATTR")) { 2430 if (typeof cfg.ADD_ATTR === "function") EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR; 2431 else if (arrayIsArray(cfg.ADD_ATTR)) { 2432 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) ALLOWED_ATTR = clone(ALLOWED_ATTR); 2433 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); 2434 } 2435 } 2436 if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); 2437 if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) { 2438 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS); 2439 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); 2440 } 2441 if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) { 2442 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS); 2443 addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc); 2444 } 2445 if (KEEP_CONTENT) ALLOWED_TAGS["#text"] = true; 2446 if (WHOLE_DOCUMENT) addToSet(ALLOWED_TAGS, [ 2447 "html", 2448 "head", 2449 "body" 2450 ]); 2451 if (ALLOWED_TAGS.table) { 2452 addToSet(ALLOWED_TAGS, ["tbody"]); 2453 delete FORBID_TAGS.tbody; 2454 } 2455 if (cfg.TRUSTED_TYPES_POLICY) { 2456 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook."); 2457 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook."); 2458 const previousTrustedTypesPolicy = trustedTypesPolicy; 2459 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; 2460 try { 2461 emptyHTML = _createTrustedHTML(""); 2462 } catch (error) { 2463 trustedTypesPolicy = previousTrustedTypesPolicy; 2464 throw error; 2465 } 2466 } else if (cfg.TRUSTED_TYPES_POLICY === null) { 2467 trustedTypesPolicy = void 0; 2468 emptyHTML = ""; 2469 } else { 2470 if (trustedTypesPolicy === void 0) trustedTypesPolicy = _getDefaultTrustedTypesPolicy(); 2471 if (trustedTypesPolicy && typeof emptyHTML === "string") emptyHTML = _createTrustedHTML(""); 2472 } 2473 if (freeze) freeze(cfg); 2474 CONFIG = cfg; 2475 }; 2476 const ALL_SVG_TAGS = addToSet({}, [ 2477 ...svg$1, 2478 ...svgFilters, 2479 ...svgDisallowed 2480 ]); 2481 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); 2482 /** 2483 * Namespace rules for an element in the SVG namespace. 2484 * 2485 * @param tagName the element's lowercase tag name 2486 * @param parent the (possibly simulated) parent node 2487 * @param parentTagName the parent's lowercase tag name 2488 * @returns true if a spec-compliant parser could produce this element 2489 */ 2490 const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) { 2491 if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "svg"; 2492 if (parent.namespaceURI === MATHML_NAMESPACE) return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); 2493 return Boolean(ALL_SVG_TAGS[tagName]); 2494 }; 2495 /** 2496 * Namespace rules for an element in the MathML namespace. 2497 * 2498 * @param tagName the element's lowercase tag name 2499 * @param parent the (possibly simulated) parent node 2500 * @param parentTagName the parent's lowercase tag name 2501 * @returns true if a spec-compliant parser could produce this element 2502 */ 2503 const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) { 2504 if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "math"; 2505 if (parent.namespaceURI === SVG_NAMESPACE) return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName]; 2506 return Boolean(ALL_MATHML_TAGS[tagName]); 2507 }; 2508 /** 2509 * Namespace rules for an element in the HTML namespace. 2510 * 2511 * @param tagName the element's lowercase tag name 2512 * @param parent the (possibly simulated) parent node 2513 * @param parentTagName the parent's lowercase tag name 2514 * @returns true if a spec-compliant parser could produce this element 2515 */ 2516 const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) { 2517 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) return false;
vendor: 4,228 bytes, lines 2518-2629
2518 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) return false; 2519 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); 2520 }; 2521 /** 2522 * @param element a DOM element whose namespace is being checked 2523 * @returns Return false if the element has a 2524 * namespace that a spec-compliant parser would never 2525 * return. Return true otherwise. 2526 */ 2527 const _checkValidNamespace = function _checkValidNamespace(element) { 2528 let parent = getParentNode(element); 2529 if (!parent || !parent.tagName) parent = { 2530 namespaceURI: NAMESPACE, 2531 tagName: "template" 2532 }; 2533 const tagName = stringToLowerCase(element.tagName); 2534 const parentTagName = stringToLowerCase(parent.tagName); 2535 if (!ALLOWED_NAMESPACES[element.namespaceURI]) return false; 2536 if (element.namespaceURI === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName); 2537 if (element.namespaceURI === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName); 2538 if (element.namespaceURI === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName); 2539 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) return true; 2540 return false; 2541 }; 2542 /** 2543 * _forceRemove 2544 * 2545 * @param node a DOM node 2546 */ 2547 const _forceRemove = function _forceRemove(node) { 2548 arrayPush(DOMPurify.removed, { element: node }); 2549 try { 2550 getParentNode(node).removeChild(node); 2551 } catch (_) { 2552 remove(node); 2553 if (!getParentNode(node)) throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place"); 2554 } 2555 }; 2556 /** 2557 * _neutralizeRoot 2558 * 2559 * Fail-closed teardown of an in-place root after the sanitize walk aborts 2560 * (campaign-3 F2). An internal throw mid-walk — e.g. a page-registered 2561 * custom element's reaction detaches a node so `_forceRemove`'s deliberate 2562 * parentless guard throws, or any other re-entrant engine mutation — would 2563 * otherwise leave the caller's *live* tree half-sanitized, with everything 2564 * after the abort point still carrying its handlers. There is no safe way 2565 * to resume the walk (the tree mutated under us), so we strip the root bare: 2566 * remove every child and every attribute, then let the caller's catch see 2567 * the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes` 2568 * getters; the root was already clobber-pre-flighted at the IN_PLACE entry). 2569 * 2570 * @param root the in-place root to empty 2571 */ 2572 const _neutralizeRoot = function _neutralizeRoot(root) { 2573 const childNodes = getChildNodes(root); 2574 if (childNodes) { 2575 const snapshot = []; 2576 arrayForEach(childNodes, (child) => { 2577 arrayPush(snapshot, child); 2578 }); 2579 arrayForEach(snapshot, (child) => { 2580 try { 2581 remove(child); 2582 } catch (_) {} 2583 }); 2584 } 2585 const attributes = getAttributes(root); 2586 if (attributes) for (let i = attributes.length - 1; i >= 0; --i) { 2587 const attribute = attributes[i]; 2588 const name = attribute && attribute.name; 2589 if (typeof name === "string") try { 2590 root.removeAttribute(name); 2591 } catch (_) {} 2592 } 2593 }; 2594 /** 2595 * _removeAttribute 2596 * 2597 * @param name an Attribute name 2598 * @param element a DOM node 2599 */ 2600 const _removeAttribute = function _removeAttribute(name, element) { 2601 try { 2602 arrayPush(DOMPurify.removed, { 2603 attribute: element.getAttributeNode(name), 2604 from: element 2605 }); 2606 } catch (_) { 2607 arrayPush(DOMPurify.removed, { 2608 attribute: null, 2609 from: element 2610 }); 2611 } 2612 element.removeAttribute(name); 2613 if (name === "is") if (RETURN_DOM || RETURN_DOM_FRAGMENT) try { 2614 _forceRemove(element); 2615 } catch (_) {} 2616 else try { 2617 element.setAttribute(name, ""); 2618 } catch (_) {} 2619 }; 2620 /** 2621 * _stripDisallowedAttributes 2622 * 2623 * Removes every attribute the active configuration does not allow from a 2624 * single element, using the same allowlist as the main attribute pass (so 2625 * `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to 2626 * neutralise nodes that are being discarded from an in-place tree. 2627 * 2628 * @param element the element to strip 2629 */
vendor: 8,537 bytes, lines 2630-2793
2630 const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) { 2631 const attributes = getAttributes(element); 2632 if (!attributes) return; 2633 for (let i = attributes.length - 1; i >= 0; --i) { 2634 const attribute = attributes[i]; 2635 const name = attribute && attribute.name; 2636 if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue; 2637 try { 2638 element.removeAttribute(name); 2639 } catch (_) {} 2640 } 2641 }; 2642 /** 2643 * _neutralizeSubtree 2644 * 2645 * Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT 2646 * move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary, 2647 * namespace, comment, processing-instruction and KEEP_CONTENT:false removals 2648 * all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path 2649 * those dropped nodes are detached from the caller's LIVE tree but a 2650 * handler-bearing original among them (an `<img onerror>`/`<video>` that was 2651 * loading) keeps its queued resource event, which fires in page scope after 2652 * sanitize returns. This walks a removed subtree and strips every attribute 2653 * the active configuration does not allow — so `on*` handlers are cancelled 2654 * through the SAME allowlist that governs kept nodes, not a separate `/^on/` 2655 * blocklist. Run synchronously before sanitize returns, i.e. before any 2656 * queued event can fire. Hook-free by design: these nodes leave the output, 2657 * so firing attribute hooks for them would be surprising. Clobber-safe reads; 2658 * a doomed clobbered node may shadow `removeAttribute` (its own attributes are 2659 * irrelevant — it is discarded — while its non-clobbered descendants, e.g. 2660 * the `<img>`, are reached and scrubbed). 2661 * 2662 * @param root the root of a removed subtree to neutralise 2663 */ 2664 const _neutralizeSubtree = function _neutralizeSubtree(root) { 2665 const stack = [root]; 2666 while (stack.length > 0) { 2667 const node = stack.pop(); 2668 if ((getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element) _stripDisallowedAttributes(node); 2669 const childNodes = getChildNodes(node); 2670 if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]); 2671 } 2672 }; 2673 /** 2674 * _initDocument 2675 * 2676 * @param dirty - a string of dirty markup 2677 * @return a DOM, filled with the dirty markup 2678 */ 2679 const _initDocument = function _initDocument(dirty) { 2680 let doc = null; 2681 let leadingWhitespace = null; 2682 if (FORCE_BODY) dirty = "<remove></remove>" + dirty; 2683 else { 2684 const matches = stringMatch(dirty, /^[\r\n\t ]+/); 2685 leadingWhitespace = matches && matches[0]; 2686 } 2687 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) dirty = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>" + dirty + "</body></html>"; 2688 const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty; 2689 if (NAMESPACE === HTML_NAMESPACE) try { 2690 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); 2691 } catch (_) {} 2692 if (!doc || !doc.documentElement) { 2693 doc = implementation.createDocument(NAMESPACE, "template", null); 2694 try { 2695 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; 2696 } catch (_) {} 2697 } 2698 const body = doc.body || doc.documentElement; 2699 if (dirty && leadingWhitespace) body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); 2700 if (NAMESPACE === HTML_NAMESPACE) return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0]; 2701 return WHOLE_DOCUMENT ? doc.documentElement : body; 2702 }; 2703 /** 2704 * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. 2705 * 2706 * @param root The root element or node to start traversing on. 2707 * @return The created NodeIterator 2708 */ 2709 const _createNodeIterator = function _createNodeIterator(root) { 2710 return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null); 2711 }; 2712 /** 2713 * Replace template expression syntax (mustache, ERB, template 2714 * literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub 2715 * sites. Order matters: mustache, then ERB, then template literal. 2716 * 2717 * @param value the string to scrub 2718 * @returns the scrubbed string 2719 */ 2720 const _stripTemplateExpressions = function _stripTemplateExpressions(value) { 2721 value = stringReplace(value, MUSTACHE_EXPR$1, " "); 2722 value = stringReplace(value, ERB_EXPR$1, " "); 2723 value = stringReplace(value, TMPLIT_EXPR$1, " "); 2724 return value; 2725 }; 2726 /** 2727 * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the 2728 * character data of an element subtree. Used as the final safety net for 2729 * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions 2730 * which only form after text-node normalization (e.g. fragments split across 2731 * stripped elements) cannot survive into a template-evaluating framework. 2732 * 2733 * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data` 2734 * in place rather than round-tripping through innerHTML. This preserves 2735 * descendant node references (important for IN_PLACE callers), avoids a 2736 * serialize/reparse cycle, and reads literal character data — which means 2737 * `<%...%>` in text content matches the ERB regex against its real bytes 2738 * instead of the HTML-entity-escaped form innerHTML would produce. 2739 * 2740 * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for 2741 * attributes is performed during the per-node `_sanitizeAttributes` pass. 2742 * 2743 * @param node The root element whose character data should be scrubbed. 2744 */ 2745 const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) { 2746 var _node$querySelectorAl; 2747 node.normalize(); 2748 const walker = createNodeIterator.call(node.ownerDocument || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null); 2749 let currentNode = walker.nextNode(); 2750 while (currentNode) { 2751 currentNode.data = _stripTemplateExpressions(currentNode.data); 2752 currentNode = walker.nextNode(); 2753 } 2754 const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template"); 2755 if (templates) arrayForEach(templates, (tmpl) => { 2756 if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content); 2757 }); 2758 }; 2759 /** 2760 * _isClobbered 2761 * 2762 * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML 2763 * interface with [LegacyOverrideBuiltIns]; a descendant element with a 2764 * `name` attribute matching a prototype property shadows that property 2765 * on direct reads. We use this check at the IN_PLACE entry-point and 2766 * during attribute sanitization to refuse clobbered forms. 2767 * 2768 * @param element element to check for clobbering attacks 2769 * @return true if clobbered, false if safe 2770 */ 2771 const _isClobbered = function _isClobbered(element) { 2772 const realTagName = getNodeName ? getNodeName(element) : null; 2773 if (typeof realTagName !== "string") return false; 2774 if (transformCaseFunc(realTagName) !== "form") return false; 2775 return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || element.nodeType !== getNodeType(element) || element.childNodes !== getChildNodes(element); 2776 }; 2777 /** 2778 * Checks whether the given value is a DocumentFragment from any realm. 2779 * 2780 * The realm-independent replacement reads `nodeType` through the cached 2781 * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE 2782 * constant (11). nodeType is a numeric value resolved from the node's 2783 * internal slot, identical across realms for the same kind of node. 2784 * 2785 * @param value object to check 2786 * @return true if value is a DocumentFragment-shaped node from any realm 2787 */ 2788 const _isDocumentFragment = function _isDocumentFragment(value) { 2789 if (!getNodeType || typeof value !== "object" || value === null) return false; 2790 try { 2791 return getNodeType(value) === NODE_TYPE.documentFragment; 2792 } catch (_) { 2793 return false;
2794 } 2795 }; 2796 /** 2797 * Checks whether the given object is a DOM node, including nodes that 2798 * originate from a different window/realm (e.g. an iframe's 2799 * contentDocument). The previous `value instanceof Node` check was 2800 * realm-bound: nodes from a different window failed it, causing 2801 * sanitize() to silently stringify them and reset IN_PLACE to false, 2802 * returning the original node unsanitized. See GHSA-4w3q-35jp-p934. 2803 * 2804 * @param value object to check whether it's a DOM node 2805 * @return true if value is a DOM node from any realm 2806 */ 2807 const _isNode = function _isNode(value) { 2808 if (!getNodeType || typeof value !== "object" || value === null) return false; 2809 try { 2810 return typeof getNodeType(value) === "number"; 2811 } catch (_) { 2812 return false; 2813 } 2814 }; 2815 function _executeHooks(hooks, currentNode, data) { 2816 if (hooks.length === 0) return; 2817 arrayForEach(hooks, (hook) => { 2818 hook.call(DOMPurify, currentNode, data, CONFIG); 2819 }); 2820 } 2821 /** 2822 * Structural-threat checks that condemn a node regardless of the 2823 * allowlists: mXSS via namespace confusion, risky CSS construction, 2824 * processing instructions, markup-bearing comments. Pure predicate; 2825 * the caller removes. Check order is load-bearing. 2826 * 2827 * @param currentNode the node to inspect 2828 * @param tagName the node's transformCaseFunc'd tag name 2829 * @return true if the node must be removed 2830 */ 2831 const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) { 2832 if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true; 2833 if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) return true; 2834 if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true; 2835 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true; 2836 return false; 2837 }; 2838 /** 2839 * Handle a node whose tag is forbidden or not allowlisted: keep 2840 * allowed custom elements (false return exits _sanitizeElements 2841 * early - namespace/fallback checks and the afterSanitizeElements 2842 * hook are intentionally skipped for kept custom elements), else 2843 * hoist content per KEEP_CONTENT and remove. 2844 * 2845 * @param currentNode the disallowed node 2846 * @param tagName the node's transformCaseFunc'd tag name 2847 * @return true if the node was removed, false if kept 2848 */ 2849 const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) { 2850 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { 2851 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false; 2852 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false; 2853 } 2854 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { 2855 const parentNode = getParentNode(currentNode); 2856 const childNodes = getChildNodes(currentNode); 2857 if (childNodes && parentNode) { 2858 const childCount = childNodes.length; 2859 for (let i = childCount - 1; i >= 0; --i) { 2860 const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true); 2861 parentNode.insertBefore(hoisted, getNextSibling(currentNode)); 2862 } 2863 } 2864 } 2865 _forceRemove(currentNode); 2866 return true; 2867 }; 2868 /** 2869 * _sanitizeElements 2870 * 2871 * @protect nodeName 2872 * @protect textContent 2873 * @protect removeChild 2874 * @param currentNode to check for permission to exist 2875 * @return true if node was killed, false if left alive 2876 */ 2877 const _sanitizeElements = function _sanitizeElements(currentNode) { 2878 _executeHooks(hooks.beforeSanitizeElements, currentNode, null); 2879 if (_isClobbered(currentNode)) { 2880 _forceRemove(currentNode); 2881 return true; 2882 } 2883 const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName); 2884 _executeHooks(hooks.uponSanitizeElement, currentNode, { 2885 tagName, 2886 allowedTags: ALLOWED_TAGS 2887 }); 2888 if (_isUnsafeNode(currentNode, tagName)) { 2889 _forceRemove(currentNode); 2890 return true; 2891 } 2892 if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) return _sanitizeDisallowedNode(currentNode, tagName); 2893 if ((getNodeType ? getNodeType(currentNode) : currentNode.nodeType) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { 2894 _forceRemove(currentNode); 2895 return true; 2896 } 2897 if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) { 2898 _forceRemove(currentNode); 2899 return true; 2900 } 2901 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { 2902 const content = _stripTemplateExpressions(currentNode.textContent); 2903 if (currentNode.textContent !== content) { 2904 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() }); 2905 currentNode.textContent = content; 2906 } 2907 } 2908 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 2909 return false;
2910 }; 2911 /** 2912 * _isValidAttribute 2913 * 2914 * @param lcTag Lowercase tag name of containing element. 2915 * @param lcName Lowercase attribute name. 2916 * @param value Attribute value. 2917 * @return Returns true if `value` is valid, otherwise false. 2918 */ 2919 const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { 2920 if (FORBID_ATTR[lcName]) return false; 2921 if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false; 2922 const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag); 2923 if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)); 2924 else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)); 2925 else if (!nameIsPermitted) if (_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))); 2926 else return false; 2927 else if (URI_SAFE_ATTRIBUTES[lcName]); 2928 else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))); 2929 else if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]); 2930 else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))); 2931 else if (value) return false; 2932 return true; 2933 }; 2934 const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [ 2935 "annotation-xml", 2936 "color-profile", 2937 "font-face", 2938 "font-face-format", 2939 "font-face-name", 2940 "font-face-src", 2941 "font-face-uri", 2942 "missing-glyph" 2943 ]); 2944 /** 2945 * _isBasicCustomElement 2946 * checks if at least one dash is included in tagName, and it's not the first char 2947 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name 2948 * 2949 * @param tagName name of the tag of the node to sanitize 2950 * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false. 2951 */ 2952 const _isBasicCustomElement = function _isBasicCustomElement(tagName) { 2953 return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName); 2954 }; 2955 /** 2956 * Wrap an attribute value in the matching Trusted Types object when 2957 * the active policy requires it. Namespaced attributes pass through 2958 * unchanged (no TT support yet, see 2959 * https://bugs.chromium.org/p/chromium/issues/detail?id=1305293). 2960 * 2961 * @param lcTag lowercase tag name of the containing element 2962 * @param lcName lowercase attribute name 2963 * @param namespaceURI the attribute's namespace, if any 2964 * @param value the attribute value to wrap 2965 * @return the value, wrapped when Trusted Types demand it 2966 */ 2967 const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) { 2968 if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) switch (trustedTypes.getAttributeType(lcTag, lcName)) { 2969 case "TrustedHTML": return _createTrustedHTML(value); 2970 case "TrustedScriptURL": return _createTrustedScriptURL(value); 2971 } 2972 return value; 2973 }; 2974 /** 2975 * Write a modified attribute value back onto the element. On 2976 * success, re-probe for clobbering introduced by the new value and 2977 * remove the element when found; otherwise pop the removal entry 2978 * recorded by the earlier _removeAttribute (long-standing pairing 2979 * with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On 2980 * failure, remove the attribute instead. 2981 * 2982 * @param currentNode the element carrying the attribute 2983 * @param name the attribute name as present on the element 2984 * @param namespaceURI the attribute's namespace, if any 2985 * @param value the new attribute value 2986 */ 2987 const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) { 2988 try { 2989 if (namespaceURI) currentNode.setAttributeNS(namespaceURI, name, value); 2990 else currentNode.setAttribute(name, value); 2991 if (_isClobbered(currentNode)) _forceRemove(currentNode); 2992 else arrayPop(DOMPurify.removed); 2993 } catch (_) { 2994 _removeAttribute(name, currentNode); 2995 } 2996 }; 2997 /** 2998 * _sanitizeAttributes 2999 * 3000 * @protect attributes 3001 * @protect nodeName 3002 * @protect removeAttribute 3003 * @protect setAttribute 3004 * 3005 * @param currentNode to sanitize 3006 */ 3007 const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { 3008 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null); 3009 const attributes = currentNode.attributes; 3010 if (!attributes || _isClobbered(currentNode)) return; 3011 const hookEvent = { 3012 attrName: "", 3013 attrValue: "", 3014 keepAttr: true, 3015 allowedAttributes: ALLOWED_ATTR, 3016 forceKeepAttr: void 0 3017 }; 3018 let l = attributes.length; 3019 const lcTag = transformCaseFunc(currentNode.nodeName); 3020 while (l--) { 3021 const attr = attributes[l]; 3022 const name = attr.name; 3023 const namespaceURI = attr.namespaceURI; 3024 const attrValue = attr.value; 3025 const lcName = transformCaseFunc(name); 3026 const initValue = attrValue; 3027 let value = name === "value" ? initValue : stringTrim(initValue); 3028 hookEvent.attrName = lcName; 3029 hookEvent.attrValue = value; 3030 hookEvent.keepAttr = true; 3031 hookEvent.forceKeepAttr = void 0; 3032 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent); 3033 value = hookEvent.attrValue;
vendor: 4,122 bytes, lines 3034-3141
3034 if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) { 3035 _removeAttribute(name, currentNode); 3036 value = SANITIZE_NAMED_PROPS_PREFIX + value; 3037 } 3038 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) { 3039 _removeAttribute(name, currentNode); 3040 continue; 3041 } 3042 if (lcName === "attributename" && stringMatch(value, "href")) { 3043 _removeAttribute(name, currentNode); 3044 continue; 3045 } 3046 if (hookEvent.forceKeepAttr) continue; 3047 if (!hookEvent.keepAttr) { 3048 _removeAttribute(name, currentNode); 3049 continue; 3050 } 3051 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) { 3052 _removeAttribute(name, currentNode); 3053 continue; 3054 } 3055 if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value); 3056 if (!_isValidAttribute(lcTag, lcName, value)) { 3057 _removeAttribute(name, currentNode); 3058 continue; 3059 } 3060 value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value); 3061 if (value !== initValue) _setAttributeValue(currentNode, name, namespaceURI, value); 3062 } 3063 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null); 3064 }; 3065 /** 3066 * _sanitizeShadowDOM 3067 * 3068 * @param fragment to iterate over recursively 3069 */ 3070 const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) { 3071 let shadowNode = null; 3072 const shadowIterator = _createNodeIterator(fragment); 3073 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null); 3074 while (shadowNode = shadowIterator.nextNode()) { 3075 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null); 3076 _sanitizeElements(shadowNode); 3077 _sanitizeAttributes(shadowNode); 3078 if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content); 3079 if ((getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType) === NODE_TYPE.element) { 3080 const innerSr = getShadowRoot(shadowNode); 3081 if (_isDocumentFragment(innerSr)) { 3082 _sanitizeAttachedShadowRoots(innerSr); 3083 _sanitizeShadowDOM2(innerSr); 3084 } 3085 } 3086 } 3087 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null); 3088 }; 3089 /** 3090 * _sanitizeAttachedShadowRoots 3091 * 3092 * Walks `root` and feeds every attached shadow root we encounter into 3093 * the existing _sanitizeShadowDOM pipeline. The default node iterator 3094 * does not descend into shadow trees, so nodes inside an attached 3095 * shadow root would otherwise be skipped entirely. 3096 * 3097 * Two real input paths put attached shadow roots in front of us: 3098 * 1. IN_PLACE on a DOM node that already has shadow roots attached. 3099 * 2. DOM-node input where importNode(dirty, true) deep-clones the 3100 * shadow root because it was created with `clonable: true`. 3101 * 3102 * This pass runs once, up front, so the main iteration loop (and the 3103 * existing _sanitizeShadowDOM template-content recursion) stay 3104 * untouched — string-input paths are not affected. 3105 * 3106 * @param root the subtree root to walk for attached shadow roots 3107 */ 3108 const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) { 3109 const stack = [{ 3110 node: root, 3111 shadow: null 3112 }]; 3113 while (stack.length > 0) { 3114 const item = stack.pop(); 3115 if (item.shadow) { 3116 _sanitizeShadowDOM2(item.shadow); 3117 continue; 3118 } 3119 const node = item.node; 3120 const isElement = (getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element; 3121 const childNodes = getChildNodes(node); 3122 if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({ 3123 node: childNodes[i], 3124 shadow: null 3125 }); 3126 if (isElement) { 3127 const rootName = getNodeName ? getNodeName(node) : null; 3128 if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") { 3129 const content = node.content; 3130 if (_isDocumentFragment(content)) stack.push({ 3131 node: content, 3132 shadow: null 3133 }); 3134 } 3135 } 3136 if (isElement) { 3137 const sr = getShadowRoot(node); 3138 if (_isDocumentFragment(sr)) stack.push({ 3139 node: null, 3140 shadow: sr 3141 }, {
vendor: 4,286 bytes, lines 3142-3236
3142 node: sr, 3143 shadow: null 3144 }); 3145 } 3146 } 3147 }; 3148 DOMPurify.sanitize = function(dirty) { 3149 let cfg = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; 3150 let body = null; 3151 let importedNode = null; 3152 let currentNode = null; 3153 let returnNode = null; 3154 IS_EMPTY_INPUT = !dirty; 3155 if (IS_EMPTY_INPUT) dirty = "<!-->"; 3156 if (typeof dirty !== "string" && !_isNode(dirty)) { 3157 dirty = stringifyValue(dirty); 3158 if (typeof dirty !== "string") throw typeErrorCreate("dirty is not a string, aborting"); 3159 } 3160 if (!DOMPurify.isSupported) return dirty; 3161 if (SET_CONFIG) { 3162 ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS; 3163 ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR; 3164 } else _parseConfig(cfg); 3165 if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) ALLOWED_TAGS = clone(ALLOWED_TAGS); 3166 if (hooks.uponSanitizeAttribute.length > 0) ALLOWED_ATTR = clone(ALLOWED_ATTR); 3167 DOMPurify.removed = []; 3168 const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty); 3169 if (inPlace) { 3170 const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName; 3171 if (typeof nn === "string") { 3172 const tagName = transformCaseFunc(nn); 3173 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place"); 3174 } 3175 if (_isClobbered(dirty)) throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place"); 3176 try { 3177 _sanitizeAttachedShadowRoots(dirty); 3178 } catch (error) { 3179 _neutralizeRoot(dirty); 3180 throw error; 3181 } 3182 } else if (_isNode(dirty)) { 3183 body = _initDocument("<!---->"); 3184 importedNode = body.ownerDocument.importNode(dirty, true); 3185 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") body = importedNode; 3186 else if (importedNode.nodeName === "HTML") body = importedNode; 3187 else body.appendChild(importedNode); 3188 _sanitizeAttachedShadowRoots(importedNode); 3189 } else { 3190 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty; 3191 body = _initDocument(dirty); 3192 if (!body) return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ""; 3193 } 3194 if (body && FORCE_BODY) _forceRemove(body.firstChild); 3195 const nodeIterator = _createNodeIterator(inPlace ? dirty : body); 3196 try { 3197 while (currentNode = nodeIterator.nextNode()) { 3198 _sanitizeElements(currentNode); 3199 _sanitizeAttributes(currentNode); 3200 if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content); 3201 } 3202 } catch (error) { 3203 if (inPlace) _neutralizeRoot(dirty); 3204 throw error; 3205 } 3206 if (inPlace) { 3207 arrayForEach(DOMPurify.removed, (entry) => { 3208 if (entry.element) _neutralizeSubtree(entry.element); 3209 }); 3210 if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty); 3211 return dirty; 3212 } 3213 if (RETURN_DOM) { 3214 if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(body); 3215 if (RETURN_DOM_FRAGMENT) { 3216 returnNode = createDocumentFragment.call(body.ownerDocument); 3217 while (body.firstChild) returnNode.appendChild(body.firstChild); 3218 } else returnNode = body; 3219 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) returnNode = importNode.call(originalDocument, returnNode, true); 3220 return returnNode; 3221 } 3222 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; 3223 if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML; 3224 if (SAFE_FOR_TEMPLATES) serializedHTML = _stripTemplateExpressions(serializedHTML); 3225 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML; 3226 }; 3227 DOMPurify.setConfig = function() { 3228 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 3229 _parseConfig(cfg); 3230 SET_CONFIG = true; 3231 SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS; 3232 SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR; 3233 }; 3234 DOMPurify.clearConfig = function() { 3235 CONFIG = null; 3236 SET_CONFIG = false;
3237 SET_CONFIG_ALLOWED_TAGS = null; 3238 SET_CONFIG_ALLOWED_ATTR = null; 3239 trustedTypesPolicy = defaultTrustedTypesPolicy; 3240 emptyHTML = ""; 3241 }; 3242 DOMPurify.isValidAttribute = function(tag, attr, value) { 3243 if (!CONFIG) _parseConfig({}); 3244 const lcTag = transformCaseFunc(tag); 3245 const lcName = transformCaseFunc(attr); 3246 return _isValidAttribute(lcTag, lcName, value); 3247 }; 3248 DOMPurify.addHook = function(entryPoint, hookFunction) { 3249 if (typeof hookFunction !== "function") return; 3250 if (!objectHasOwnProperty(hooks, entryPoint)) return; 3251 arrayPush(hooks[entryPoint], hookFunction); 3252 }; 3253 DOMPurify.removeHook = function(entryPoint, hookFunction) { 3254 if (!objectHasOwnProperty(hooks, entryPoint)) return; 3255 if (hookFunction !== void 0) { 3256 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction); 3257 return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0]; 3258 } 3259 return arrayPop(hooks[entryPoint]); 3260 }; 3261 DOMPurify.removeHooks = function(entryPoint) { 3262 if (!objectHasOwnProperty(hooks, entryPoint)) return; 3263 hooks[entryPoint] = []; 3264 }; 3265 DOMPurify.removeAllHooks = function() { 3266 hooks = _createHooksMap(); 3267 }; 3268 return DOMPurify; 3269 } 3270 var entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor, freeze, seal, create, _ref, apply, construct, arrayForEach, arrayLastIndexOf, arrayPop, arrayPush, arraySplice, arrayIsArray, stringToLowerCase, stringToString, stringMatch, stringReplace, stringIndexOf, stringTrim, numberToString, booleanToString, bigintToString, symbolToString, objectHasOwnProperty, objectToString, regExpTest, typeErrorCreate, html$1, svg$1, svgFilters, svgDisallowed, mathMl$1, mathMlDisallowed, text, html, svg, mathMl, xml, MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_ALLOWED_URI, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE, DOCTYPE_NAME, CUSTOM_ELEMENT, ELEMENT_MARKUP_PROBE, COMMENT_MARKUP_PROBE, FALLBACK_TAG_CLOSE, SELF_CLOSING_TAG, NODE_TYPE, getGlobal, _createTrustedTypesPolicy, _createHooksMap, _resolveSetOption, purify; 3271 var init_purify_es = __esmMin((() => { 3272 entries = Object.entries; 3273 setPrototypeOf = Object.setPrototypeOf; 3274 isFrozen = Object.isFrozen; 3275 getPrototypeOf = Object.getPrototypeOf; 3276 getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 3277 freeze = Object.freeze; 3278 seal = Object.seal; 3279 create = Object.create; 3280 _ref = typeof Reflect !== "undefined" && Reflect; 3281 apply = _ref.apply; 3282 construct = _ref.construct; 3283 if (!freeze) freeze = function freeze(x) { 3284 return x; 3285 }; 3286 if (!seal) seal = function seal(x) { 3287 return x; 3288 }; 3289 if (!apply) apply = function apply(func, thisArg) { 3290 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key]; 3291 return func.apply(thisArg, args); 3292 }; 3293 if (!construct) construct = function construct(Func) { 3294 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) args[_key2 - 1] = arguments[_key2]; 3295 return new Func(...args); 3296 }; 3297 arrayForEach = unapply(Array.prototype.forEach); 3298 arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); 3299 arrayPop = unapply(Array.prototype.pop); 3300 arrayPush = unapply(Array.prototype.push); 3301 arraySplice = unapply(Array.prototype.splice); 3302 arrayIsArray = Array.isArray; 3303 stringToLowerCase = unapply(String.prototype.toLowerCase); 3304 stringToString = unapply(String.prototype.toString); 3305 stringMatch = unapply(String.prototype.match); 3306 stringReplace = unapply(String.prototype.replace); 3307 stringIndexOf = unapply(String.prototype.indexOf); 3308 stringTrim = unapply(String.prototype.trim); 3309 numberToString = unapply(Number.prototype.toString); 3310 booleanToString = unapply(Boolean.prototype.toString); 3311 bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString); 3312 symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString); 3313 objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); 3314 objectToString = unapply(Object.prototype.toString); 3315 regExpTest = unapply(RegExp.prototype.test); 3316 typeErrorCreate = unconstruct(TypeError); 3317 html$1 = freeze([ 3318 "a", 3319 "abbr", 3320 "acronym", 3321 "address", 3322 "area", 3323 "article", 3324 "aside", 3325 "audio", 3326 "b", 3327 "bdi", 3328 "bdo", 3329 "big", 3330 "blink", 3331 "blockquote", 3332 "body", 3333 "br", 3334 "button", 3335 "canvas", 3336 "caption", 3337 "center", 3338 "cite", 3339 "code", 3340 "col", 3341 "colgroup", 3342 "content", 3343 "data", 3344 "datalist", 3345 "dd", 3346 "decorator", 3347 "del", 3348 "details", 3349 "dfn", 3350 "dialog", 3351 "dir", 3352 "div", 3353 "dl", 3354 "dt", 3355 "element", 3356 "em", 3357 "fieldset", 3358 "figcaption", 3359 "figure", 3360 "font", 3361 "footer", 3362 "form", 3363 "h1", 3364 "h2", 3365 "h3", 3366 "h4", 3367 "h5", 3368 "h6", 3369 "head", 3370 "header", 3371 "hgroup", 3372 "hr", 3373 "html", 3374 "i", 3375 "img", 3376 "input", 3377 "ins", 3378 "kbd", 3379 "label", 3380 "legend", 3381 "li", 3382 "main", 3383 "map", 3384 "mark", 3385 "marquee", 3386 "menu", 3387 "menuitem", 3388 "meter", 3389 "nav", 3390 "nobr", 3391 "ol", 3392 "optgroup", 3393 "option", 3394 "output", 3395 "p", 3396 "picture", 3397 "pre", 3398 "progress", 3399 "q", 3400 "rp", 3401 "rt", 3402 "ruby", 3403 "s", 3404 "samp", 3405 "search", 3406 "section", 3407 "select", 3408 "shadow", 3409 "slot", 3410 "small", 3411 "source", 3412 "spacer", 3413 "span", 3414 "strike", 3415 "strong", 3416 "style", 3417 "sub", 3418 "summary", 3419 "sup", 3420 "table", 3421 "tbody", 3422 "td", 3423 "template", 3424 "textarea", 3425 "tfoot", 3426 "th", 3427 "thead", 3428 "time", 3429 "tr", 3430 "track", 3431 "tt", 3432 "u", 3433 "ul", 3434 "var", 3435 "video", 3436 "wbr" 3437 ]); 3438 svg$1 = freeze([ 3439 "svg", 3440 "a", 3441 "altglyph", 3442 "altglyphdef", 3443 "altglyphitem", 3444 "animatecolor", 3445 "animatemotion", 3446 "animatetransform", 3447 "circle", 3448 "clippath", 3449 "defs", 3450 "desc", 3451 "ellipse", 3452 "enterkeyhint", 3453 "exportparts", 3454 "filter", 3455 "font", 3456 "g", 3457 "glyph", 3458 "glyphref", 3459 "hkern", 3460 "image", 3461 "inputmode", 3462 "line", 3463 "lineargradient", 3464 "marker", 3465 "mask", 3466 "metadata", 3467 "mpath", 3468 "part", 3469 "path", 3470 "pattern", 3471 "polygon", 3472 "polyline", 3473 "radialgradient", 3474 "rect", 3475 "stop", 3476 "style", 3477 "switch", 3478 "symbol", 3479 "text", 3480 "textpath", 3481 "title", 3482 "tref", 3483 "tspan", 3484 "view", 3485 "vkern" 3486 ]); 3487 svgFilters = freeze([ 3488 "feBlend", 3489 "feColorMatrix", 3490 "feComponentTransfer", 3491 "feComposite", 3492 "feConvolveMatrix", 3493 "feDiffuseLighting", 3494 "feDisplacementMap", 3495 "feDistantLight", 3496 "feDropShadow", 3497 "feFlood", 3498 "feFuncA", 3499 "feFuncB", 3500 "feFuncG", 3501 "feFuncR", 3502 "feGaussianBlur", 3503 "feImage", 3504 "feMerge", 3505 "feMergeNode", 3506 "feMorphology", 3507 "feOffset", 3508 "fePointLight", 3509 "feSpecularLighting", 3510 "feSpotLight", 3511 "feTile", 3512 "feTurbulence" 3513 ]); 3514 svgDisallowed = freeze([ 3515 "animate", 3516 "color-profile", 3517 "cursor", 3518 "discard", 3519 "font-face", 3520 "font-face-format", 3521 "font-face-name", 3522 "font-face-src", 3523 "font-face-uri", 3524 "foreignobject", 3525 "hatch", 3526 "hatchpath", 3527 "mesh", 3528 "meshgradient", 3529 "meshpatch", 3530 "meshrow", 3531 "missing-glyph", 3532 "script", 3533 "set", 3534 "solidcolor", 3535 "unknown", 3536 "use" 3537 ]); 3538 mathMl$1 = freeze([ 3539 "math", 3540 "menclose", 3541 "merror", 3542 "mfenced", 3543 "mfrac", 3544 "mglyph", 3545 "mi", 3546 "mlabeledtr", 3547 "mmultiscripts", 3548 "mn", 3549 "mo", 3550 "mover", 3551 "mpadded", 3552 "mphantom", 3553 "mroot", 3554 "mrow", 3555 "ms", 3556 "mspace", 3557 "msqrt", 3558 "mstyle", 3559 "msub", 3560 "msup", 3561 "msubsup", 3562 "mtable", 3563 "mtd", 3564 "mtext", 3565 "mtr", 3566 "munder", 3567 "munderover", 3568 "mprescripts" 3569 ]); 3570 mathMlDisallowed = freeze([ 3571 "maction", 3572 "maligngroup", 3573 "malignmark", 3574 "mlongdiv", 3575 "mscarries", 3576 "mscarry", 3577 "msgroup", 3578 "mstack", 3579 "msline", 3580 "msrow", 3581 "semantics", 3582 "annotation", 3583 "annotation-xml", 3584 "mprescripts", 3585 "none" 3586 ]); 3587 text = freeze(["#text"]); 3588 html = freeze([ 3589 "accept", 3590 "action", 3591 "align", 3592 "alt", 3593 "autocapitalize", 3594 "autocomplete", 3595 "autopictureinpicture", 3596 "autoplay", 3597 "background", 3598 "bgcolor", 3599 "border", 3600 "capture", 3601 "cellpadding", 3602 "cellspacing", 3603 "checked", 3604 "cite", 3605 "class", 3606 "clear", 3607 "color", 3608 "cols", 3609 "colspan", 3610 "command", 3611 "commandfor", 3612 "controls", 3613 "controlslist", 3614 "coords", 3615 "crossorigin", 3616 "datetime", 3617 "decoding", 3618 "default", 3619 "dir", 3620 "disabled", 3621 "disablepictureinpicture", 3622 "disableremoteplayback", 3623 "download", 3624 "draggable", 3625 "enctype", 3626 "enterkeyhint", 3627 "exportparts", 3628 "face", 3629 "for", 3630 "headers",
3631 "height", 3632 "hidden", 3633 "high", 3634 "href", 3635 "hreflang", 3636 "id", 3637 "inert", 3638 "inputmode", 3639 "integrity", 3640 "ismap", 3641 "kind", 3642 "label", 3643 "lang", 3644 "list", 3645 "loading", 3646 "loop", 3647 "low", 3648 "max", 3649 "maxlength", 3650 "media", 3651 "method", 3652 "min", 3653 "minlength", 3654 "multiple", 3655 "muted", 3656 "name", 3657 "nonce", 3658 "noshade", 3659 "novalidate", 3660 "nowrap", 3661 "open", 3662 "optimum", 3663 "part", 3664 "pattern", 3665 "placeholder", 3666 "playsinline", 3667 "popover", 3668 "popovertarget", 3669 "popovertargetaction", 3670 "poster", 3671 "preload", 3672 "pubdate", 3673 "radiogroup", 3674 "readonly", 3675 "rel", 3676 "required", 3677 "rev", 3678 "reversed", 3679 "role", 3680 "rows", 3681 "rowspan", 3682 "spellcheck", 3683 "scope", 3684 "selected", 3685 "shape", 3686 "size", 3687 "sizes", 3688 "slot", 3689 "span", 3690 "srclang", 3691 "start", 3692 "src", 3693 "srcset", 3694 "step", 3695 "style", 3696 "summary", 3697 "tabindex", 3698 "title", 3699 "translate", 3700 "type", 3701 "usemap", 3702 "valign", 3703 "value", 3704 "width", 3705 "wrap", 3706 "xmlns" 3707 ]); 3708 svg = freeze([ 3709 "accent-height", 3710 "accumulate", 3711 "additive", 3712 "alignment-baseline", 3713 "amplitude", 3714 "ascent", 3715 "attributename", 3716 "attributetype", 3717 "azimuth", 3718 "basefrequency", 3719 "baseline-shift", 3720 "begin", 3721 "bias", 3722 "by", 3723 "class", 3724 "clip", 3725 "clippathunits", 3726 "clip-path", 3727 "clip-rule", 3728 "color", 3729 "color-interpolation", 3730 "color-interpolation-filters", 3731 "color-profile", 3732 "color-rendering", 3733 "cx", 3734 "cy", 3735 "d", 3736 "dx", 3737 "dy", 3738 "diffuseconstant", 3739 "direction", 3740 "display", 3741 "divisor", 3742 "dur", 3743 "edgemode", 3744 "elevation", 3745 "end", 3746 "exponent", 3747 "fill", 3748 "fill-opacity", 3749 "fill-rule", 3750 "filter", 3751 "filterunits", 3752 "flood-color", 3753 "flood-opacity", 3754 "font-family", 3755 "font-size", 3756 "font-size-adjust", 3757 "font-stretch", 3758 "font-style", 3759 "font-variant", 3760 "font-weight", 3761 "fx", 3762 "fy", 3763 "g1", 3764 "g2", 3765 "glyph-name", 3766 "glyphref", 3767 "gradientunits", 3768 "gradienttransform", 3769 "height", 3770 "href", 3771 "id", 3772 "image-rendering", 3773 "in", 3774 "in2", 3775 "intercept", 3776 "k", 3777 "k1", 3778 "k2", 3779 "k3", 3780 "k4", 3781 "kerning", 3782 "keypoints", 3783 "keysplines", 3784 "keytimes", 3785 "lang", 3786 "lengthadjust", 3787 "letter-spacing", 3788 "kernelmatrix", 3789 "kernelunitlength", 3790 "lighting-color", 3791 "local", 3792 "marker-end", 3793 "marker-mid", 3794 "marker-start", 3795 "markerheight", 3796 "markerunits", 3797 "markerwidth", 3798 "maskcontentunits", 3799 "maskunits", 3800 "max", 3801 "mask", 3802 "mask-type", 3803 "media", 3804 "method", 3805 "mode", 3806 "min", 3807 "name", 3808 "numoctaves", 3809 "offset", 3810 "operator", 3811 "opacity", 3812 "order", 3813 "orient", 3814 "orientation", 3815 "origin", 3816 "overflow", 3817 "paint-order", 3818 "path", 3819 "pathlength", 3820 "patterncontentunits", 3821 "patterntransform", 3822 "patternunits", 3823 "points", 3824 "preservealpha", 3825 "preserveaspectratio", 3826 "primitiveunits", 3827 "r", 3828 "rx", 3829 "ry", 3830 "radius", 3831 "refx", 3832 "refy", 3833 "repeatcount", 3834 "repeatdur", 3835 "restart", 3836 "result", 3837 "rotate", 3838 "scale", 3839 "seed", 3840 "shape-rendering", 3841 "slope", 3842 "specularconstant", 3843 "specularexponent", 3844 "spreadmethod", 3845 "startoffset", 3846 "stddeviation", 3847 "stitchtiles", 3848 "stop-color", 3849 "stop-opacity", 3850 "stroke-dasharray", 3851 "stroke-dashoffset", 3852 "stroke-linecap", 3853 "stroke-linejoin", 3854 "stroke-miterlimit", 3855 "stroke-opacity", 3856 "stroke", 3857 "stroke-width", 3858 "style", 3859 "surfacescale", 3860 "systemlanguage", 3861 "tabindex", 3862 "tablevalues", 3863 "targetx", 3864 "targety", 3865 "transform", 3866 "transform-origin", 3867 "text-anchor", 3868 "text-decoration", 3869 "text-rendering", 3870 "textlength", 3871 "type", 3872 "u1", 3873 "u2", 3874 "unicode", 3875 "values", 3876 "viewbox", 3877 "visibility", 3878 "version", 3879 "vert-adv-y", 3880 "vert-origin-x", 3881 "vert-origin-y", 3882 "width", 3883 "word-spacing", 3884 "wrap", 3885 "writing-mode", 3886 "xchannelselector", 3887 "ychannelselector", 3888 "x", 3889 "x1", 3890 "x2", 3891 "xmlns", 3892 "y", 3893 "y1", 3894 "y2", 3895 "z", 3896 "zoomandpan" 3897 ]); 3898 mathMl = freeze([ 3899 "accent", 3900 "accentunder", 3901 "align", 3902 "bevelled", 3903 "close", 3904 "columnalign", 3905 "columnlines", 3906 "columnspacing", 3907 "columnspan", 3908 "denomalign", 3909 "depth", 3910 "dir", 3911 "display", 3912 "displaystyle", 3913 "encoding", 3914 "fence", 3915 "frame",
3916 "height", 3917 "href", 3918 "id", 3919 "largeop", 3920 "length", 3921 "linethickness", 3922 "lquote", 3923 "lspace", 3924 "mathbackground", 3925 "mathcolor", 3926 "mathsize", 3927 "mathvariant", 3928 "maxsize", 3929 "minsize", 3930 "movablelimits", 3931 "notation", 3932 "numalign", 3933 "open", 3934 "rowalign", 3935 "rowlines", 3936 "rowspacing", 3937 "rowspan", 3938 "rspace", 3939 "rquote", 3940 "scriptlevel", 3941 "scriptminsize", 3942 "scriptsizemultiplier", 3943 "selection", 3944 "separator", 3945 "separators", 3946 "stretchy", 3947 "subscriptshift", 3948 "supscriptshift", 3949 "symmetric", 3950 "voffset", 3951 "width", 3952 "xmlns" 3953 ]); 3954 xml = freeze([ 3955 "xlink:href", 3956 "xml:id", 3957 "xlink:title", 3958 "xml:space", 3959 "xmlns:xlink" 3960 ]); 3961 MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g); 3962 ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g); 3963 TMPLIT_EXPR = seal(/\${[\w\W]*/g); 3964 DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); 3965 ARIA_ATTR = seal(/^aria-[\-\w]+$/); 3966 IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i); 3967 IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); 3968 ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g); 3969 DOCTYPE_NAME = seal(/^html$/i); 3970 CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); 3971 ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); 3972 COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); 3973 FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); 3974 SELF_CLOSING_TAG = seal(/\/>/i); 3975 NODE_TYPE = { 3976 element: 1, 3977 attribute: 2, 3978 text: 3, 3979 cdataSection: 4, 3980 entityReference: 5, 3981 entityNode: 6, 3982 processingInstruction: 7, 3983 comment: 8, 3984 document: 9, 3985 documentType: 10, 3986 documentFragment: 11, 3987 notation: 12 3988 }; 3989 getGlobal = function getGlobal() { 3990 return typeof window === "undefined" ? null : window; 3991 }; 3992 _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) { 3993 if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") return null; 3994 let suffix = null; 3995 const ATTR_NAME = "data-tt-policy-suffix"; 3996 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) suffix = purifyHostElement.getAttribute(ATTR_NAME); 3997 const policyName = "dompurify" + (suffix ? "#" + suffix : ""); 3998 try { 3999 return trustedTypes.createPolicy(policyName, { 4000 createHTML(html) { 4001 return html; 4002 }, 4003 createScriptURL(scriptUrl) { 4004 return scriptUrl; 4005 } 4006 }); 4007 } catch (_) { 4008 console.warn("TrustedTypes policy " + policyName + " could not be created."); 4009 return null; 4010 } 4011 }; 4012 _createHooksMap = function _createHooksMap() { 4013 return { 4014 afterSanitizeAttributes: [], 4015 afterSanitizeElements: [], 4016 afterSanitizeShadowDOM: [], 4017 beforeSanitizeAttributes: [], 4018 beforeSanitizeElements: [], 4019 beforeSanitizeShadowDOM: [], 4020 uponSanitizeAttribute: [], 4021 uponSanitizeElement: [], 4022 uponSanitizeShadowNode: [] 4023 }; 4024 }; 4025 _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) { 4026 return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback; 4027 }; 4028 purify = createDOMPurify(); 4029 })); 4030 //#endregion 4031 //#region modules/payments/assets/js/frontend/handlers/stripe-button.js 4032 var stripe_button_exports = /* @__PURE__ */ __exportAll({ default: () => StripeHandler }); 4033 var StripeHandler; 4034 var init_stripe_button = __esmMin((() => { 4035 init_purify_es(); 4036 StripeHandler = class extends elementorModules.frontend.handlers.Base { 4037 getDefaultSettings() { 4038 return { selectors: { 4039 form: ".elementor-stripe-form", 4040 errors: ".elementor-message-danger" 4041 } }; 4042 } 4043 getDefaultElements() { 4044 const settings = this.getSettings(); 4045 return { 4046 form: this.$element[0].querySelector(settings.selectors.form), 4047 errors: this.$element[0].querySelectorAll(settings.selectors.errors), 4048 post_id: this.$element.closest("[data-elementor-id]").attr("data-elementor-id") 4049 }; 4050 } 4051 handleSubmit(event) { 4052 event.preventDefault(); 4053 if (elementorFrontend.isEditMode()) return; 4054 if (this.elements.errors.innerHTML !== "") document.querySelectorAll(".elementor-stripe-error-message").forEach((e) => e.remove()); 4055 const stripeForm = this.elements.form; 4056 const formData = new FormData(stripeForm); 4057 const ajaxurl = formData.get("url"); 4058 const action = formData.get("action"); 4059 const postId = parseInt(this.elements.post_id); 4060 const widgetId = formData.get("widget_id"); 4061 const customErrorMsg = formData.get("custom_error_msg"); 4062 const customErrorMsgGlobal = formData.get("custom_error_msg_global"); 4063 const customErrorMsgPayment = formData.get("custom_error_msg_payment"); 4064 const nonce = formData.get("stripe_form_submit_nonce"); 4065 const pageUrl = document.URL; 4066 const target = "yes" === formData.get("open_in_new_window") ? "_blank" : "_self"; 4067 const createErrorContainer = (errorMsg) => { 4068 const errorDiv = document.createElement("div"); 4069 const errorCont = stripeForm.appendChild(errorDiv); 4070 errorCont.className = "elementor-message elementor-stripe-error-message elementor-message-danger";
4071 errorCont.innerHTML = `${purify.sanitize(errorMsg)}`; 4072 }; 4073 const data = { 4074 action, 4075 postId, 4076 widgetId, 4077 pageUrl, 4078 nonce 4079 }; 4080 if (0 < this.elements.errors.length) this.elements.errors.forEach((error) => { 4081 error.classList.remove("elementor-hidden"); 4082 }); 4083 else jQuery.post(ajaxurl, { 4084 action, 4085 data 4086 }).done((response) => { 4087 const code = response.response.code; 4088 const result2 = response.body && JSON.parse(response.body); 4089 switch (code) { 4090 case 200: 4091 window.open(result2.url, target); 4092 break; 4093 case 401: 4094 case 403: 4095 if (customErrorMsg) createErrorContainer(customErrorMsgPayment); 4096 else createErrorContainer(result2.error.message); 4097 break; 4098 default: if (customErrorMsg) createErrorContainer(customErrorMsgGlobal); 4099 else createErrorContainer(result2.error.message); 4100 } 4101 }).fail(() => { 4102 if (customErrorMsg) createErrorContainer(customErrorMsgGlobal); 4103 else createErrorContainer(result.error.message); 4104 }); 4105 } 4106 bindEvents() { 4107 this.elements.form.addEventListener("submit", (e) => this.handleSubmit(e)); 4108 } 4109 }; 4110 })); 4111 //#endregion 4112 //#region modules/payments/assets/js/frontend/frontend.js 4113 var frontend_default$1 = class extends elementorModules.Module { 4114 static { 4115 __name(this, "default"); 4116 } 4117 constructor() { 4118 super(); 4119 elementorFrontend.elementsHandler.attachHandler("paypal-button", () => __vitePreload(() => Promise.resolve().then(() => (init_paypal_button(), paypal_button_exports)), void 0)); 4120 elementorFrontend.elementsHandler.attachHandler("stripe-button", () => __vitePreload(() => Promise.resolve().then(() => (init_stripe_button(), stripe_button_exports)), void 0)); 4121 } 4122 }; 4123 //#endregion 4124 //#region modules/progress-tracker/assets/js/frontend/handlers/circular-progress.js 4125 var CircularProgress; 4126 var init_circular_progress = __esmMin((() => { 4127 CircularProgress = class { 4128 constructor(element, settings) { 4129 this.settings = settings; 4130 this.lastKnownProgress = null; 4131 this.circularProgressTracker = element.find(".elementor-scrolling-tracker-circular")[0]; 4132 this.circularCurrentProgress = this.circularProgressTracker.getElementsByClassName("current-progress")[0]; 4133 this.circularCurrentProgressPercentage = this.circularProgressTracker.getElementsByClassName("current-progress-percentage")[0]; 4134 const circumference = this.circularCurrentProgress.r.baseVal.value * 2 * Math.PI; 4135 this.circularCurrentProgress.style.strokeDasharray = `${circumference} ${circumference}`; 4136 this.circularCurrentProgress.style.strokeDashoffset = circumference; 4137 this.elements = this.cacheElements(); 4138 this.resizeObserver = new ResizeObserver(() => { 4139 if (this.lastKnownProgress) this.updateProgress(this.lastKnownProgress); 4140 }); 4141 this.resizeObserver.observe(this.circularProgressTracker); 4142 } 4143 cacheElements() { 4144 return { 4145 circularProgressTracker: this.circularProgressTracker, 4146 circularCurrentProgress: this.circularCurrentProgress, 4147 circularCurrentProgressPercentage: this.circularCurrentProgressPercentage 4148 }; 4149 } 4150 updateProgress(progress) { 4151 if (progress <= 0) { 4152 this.elements.circularCurrentProgress.style.display = "none"; 4153 this.elements.circularCurrentProgressPercentage.style.display = "none"; 4154 return; 4155 } 4156 this.elements.circularCurrentProgress.style.display = "block"; 4157 this.elements.circularCurrentProgressPercentage.style.display = "block"; 4158 const circumference = this.elements.circularCurrentProgress.r.baseVal.value * 2 * Math.PI; 4159 const offset = circumference - progress / 100 * circumference; 4160 this.lastKnownProgress = progress; 4161 this.elements.circularCurrentProgress.style.strokeDasharray = `${circumference} ${circumference}`; 4162 this.elements.circularCurrentProgress.style.strokeDashoffset = "ltr" === this.settings.direction ? -offset : offset; 4163 if ("yes" === this.settings.percentage) this.elements.circularCurrentProgressPercentage.innerHTML = Math.round(progress) + "%"; 4164 } 4165 onDestroy() { 4166 this.resizeObserver.unobserve(this.circularProgressTracker); 4167 } 4168 }; 4169 })); 4170 //#endregion 4171 //#region modules/progress-tracker/assets/js/frontend/handlers/linear-progress.js 4172 var LinearProgress; 4173 var init_linear_progress = __esmMin((() => { 4174 LinearProgress = class { 4175 constructor(element, settings) { 4176 this.settings = settings; 4177 this.linearProgressTracker = element.find(".elementor-scrolling-tracker-horizontal")[0]; 4178 this.linearCurrentProgress = this.linearProgressTracker.getElementsByClassName("current-progress")[0]; 4179 this.linearCurrentProgressPercentage = this.linearProgressTracker.getElementsByClassName("current-progress-percentage")[0]; 4180 this.elements = this.cacheElements(); 4181 } 4182 cacheElements() { 4183 return { 4184 linearProgressTracker: this.linearProgressTracker, 4185 linearCurrentProgress: this.linearCurrentProgress, 4186 linearCurrentProgressPercentage: this.linearCurrentProgressPercentage 4187 }; 4188 } 4189 updateProgress(progress) { 4190 if (progress < 1) { 4191 this.elements.linearCurrentProgress.style.display = "none"; 4192 return; 4193 } 4194 this.elements.linearCurrentProgress.style.display = "flex"; 4195 this.elements.linearCurrentProgress.style.width = progress + "%"; 4196 if ("yes" === this.settings.percentage && this.elements.linearCurrentProgress.getBoundingClientRect().width > this.elements.linearCurrentProgressPercentage.getBoundingClientRect().width * 1.5) { 4197 this.elements.linearCurrentProgressPercentage.innerHTML = Math.round(progress) + "%"; 4198 this.elements.linearCurrentProgressPercentage.style.color = getComputedStyle(this.linearCurrentProgress).getPropertyValue("--percentage-color"); 4199 } else this.elements.linearCurrentProgressPercentage.style.color = "transparent";
4200 } 4201 }; 4202 })); 4203 //#endregion 4204 //#region modules/progress-tracker/assets/js/frontend/handlers/progress-tracker.js 4205 var progress_tracker_exports = /* @__PURE__ */ __exportAll({ default: () => ProgressTracker }); 4206 var ProgressTracker; 4207 var init_progress_tracker = __esmMin((() => { 4208 init_circular_progress(); 4209 init_linear_progress(); 4210 ProgressTracker = class extends elementorModules.frontend.handlers.Base { 4211 onInit() { 4212 elementorModules.frontend.handlers.Base.prototype.onInit.apply(this, arguments); 4213 this.circular = "circular" === this.getElementSettings().type; 4214 const Handler = this.circular ? CircularProgress : LinearProgress; 4215 this.progressBar = new Handler(this.$element, this.getElementSettings()); 4216 this.progressPercentage = 0; 4217 this.scrollHandler(); 4218 this.handler = this.scrollHandler.bind(this); 4219 this.initListeners(); 4220 } 4221 getTrackingElementSelector() { 4222 const trackingElementSetting = this.getElementSettings().relative_to; 4223 let selector; 4224 switch (trackingElementSetting) { 4225 case "selector": 4226 selector = jQuery(this.getElementSettings().selector); 4227 break; 4228 case "post_content": 4229 selector = jQuery(".elementor-widget-theme-post-content"); 4230 break; 4231 default: 4232 selector = this.isScrollSnap() ? jQuery("#e-scroll-snap-container") : elementorFrontend.elements.$body; 4233 break; 4234 } 4235 return selector; 4236 } 4237 isScrollSnap() { 4238 return "yes" === (this.isEdit ? elementor.settings.page.model.attributes.scroll_snap : elementorFrontend.config.settings.page.scroll_snap) ? true : false; 4239 } 4240 addScrollSnapContainer() { 4241 if (this.isScrollSnap() && !jQuery("#e-scroll-snap-container").length) jQuery("body").wrapInner("<div id=\"e-scroll-snap-container\" />"); 4242 } 4243 scrollHandler() { 4244 this.addScrollSnapContainer(); 4245 const $trackingElementSelector = this.getTrackingElementSelector(); 4246 const scrollStartPercentage = $trackingElementSelector.is(elementorFrontend.elements.$body) || $trackingElementSelector.is(jQuery("#e-scroll-snap-container")) ? -100 : 0; 4247 this.progressPercentage = elementorModules.utils.Scroll.getElementViewportPercentage(this.getTrackingElementSelector(), { 4248 start: scrollStartPercentage, 4249 end: -100 4250 }); 4251 this.progressBar.updateProgress(this.progressPercentage); 4252 } 4253 initListeners() { 4254 window.addEventListener("scroll", this.handler); 4255 elementorFrontend.elements.$body[0].addEventListener("scroll", this.handler); 4256 } 4257 onDestroy() { 4258 if (this.progressBar.onDestroy) this.progressBar.onDestroy(); 4259 window.removeEventListener("scroll", this.handler); 4260 elementorFrontend.elements.$body[0].removeEventListener("scroll", this.handler); 4261 } 4262 }; 4263 })); 4264 //#endregion 4265 //#region modules/progress-tracker/assets/js/frontend/frontend.js 4266 var frontend_default = class extends elementorModules.Module { 4267 static { 4268 __name(this, "default"); 4269 } 4270 constructor() { 4271 super(); 4272 elementorFrontend.elementsHandler.attachHandler("progress-tracker", () => __vitePreload(() => Promise.resolve().then(() => (init_progress_tracker(), progress_tracker_exports)), void 0)); 4273 } 4274 }; 4275 //#endregion 4276 //#region assets/dev/js/frontend/utils/controls.js 4277 var Controls = class { 4278 /** 4279 * Get Control Value 4280 * 4281 * Retrieves a control value. 4282 * This function has been copied from `elementor/assets/dev/js/editor/utils/conditions.js`. 4283 * 4284 * @since 3.11.0 4285 * 4286 * @param {{}} controlSettings A settings object (e.g. element settings - keys and values) 4287 * @param {string} controlKey The control key name 4288 * @param {string} controlSubKey A specific property of the control object. 4289 * @return {*} Control Value 4290 */ 4291 getControlValue(controlSettings, controlKey, controlSubKey) { 4292 let value; 4293 if ("object" === typeof controlSettings[controlKey] && controlSubKey) value = controlSettings[controlKey][controlSubKey]; 4294 else value = controlSettings[controlKey]; 4295 return value; 4296 } 4297 /** 4298 * Get the value of a responsive control. 4299 * 4300 * Retrieves the value of a responsive control for the current device or for this first parent device which has a control value. 4301 * 4302 * @since 3.11.0 4303 * 4304 * @param {{}} controlSettings A settings object (e.g. element settings - keys and values) 4305 * @param {string} controlKey The control key name 4306 * @param {string} controlSubKey A specific property of the control object. 4307 * @return {*} Control Value 4308 */ 4309 getResponsiveControlValue(controlSettings, controlKey, controlSubKey = "") { 4310 const currentDeviceMode = elementorFrontend.getCurrentDeviceMode(); 4311 const controlValueDesktop = this.getControlValue(controlSettings, controlKey, controlSubKey); 4312 if ("widescreen" === currentDeviceMode) { 4313 const controlValueWidescreen = this.getControlValue(controlSettings, `${controlKey}_widescreen`, controlSubKey); 4314 return !!controlValueWidescreen || 0 === controlValueWidescreen ? controlValueWidescreen : controlValueDesktop; 4315 } 4316 const activeBreakpoints = elementorFrontend.breakpoints.getActiveBreakpointsList({ withDesktop: true }); 4317 let parentDeviceMode = currentDeviceMode; 4318 let deviceIndex = activeBreakpoints.indexOf(currentDeviceMode); 4319 let controlValue = ""; 4320 while (deviceIndex <= activeBreakpoints.length) { 4321 if ("desktop" === parentDeviceMode) { 4322 controlValue = controlValueDesktop; 4323 break; 4324 } 4325 const responsiveControlKey = `${controlKey}_${parentDeviceMode}`; 4326 const responsiveControlValue = this.getControlValue(controlSettings, responsiveControlKey, controlSubKey); 4327 if (!!responsiveControlValue || 0 === responsiveControlValue) { 4328 controlValue = responsiveControlValue; 4329 break; 4330 } 4331 deviceIndex++; 4332 parentDeviceMode = activeBreakpoints[deviceIndex]; 4333 } 4334 return controlValue; 4335 } 4336 }; 4337 //#endregion 4338 //#region assets/dev/js/frontend/utils/dropdown-menu-height-controller.js
4339 var DropdownMenuHeightController = class { 4340 constructor(widgetConfig) { 4341 this.widgetConfig = widgetConfig; 4342 } 4343 calculateStickyMenuNavHeight() { 4344 this.widgetConfig.elements.$dropdownMenuContainer.css(this.widgetConfig.settings.menuHeightCssVarName, ""); 4345 const menuToggleHeight = this.widgetConfig.elements.$dropdownMenuContainer.offset().top - jQuery(window).scrollTop(); 4346 return elementorFrontend.elements.$window.height() - menuToggleHeight; 4347 } 4348 calculateMenuTabContentHeight($tab) { 4349 return elementorFrontend.elements.$window.height() - $tab[0].getBoundingClientRect().top; 4350 } 4351 isElementSticky() { 4352 return this.widgetConfig.elements.$element.hasClass("elementor-sticky") || this.widgetConfig.elements.$element.parents(".elementor-sticky").length; 4353 } 4354 getMenuHeight() { 4355 return this.isElementSticky() ? this.calculateStickyMenuNavHeight() + "px" : this.widgetConfig.settings.dropdownMenuContainerMaxHeight; 4356 } 4357 setMenuHeight(menuHeight) { 4358 this.widgetConfig.elements.$dropdownMenuContainer.css(this.widgetConfig.settings.menuHeightCssVarName, menuHeight); 4359 } 4360 reassignMobileMenuHeight() { 4361 const menuHeight = this.isToggleActive() ? this.getMenuHeight() : 0; 4362 return this.setMenuHeight(menuHeight); 4363 } 4364 reassignMenuHeight($activeTabContent) { 4365 if (!this.isElementSticky() || 0 === $activeTabContent.length) return; 4366 const offsetBottom = elementorFrontend.elements.$window.height() - $activeTabContent[0].getBoundingClientRect().top; 4367 if (!($activeTabContent.height() > offsetBottom)) return; 4368 $activeTabContent.css("height", this.calculateMenuTabContentHeight($activeTabContent) + "px"); 4369 $activeTabContent.css("overflow-y", "scroll"); 4370 } 4371 resetMenuHeight($activeTabContent) { 4372 if (!this.isElementSticky()) return; 4373 $activeTabContent.css("height", "initial"); 4374 $activeTabContent.css("overflow-y", "visible"); 4375 } 4376 isToggleActive() { 4377 var _this$widgetConfig$at; 4378 const $menuToggle = this.widgetConfig.elements.$menuToggle; 4379 if (!!((_this$widgetConfig$at = this.widgetConfig.attributes) === null || _this$widgetConfig$at === void 0 ? void 0 : _this$widgetConfig$at.menuToggleState)) return "true" === $menuToggle.attr(this.widgetConfig.attributes.menuToggleState); 4380 return $menuToggle.hasClass(this.widgetConfig.classes.menuToggleActiveClass); 4381 } 4382 }; 4383 //#endregion 4384 //#region assets/dev/js/frontend/frontend.js 4385 var ElementorProFrontend = class extends elementorModules.ViewModule { 4386 onInit() { 4387 super.onInit(); 4388 this.config = ElementorProFrontendConfig; 4389 this.modules = {}; 4390 this.initOnReadyComponents(); 4391 } 4392 bindEvents() { 4393 jQuery(window).on("elementor/frontend/init", this.onElementorFrontendInit.bind(this)); 4394 } 4395 initModules() { 4396 let handlers = { 4397 motionFX: frontend_default$5, 4398 sticky: frontend_default$4, 4399 codeHighlight: frontend_default$3, 4400 videoPlaylist: frontend_default$2, 4401 payments: frontend_default$1, 4402 progressTracker: frontend_default 4403 }; 4404 elementorProFrontend.trigger("elementor-pro/modules/init/before"); 4405 handlers = elementorFrontend.hooks.applyFilters("elementor-pro/frontend/handlers", handlers); 4406 jQuery.each(handlers, (moduleName, ModuleClass) => { 4407 this.modules[moduleName] = new ModuleClass(); 4408 }); 4409 this.modules.linkActions = { addAction: (...args) => { 4410 elementorFrontend.utils.urlActions.addAction(...args); 4411 } }; 4412 } 4413 onElementorFrontendInit() { 4414 this.initModules(); 4415 } 4416 initOnReadyComponents() { 4417 this.utils = { 4418 controls: new Controls(), 4419 DropdownMenuHeightController 4420 }; 4421 } 4422 }; 4423 window.elementorProFrontend = new ElementorProFrontend(); 4424 //#endregion 4425})(); 4426 4427//# sourceMappingURL=frontend.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.