| 11 | } |
| 12 | |
| 13 | function detectAndMark(el, opts) { |
| 14 | const marker = opts.marker |
| 15 | const kinds = opts.kinds |
| 16 | const CE = '[contenteditable="true"], [contenteditable=""]' |
| 17 | |
| 18 | function mark(kind, target) { |
| 19 | document.querySelectorAll('[' + marker + ']').forEach(n => n.removeAttribute(marker)) |
| 20 | if (target && target.nodeType === 1) target.setAttribute(marker, '1') |
| 21 | return kind |
| 22 | } |
| 23 | |
| 24 | if (!el || el.nodeType !== 1) return mark(kinds.STANDARD, el) |
| 25 | |
| 26 | const tag = el.tagName |
| 27 | if (tag === 'IFRAME') return mark(kinds.IFRAME, el) |
| 28 | if (el.isContentEditable) return mark(kinds.CONTENTEDITABLE, el) |
| 29 | |
| 30 | const isFormHidden = tag === 'INPUT' && el.type === 'hidden' |
| 31 | if ((tag === 'INPUT' || tag === 'TEXTAREA') && !isFormHidden) { |
| 32 | const style = window.getComputedStyle(el) |
| 33 | if (style.display === 'none') return mark(kinds.UNREACHABLE, el) |
| 34 | } |
| 35 | |
| 36 | const canSearchDescendants = tag !== 'INPUT' && tag !== 'TEXTAREA' |
| 37 | if (canSearchDescendants) { |
| 38 | const iframe = el.querySelector('iframe') |
| 39 | if (iframe) return mark(kinds.IFRAME, iframe) |
| 40 | const ce = el.querySelector(CE) |
| 41 | if (ce) return mark(kinds.CONTENTEDITABLE, ce) |
| 42 | const textareas = [...el.querySelectorAll('textarea')] |
| 43 | const focusable = textareas.find(t => window.getComputedStyle(t).display !== 'none') |
| 44 | const textarea = focusable || textareas[0] |
| 45 | if (textarea) return mark(kinds.HIDDEN_TEXTAREA, textarea) |
| 46 | } |
| 47 | |
| 48 | return mark(kinds.STANDARD, el) |
| 49 | } |
| 50 | |
| 51 | function detectInsideFrame() { |
| 52 | const MARKER = 'data-codeceptjs-rte-target' |