text-path.9b3ece1b692d34d012b5.bundle.js (6841B)
1 /*! elementor - v3.4.4 - 13-09-2021 */ 2 (self["webpackChunkelementor"] = self["webpackChunkelementor"] || []).push([["text-path"],{ 3 4 /***/ "../modules/shapes/assets/js/frontend/handlers/text-path.js": 5 /*!******************************************************************!*\ 6 !*** ../modules/shapes/assets/js/frontend/handlers/text-path.js ***! 7 \******************************************************************/ 8 /***/ ((__unused_webpack_module, exports, __webpack_require__) => { 9 10 "use strict"; 11 12 13 Object.defineProperty(exports, "__esModule", ({ 14 value: true 15 })); 16 exports.default = void 0; 17 18 var _utils = __webpack_require__(/*! elementor-frontend/utils/utils */ "../assets/dev/js/frontend/utils/utils.js"); 19 20 class TextPathHandler extends elementorModules.frontend.handlers.Base { 21 getDefaultSettings() { 22 return { 23 selectors: { 24 pathContainer: '.e-text-path', 25 svg: '.e-text-path > svg' 26 } 27 }; 28 } 29 30 getDefaultElements() { 31 const { 32 selectors 33 } = this.getSettings(); 34 const element = this.$element[0]; 35 return { 36 widgetWrapper: element, 37 pathContainer: element.querySelector(selectors.pathContainer), 38 svg: element.querySelector(selectors.svg), 39 textPath: element.querySelector(selectors.textPath) 40 }; 41 } 42 /** 43 * Initialize the object. 44 * 45 * @returns {void} 46 */ 47 48 49 onInit() { 50 this.elements = this.getDefaultElements(); // Generate unique IDs using the wrapper's `data-id`. 51 52 this.pathId = `e-path-${this.elements.widgetWrapper.dataset.id}`; 53 this.textPathId = `e-text-path-${this.elements.widgetWrapper.dataset.id}`; 54 55 if (!this.elements.svg) { 56 return; 57 } 58 59 this.initTextPath(); 60 } 61 /** 62 * Gets a text offset (relative to the starting point) as a string or int, and set it as percents to the 63 * `startOffset` attribute of the `<textPath>` element. 64 * 65 * @param offset {string|int} The text start offset. 66 * 67 * @returns {void} 68 */ 69 70 71 setOffset(offset) { 72 if (!this.elements.textPath) { 73 return; 74 } 75 76 if (this.isRTL()) { 77 offset = 100 - parseInt(offset); 78 } 79 80 this.elements.textPath.setAttribute('startOffset', offset + '%'); 81 } 82 /** 83 * Handle element settings changes. 84 * 85 * @param setting {Object} The settings object from the editor. 86 * 87 * @returns {void} 88 */ 89 90 91 onElementChange(setting) { 92 const { 93 start_point: startPoint, 94 text 95 } = this.getElementSettings(); 96 97 switch (setting) { 98 case 'start_point': 99 this.setOffset(startPoint.size); 100 break; 101 102 case 'text': 103 this.setText(text); 104 break; 105 106 case 'text_path_direction': 107 this.setOffset(startPoint.size); 108 this.setText(text); 109 break; 110 111 default: 112 break; 113 } 114 } 115 /** 116 * Attach a unique ID to the `path` element in the SVG, based on the container's ID. 117 * This function selects the first `path` with a `data-path-anchor` attribute, or defaults to the first `path` element. 118 * 119 * @returns {void} 120 */ 121 122 123 attachIdToPath() { 124 // Prioritize the custom `data` attribute over the `path` element, and fallback to the first `path`. 125 const path = this.elements.svg.querySelector('[data-path-anchor]') || this.elements.svg.querySelector('path'); 126 path.id = this.pathId; 127 } 128 /** 129 * Initialize & build the SVG markup of the widget using the settings from the panel. 130 * 131 * @returns {void} 132 */ 133 134 135 initTextPath() { 136 const { 137 start_point: startPoint 138 } = this.getElementSettings(); 139 const text = this.elements.pathContainer.dataset.text; 140 this.attachIdToPath(); // Generate the `textPath` element with its settings. 141 142 this.elements.svg.innerHTML += ` 143 <text> 144 <textPath id="${this.textPathId}" href="#${this.pathId}"></textPath> 145 </text> 146 `; // Regenerate the elements object to have access to `this.elements.textPath`. 147 148 this.elements.textPath = this.elements.svg.querySelector(`#${this.textPathId}`); 149 this.setOffset(startPoint.size); 150 this.setText(text); 151 } 152 /** 153 * Sets the text on the SVG path, including the link (if set) and its properties. 154 * 155 * @param newText {string} The new text to put in the text path. 156 * 157 * @returns {void} 158 */ 159 160 161 setText(newText) { 162 var _this$getElementSetti; 163 164 const { 165 url, 166 is_external: isExternal, 167 nofollow 168 } = (_this$getElementSetti = this.getElementSettings()) === null || _this$getElementSetti === void 0 ? void 0 : _this$getElementSetti.link; 169 const target = isExternal ? '_blank' : '', 170 rel = nofollow ? 'nofollow' : ''; // Add link attributes. 171 172 if (url) { 173 newText = `<a href="${(0, _utils.escapeHTML)(url)}" rel="${rel}" target="${target}">${(0, _utils.escapeHTML)(newText)}</a>`; 174 } // Set the text. 175 176 177 this.elements.textPath.innerHTML = newText; // Remove the cloned element if exists. 178 179 const existingClone = this.elements.svg.querySelector(`#${this.textPathId}-clone`); 180 181 if (existingClone) { 182 existingClone.remove(); 183 } // Reverse the text if needed. 184 185 186 if (this.shouldReverseText()) { 187 // Keep an invisible selectable copy of original element for better a11y. 188 const clone = this.elements.textPath.cloneNode(); 189 clone.id += '-clone'; 190 clone.classList.add('elementor-hidden'); 191 clone.textContent = newText; 192 this.elements.textPath.parentNode.appendChild(clone); 193 this.reverseToRTL(); 194 } 195 } 196 /** 197 * Determine if the text direction of the widget should be RTL or not, based on the site direction and the widget's settings. 198 * 199 * @returns {boolean} 200 */ 201 202 203 isRTL() { 204 const { 205 text_path_direction: direction 206 } = this.getElementSettings(); 207 let isRTL = elementorFrontend.config.is_rtl; 208 209 if (direction) { 210 isRTL = 'rtl' === direction; 211 } 212 213 return isRTL; 214 } 215 /** 216 * Determine if it should RTL the text (reversing it, etc.). 217 * 218 * @returns {boolean} 219 */ 220 221 222 shouldReverseText() { 223 return this.isRTL() && -1 === navigator.userAgent.indexOf('Firefox'); 224 } 225 /** 226 * Reverse the text path to support RTL. 227 * 228 * @returns {void} 229 */ 230 231 232 reverseToRTL() { 233 // Make sure to use the inner `a` tag if exists. 234 let parentElement = this.elements.textPath; 235 parentElement = parentElement.querySelector('a') || parentElement; // Catch all RTL chars and reverse their order. 236 237 const pattern = /([\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC\s$&+,:;=?@#|'<>.^*()%!-]+)/ig; // Reverse the text. 238 239 parentElement.textContent = parentElement.textContent.replace(pattern, word => { 240 return word.split('').reverse().join(''); 241 }); // Add a11y attributes. 242 243 parentElement.setAttribute('aria-hidden', true); 244 } 245 246 } 247 248 exports.default = TextPathHandler; 249 250 /***/ }) 251 252 }]); 253 //# sourceMappingURL=text-path.9b3ece1b692d34d012b5.bundle.js.map