| 1 |
/** |
| 2 |
* Wrapper Link — makes a whole container clickable. |
| 3 |
* |
| 4 |
* The wrapper only acts when the click was not meant for something inside it. |
| 5 |
* A link, a button or a form control inside the container has to keep working |
| 6 |
* on its own; letting both fire sends the visitor to two places at once. |
| 7 |
*/ |
| 8 |
(function () { |
| 9 |
'use strict'; |
| 10 |
|
| 11 |
var WRAPPER_SELECTOR = '[data-kng-wrapper-link]'; |
| 12 |
|
| 13 |
/** |
| 14 |
* Things a visitor can click on purpose. A click that starts on any of |
| 15 |
* these belongs to that element, not to the wrapper around it. |
| 16 |
*/ |
| 17 |
var INTERACTIVE_SELECTOR = [ |
| 18 |
'a[href]', |
| 19 |
'button', |
| 20 |
'input', |
| 21 |
'select', |
| 22 |
'textarea', |
| 23 |
'label', |
| 24 |
'summary', |
| 25 |
'video', |
| 26 |
'audio', |
| 27 |
'iframe', |
| 28 |
'[role="button"]', |
| 29 |
'[role="link"]', |
| 30 |
'[role="tab"]', |
| 31 |
'[contenteditable="true"]', |
| 32 |
'[data-kng-wrapper-link]' |
| 33 |
].join(','); |
| 34 |
|
| 35 |
function closest(node, selector) { |
| 36 |
if (!node) { |
| 37 |
return null; |
| 38 |
} |
| 39 |
if (typeof node.closest === 'function') { |
| 40 |
return node.closest(selector); |
| 41 |
} |
| 42 |
// Very old browsers: walk up by hand. |
| 43 |
var el = node.nodeType === 1 ? node : node.parentElement; |
| 44 |
while (el) { |
| 45 |
if (el.matches && el.matches(selector)) { |
| 46 |
return el; |
| 47 |
} |
| 48 |
el = el.parentElement; |
| 49 |
} |
| 50 |
return null; |
| 51 |
} |
| 52 |
|
| 53 |
function hasTextSelection() { |
| 54 |
try { |
| 55 |
var selection = window.getSelection(); |
| 56 |
return !!selection && String(selection).trim().length > 0; |
| 57 |
} catch (e) { |
| 58 |
return false; |
| 59 |
} |
| 60 |
} |
| 61 |
|
| 62 |
function onClick(event) { |
| 63 |
// Only plain left clicks navigate; the rest is the browser's business. |
| 64 |
if (event.defaultPrevented || (typeof event.button === 'number' && event.button !== 0)) { |
| 65 |
return; |
| 66 |
} |
| 67 |
|
| 68 |
var wrapper = closest(event.target, WRAPPER_SELECTOR); |
| 69 |
if (!wrapper) { |
| 70 |
return; |
| 71 |
} |
| 72 |
|
| 73 |
// Editing the page should not navigate away from it. |
| 74 |
if (document.body && document.body.classList.contains('elementor-editor-active')) { |
| 75 |
return; |
| 76 |
} |
| 77 |
|
| 78 |
// The click landed on something clickable in its own right — or on a |
| 79 |
// nested wrapper, which owns the click instead of this one. |
| 80 |
var inner = closest(event.target, INTERACTIVE_SELECTOR); |
| 81 |
if (inner && inner !== wrapper) { |
| 82 |
return; |
| 83 |
} |
| 84 |
|
| 85 |
// Selecting text inside the container is not a request to leave it. |
| 86 |
if (hasTextSelection()) { |
| 87 |
return; |
| 88 |
} |
| 89 |
|
| 90 |
var url = wrapper.getAttribute('data-kng-wrapper-link'); |
| 91 |
if (!url) { |
| 92 |
return; |
| 93 |
} |
| 94 |
|
| 95 |
var target = wrapper.getAttribute('data-kng-wrapper-link-target') || '_self'; |
| 96 |
|
| 97 |
// Behave like a real link under the modifier keys people expect. |
| 98 |
if (target === '_blank' || event.metaKey || event.ctrlKey || event.shiftKey) { |
| 99 |
window.open(url, '_blank', 'noopener'); |
| 100 |
return; |
| 101 |
} |
| 102 |
|
| 103 |
window.location.href = url; |
| 104 |
} |
| 105 |
|
| 106 |
document.addEventListener('click', onClick, false); |
| 107 |
}()); |
| 108 |
|