import document from 'global/document';
import HT from '../HT';
import { getPlainText, isChildren, checkException } from '../utils';
import 'style-loader!css-loader!sass-loader!../style/hover.scss';
import hoverCssCode from 'css-to-string-loader!css-loader!../style/hover.scss';
import { EventEmitter } from 'events';
class TextManager extends EventEmitter {
ht = null;
hasMoved = false;
addedListeners = false;
constructor(ht) {
super();
this.ht = ht;
}
_activated = false;
get activated() { return this._activated; }
set activated(value) {
this._activated = value;
if (value) {
// Faz a checagem dos iframes apenas uma vez
if (!this.addedListeners) {
// Adiciona os event Listeners no frame principal
this.addEventListeners(document);
this.addedListeners = true;
}
this.ht.emit('activated', 'textManager');
}
}
/**
* Captura o texto de um elemento, caso seja imagem captura o alt
* @param elem - Elemento a ter o texto capturado
*/
getText = (elem) => {
const { tagName } = elem;
const { exceptions } = this.ht.config;
const lowerTagName = (tagName || '').toLowerCase();
// Verifica se o ElementInspector está ativado
if (!this.activated) {
this.ht.logger.debug('TextManager desativado');
return false;
}
// Verifica se o elemento está na lista de exceções
if (!checkException(exceptions, elem)) {
this.ht.logger.debug('Elemento é uma exceção');
return false;
}
// Verifica se o elemento está na lista de tags proibidas
if (lowerTagName && HT.skipTags.indexOf(lowerTagName) >= 0) {
this.ht.logger.debug('Tag do elemento é', lowerTagName);
return false;
}
// Caso elemento seja uma imagem iremos fazer a tradução do ALT
if (lowerTagName === 'img') {
const imgText = elem.getAttribute('data-ht-alt') || elem.getAttribute('alt');
return this.checkTextSize(imgText) ? imgText : false;
}
// Elemento de texto padrão (span, p, div, ...)
if (!this.checkTextSize(elem.innerText)) return false;
// Verifica se o elemento é filho de um .ht-skip
if (isChildren(elem, '.ht-skip')) {
this.ht.logger.debug('Elemento tem ou é filho de um .ht-skip', lowerTagName);
return false;
}
const plainText = getPlainText(elem);
return this.checkTextSize(plainText) ? plainText : false;
};
/**
* Verifica se a quantidade de caracteres é menor que o estipulado e maior que 0
* @param {String} text - Texto a ter o tamanho verificado.
* @returns {Boolean}
*/
checkTextSize = (text) => {
if (text.length > 0 && text.length < this.ht.config.maxTextSize) return true;
this.ht.logger.debug('O Elemento possui muitos ou nenhum caractere dentro do texto', text.length);
return false;
}
/**
* Quando o mouse passa sobre um elemento -
* Document ou iframe.contentDocument do elemento
* precisa estar vinculado por this.addEventListeners().
*/
onMouseOver = ({ target }) => {
if (this.activated && this.getText(target)) this.emit('validElementOver', target);
};
/**
* Quando o mouse sai de um elemento -
* Document ou iframe.contentDocument do elemento
* precisa estar vinculado por this.addEventListeners().
*/
onMouseOut = ({ target }) => {
if (this.activated) this.emit('validElementOut', target);
};
/**
* Quando um elemento é clicado -
* Document ou iframe.contentDocument do elemento
* precisa estar vinculado por this.addEventListeners().
*/
onClick = (e) => {
if (!this.activated) return false;
const { target } = e;
const text = this.getText(target, true);
if (!text) return false;
this.emit('validElementClicked', e, text);
e.stopPropagation();
e.preventDefault();
};
/** Quando o touch está se movendo */
onTouchMove = () => {
if (this.activated) this.hasMoved = true;
};
/** Quando o touch sai da tela */
onTouchEnd = (e) => {
if (!this.activated) return false;
if (!this.hasMoved) this.onClick(e);
this.hasMoved = false;
}
/**
* Adiciona os EventListeners em um frame especifico
* @param frame - Frame que receberá os EventListeners.
*/
addEventListeners = (frame) => {
if (HT.deviceInfo.isMobile) {
frame.addEventListener('touchmove', this.onTouchMove, true);
frame.addEventListener('touchend', this.onTouchEnd, true);
} else {
frame.addEventListener('mouseover', this.onMouseOver);
frame.addEventListener('mouseout', this.onMouseOut);
frame.addEventListener('click', this.onClick, true);
}
this.ht.logger.info('EventListeners adicionados no frame', frame);
}
/**
* Adiciona o css de hover em um iframe
* @param iframe - Frame alvo
*/
addExtraStyle = (iframe) => {
const head = iframe.contentDocument.head || iframe.contentDocument.querySelector('head');
const styleElem = iframe.contentDocument.createElement('style');
styleElem.type = 'text/css';
styleElem.appendChild(iframe.contentDocument.createTextNode(hoverCssCode));
head.appendChild(styleElem);
}
/**
* Adiciona os EventListeners em um iframe especifico
* @param iframe - iframe que receberá os listeners
*/
addIframeListeners = (iframe) => {
if (!iframe.getAttribute('data-ht-bindedevents')) {
this.addEventListeners(iframe.contentDocument);
this.addExtraStyle(iframe);
iframe.setAttribute('data-ht-bindedevents', true);
} else this.ht.logger.info('Ignorando iframe que ja possui os Event Listeners', iframe);
}
/**
* Adiciona EventListener nos frames encontrados com o atributo data-ht-bindedevents = false
*/
addIframesListenersAll = () => {
Array.prototype.forEach.bind(document.body.querySelectorAll('iframe'))((iframe) => {
try {
this.addIframeListeners(iframe);
} catch (e) {
this.ht.logger.warn('Falha ao adicionar EventListener no iframe ' + e);
}
});
};
/**
* Remove os EventListeners de um frame especifico - Desktop e Mobile.
* @param frame - Frame que terá os Event Listeners removidos.
*/
removeEventListener = (frame) => {
if (HT.deviceInfo.isMobile) {
frame.removeEventListener('touchmove', this.onTouchMove, true);
frame.removeEventListener('touchend', this.onTouchEnd, true);
} else {
frame.removeEventListener('mouseover', this.onMouseOver);
frame.removeEventListener('mouseout', this.onMouseOut);
frame.removeEventListener('click', this.onClick, true);
}
}
destroy = () => {
this.removeEventListener(document);
Array.prototype.forEach.bind(document.body.querySelectorAll('iframe'))((iframe) => {
try {
this.removeEventListener(iframe.contentDocument);
iframe.removeAttribute('data-ht-bindedevents');
} catch (e) {
this.ht.logger.warn('Falha ao remover EventListener no iframe ' + e);
}
});
this.activated = false;
this.ht.logger.info('TextManager destruido');
};
}
export default TextManager;