Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tml-js-browser

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tml-js-browser - npm Package Compare versions

Comparing version 0.4.26 to 0.4.28

lib/helpers/dom-helpers.js

28

lib/helpers.js

@@ -65,30 +65,2 @@ /**

includeTools: function(app, locale, callback) {
utils.addCSS(window.document, app.tools.stylesheet, false);
utils.addCSS(window.document, app.css, true);
utils.addJS(window.document, 'tml-jssdk', app.tools.javascript, function() {
Tml.app_key = app.key;
Tml.host = app.tools.host;
Tml.current_source = app.current_source;
Tml.default_locale = app.default_locale;
Tml.page_locale = locale;
Tml.locale = locale;
var shortcutFn = function(sc){
return function() {
eval(app.shortcuts[sc]); // jshint ignore:line
};
};
if (app.isFeatureEnabled("shortcuts")) {
for (var sc in app.shortcuts) {
shortcut.add(sc, shortcutFn(sc));
}
}
if (callback) callback();
});
},
includeAgent: function(app, options, callback) {

@@ -95,0 +67,0 @@ var agent_host = options.host || "https://tools.translationexchange.com/agent/stable/agent.min.js";

890

lib/index.js

@@ -34,506 +34,554 @@ /**

var tml = require('tml-js');
var helpers = require('./helpers');
var DomTokenizer = require('./tokenizers/dom');
(function (root, factory) {
function addToRoot(result) {
//for backwards compatibility - always copy everything to global object
if (root) {
var DEFAULT_HOST = "https://api.translationexchange.com";
var mutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
for (var key in result) {
if (result.hasOwnProperty(key)) {
root[key] = result[key];
}
}
}
}
tml = tml.utils.extend(tml, {
version: '/* @echo VERSION */',
if (typeof define === 'function' && define.amd) {
//console.log('amd load');
define([], factory);
}
else if (typeof exports === 'object') {
//console.log('exports load', module);
module.exports = factory();
addToRoot(module.exports);
}
else {
//console.log('global load');
addToRoot(factory());
}
}(window, function () {
app: null,
block_options: [],
root_element: null,
options: {},
var tml = require('tml-js');
var helpers = require('./helpers');
var DomTokenizer = require('./tokenizers/dom');
var Emitter = require('tiny-emitter');
var emitter = new Emitter();
/**
* Initializes TML library
* @param options
* @param callback
*/
init: function(options, callback) {
options = options || {};
var DEFAULT_HOST = "https://api.translationexchange.com";
var mutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
tml.options = options;
tml.config.debug = (options.debug ? options.debug : tml.config.debug);
tml = tml.utils.extend(tml, {
version: '/* @echo VERSION */',
options.preferred_languages = options.preferred_languages || helpers.getBrowserLanguages();
on: emitter.on.bind(emitter),
off: emitter.off.bind(emitter),
once: emitter.once.bind(emitter),
emit: emitter.emit.bind(emitter),
if (tml.config.debug || options.info)
helpers.printWelcomeMessage(tml.version);
app: null,
block_options: [],
root_element: null,
options: {},
tml.initApplication(options, callback);
},
/**
* Initializes TML library
* @param options
* @param callback
*/
init: function (options, callback) {
options = options || {};
/**
* Initializes application
*
* @param options
* @param callback
*/
initApplication: function(options, callback) {
var t0 = new Date();
tml.options = options;
tml.config.debug = (options.debug ? options.debug : tml.config.debug);
var cookie = helpers.getCookie(options.key);
options.preferred_languages = options.preferred_languages || helpers.getBrowserLanguages();
var cache_version = null;
if (!options.current_source) {
options.current_source = function () {
return helpers.getCurrentSource({});
};
}
if (options.cache && options.cache.version)
cache_version = options.cache.version;
if (tml.config.debug || options.info) {
helpers.printWelcomeMessage(tml.version);
}
tml.config.registerApiAdapter('ajax', require('./api_adapters/ajax'));
tml.config.api = 'ajax';
tml.initApplication(options, function () {
tml.startKeyListener();
tml.startSourceListener(options);
if (callback) {
callback();
}
});
},
tml.config.registerCacheAdapters({
inline: require('./cache_adapters/inline'),
browser: require('./cache_adapters/browser')
});
// submit any newly registered keys every 3 seconds
startKeyListener: function () {
if (tml.getApplication().isInlineModeEnabled()) {
var app = tml.getApplication();
var freq = 3000;
setInterval(function () {
app.submitMissingTranslationKeys();
}, freq);
}
},
options = tml.utils.merge(tml.config, {
delayed_flush: true,
api: "ajax",
current_source: helpers.getCurrentSource(options),
current_locale: helpers.getCurrentLocale(options.key, options.current_locale),
current_translator: cookie.translator ? new tml.Translator(cookie.translator) : null,
accepted_locales: window.navigator.languages,
cache: {
enabled: true,
adapter: "browser",
version: cache_version
}
}, options);
refreshSource: function (options) {
var self = this;
var source = helpers.getCurrentSource(options);
var app = tml.getApplication();
var key = tml.utils.generateKey(source); // utils
var locale = app.current_locale;
options.fetch_version = (options.cache.adapter == 'browser' && !cache_version);
var updateSource = function () {
if (self.tokenizer) {
self.tokenizer.updateAllNodes();
}
};
tml.config.initCache(options.key);
// console.log(options);
if (!app.getSource(source)) {
app.loadSources([source], locale, function (sources) {
if (sources.length > 0 && sources[0] && sources[0].sources && sources[0].sources.length > 0) {
app.loadSources(sources[0].sources, app.current_locale, updateSource);
} else {
updateSource();
}
});
}
},
tml.app = new tml.Application({
key: options.key,
token: options.token,
host: options.host || DEFAULT_HOST
});
// keep track of route changes and update source
startSourceListener: function (options) {
var self = this;
var app = tml.getApplication();
tml.app.init(options, function (err) {
if (err) {
throw new Error(err);
}
if ((options.translateBody || options.translate_body) && mutationObserver) {
tml.translateElement(document);
}
tml.domReady(function(){
if ((options.translateBody || options.translate_body) && !mutationObserver) {
tml.translateElement(document.body);
function setSource(method) {
return function () {
if (method) {
method.apply(history, arguments);
}
self.refreshSource(options);
};
}
var t1 = new Date();
tml.logger.debug("page render took " + (t1 - t0) + " mls");
window.history.pushState = setSource(window.history.pushState);
window.history.replaceState = setSource(window.history.replaceState);
window.addEventListener('popstate', setSource());
},
tml.updateLanguageSelector();
/**
* Initializes application
*
* @param options
* @param callback
*/
initApplication: function (options, callback) {
var t0 = new Date();
if ((options.translateTitle || options.translate_title) && document.title !== "") {
document.title = tml.translateLabel(document.title);
}
var cookie = helpers.getCookie(options.key);
if (!options.agent) {
options.agent = {
type: 'agent',
cache: 864000000
};
}
var cache_version = null;
if (options.agent.type == "agent") {
helpers.includeAgent(tml.app, {
host: options.agent.host,
cache: options.agent.cache,
domains: options.agent.domains || {},
locale: options.current_locale,
source: options.current_source,
languages: tml.app.languages
}, function () {
if (callback) callback();
});
} else {
helpers.includeTools(tml.app, options.current_locale, function () {
if (callback) callback();
});
}
if (options.cache && options.cache.version)
cache_version = options.cache.version;
if (typeof(options.onLoad) == "function") {
options.onLoad(tml.app);
}
});
tml.config.registerApiAdapter('ajax', require('./api_adapters/ajax'));
tml.config.api = 'ajax';
// if version is hardcoded - don't bother checking the version
if (options.fetch_version) {
setTimeout(function () {
tml.config.getCache().fetchVersion(function (current_version) {
tml.app.getApiClient().getReleaseVersion(function (new_version) {
if (current_version != new_version)
tml.config.getCache().clear();
});
});
}, 1000);
}
});
},
tml.config.registerCacheAdapters({
inline: require('./cache_adapters/inline'),
browser: require('./cache_adapters/browser')
});
/**
* Fires when DOM is ready
*
* @param fn
*/
domReady: function(fn){
if (!document.readyState || /ded|te/.test(document.readyState)) {
fn();
} else {
document.addEventListener("DOMContentLoaded", fn, false);
}
},
options = tml.utils.merge(tml.config, {
delayed_flush: true,
api: "ajax",
current_source: helpers.getCurrentSource(options),
current_locale: helpers.getCurrentLocale(options.key, options.current_locale),
current_translator: cookie.translator ? new tml.Translator(cookie.translator) : null,
accepted_locales: window.navigator.languages,
cache: {
enabled: true,
adapter: "browser",
version: cache_version
}
}, options);
/**
* Updates language selector
*/
updateLanguageSelector: function() {
var languageSelector = document.querySelectorAll("[data-tml-language-selector], [tml-language-selector]");
options.fetch_version = (options.cache.adapter == 'browser' && !cache_version);
if (languageSelector.length === 0) return;
for (var i=0; i<languageSelector.length; i++) {
var type = languageSelector[i].getAttribute("data-tml-language-selector");
type = type || 'popup';
var element = languageSelector[i].getAttribute("data-tml-language-selector-element");
element = element || 'div';
var toggle = languageSelector[i].getAttribute("data-tml-toggle") == 'true';
var toggle_label = languageSelector[i].getAttribute("data-tml-toggle-label");
var powered_by = languageSelector[i].getAttribute("data-tml-powered-by") == 'true';
languageSelector[i].innerHTML = tml.getLanguageSelector(type, {
element: element,
container: languageSelector[i],
toggle: toggle,
toggle_label: toggle_label,
powered_by: powered_by
});
tml.scripts.language_selector_init(tml.app, type);
}
},
tml.config.initCache(options.key);
// console.log(options);
/**
* Changes language
*
* @param locale
*/
changeLanguage: function(locale) {
tml.app.changeLanguage(locale, function(language) {
helpers.updateCurrentLocale(tml.options.key, locale);
tml.config.currentLanguage = tml.app.getCurrentLanguage();
tml.app = new tml.Application({
key: options.key,
token: options.token,
host: options.host || DEFAULT_HOST
});
if (this.tokenizer)
this.tokenizer.updateAllNodes();
tml.app.init(options, function (err) {
tml.updateLanguageSelector();
if ((options.translateBody || options.translate_body) && mutationObserver) {
tml.translateElement(document);
}
if (tml.utils.isFunction(tml.options.onLanguageChange))
tml.options.onLanguageChange(language);
}.bind(this));
},
tml.domReady(function () {
/**
* Translates a string
*
* @param label
* @param description
* @param tokens
* @param options
* @returns {*}
*/
translate: function(label, description, tokens, options) {
if(!tml.app) {
throw new Error("Invalid application.");
}
if ((options.translateBody || options.translate_body) && !mutationObserver) {
tml.translateElement(document.body);
}
var params = tml.utils.normalizeParams(label, description, tokens, options);
params.label = params.label.replace(/\s\s+/g, ' ');
var t1 = new Date();
tml.logger.debug("page render took " + (t1 - t0) + " mls");
params.options = tml.utils.extend({}, {
current_locale: tml.app.current_locale,
current_source: tml.app.current_source,
current_translator: tml.app.current_translator,
block_options: (tml.block_options || [])
}, params.options);
if ((options.translateTitle || options.translate_title) && document.title !== "") {
document.title = tml.translateLabel(document.title);
}
return tml.app.getCurrentLanguage().translate(params);
},
if (!options.agent) options.agent = {};
/**
* Translates a label
*
* @param label
* @param description
* @param tokens
* @param options
* @returns {*}
*/
translateLabel: function(label, description, tokens, options) {
var params = tml.utils.normalizeParams(label, description, tokens, options);
params.options.skip_decorations = true;
return tml.translate(params);
},
helpers.includeAgent(tml.app, {
host: options.agent.host,
cache: options.agent.cache || 864000000,
domains: options.agent.domains || {},
locale: tml.app.current_locale,
source: tml.app.current_source,
sdk: options.sdk || 'tml-js v' + tml.version,
css: tml.app.css,
languages: tml.app.languages
}, function () {
if (callback) callback();
});
/**
* Translates an element
*
* @param container
*/
translateElement: function(container) {
container = (typeof container === "string") ? document.getElementById(container) : container;
if (typeof(options.onLoad) == "function") {
options.onLoad(tml.app);
}
});
tml.config.currentLanguage = tml.app.getCurrentLanguage();
// if version is hardcoded - don't bother checking the version
if (options.fetch_version) {
setTimeout(function () {
tml.config.getCache().fetchVersion(function (current_version) {
tml.app.getApiClient().getReleaseVersion(function (new_version) {
if (current_version != new_version)
tml.config.getCache().clear();
});
});
}, 1000);
}
});
},
this.tokenizer = new DomTokenizer(container, {}, {
debug: false,
current_source: tml.app.current_source || 'index',
current_translator: tml.app.current_translator
});
/**
* Fires when DOM is ready
*
* @param fn
*/
domReady: function (fn) {
if (!document.readyState || /ded|te/.test(document.readyState)) {
fn();
} else {
document.addEventListener("DOMContentLoaded", fn, false);
}
},
if(/ded|te/.test(document.readyState)) {
this.tokenizer.translateDOM(document.body);
} else if (mutationObserver) {
if(document.body) {
this.tokenizer.translateDOM(document.body);
}
this.translateNow();
}
},
/**
* Changes language
*
* @param locale
*/
changeLanguage: function (locale) {
tml.app.changeLanguage(locale, function (language) {
helpers.updateCurrentLocale(tml.options.key, locale);
tml.config.currentLanguage = tml.app.getCurrentLanguage();
/**
* Translates DOM
*/
translateNow: function(){
var observer, tokenizer = this.tokenizer;
var moHandler = function(mutations) {
var nodeList = [];
if (mutations.length > 0) {
mutations.forEach(function(mutation) {
var target = mutation.target;
var nodes = mutation.addedNodes || [];
if (this.tokenizer) {
this.tokenizer.updateAllNodes();
}
if (nodes.length > 0) {
for (var i = nodes.length - 1; i > -1; i--) {
var node = nodes[i];
if(node.tagName && node.tagName.toLowerCase().indexOf("tml:") != -1) continue;
if(node.tagName && node.tagName.toLowerCase().indexOf("script") != -1) continue;
nodeList.push(node);
}
if (tml.utils.isFunction(tml.options.onLanguageChange)) {
tml.options.onLanguageChange(language);
}
});
nodeList.forEach(function(n){
tokenizer.translateDOM(n);
tml.emit('language-change', language);
}.bind(this));
},
/**
* Translates a string
*
* @param label
* @param description
* @param tokens
* @param options
* @returns {*}
*/
translate: function (label, description, tokens, options) {
if (!tml.app) {
throw new Error("Invalid application.");
}
var params = tml.utils.normalizeParams(label, description, tokens, options);
params.label = params.label.replace(/\s\s+/g, ' ');
params.options = tml.utils.extend({}, {
current_locale: tml.app.current_locale,
current_source: tml.app.current_source,
current_translator: tml.app.current_translator,
block_options: (tml.block_options || [])
}, params.options);
return tml.app.getCurrentLanguage().translate(params);
},
/**
* Translates a label
*
* @param label
* @param description
* @param tokens
* @param options
* @returns {*}
*/
translateLabel: function (label, description, tokens, options) {
var params = tml.utils.normalizeParams(label, description, tokens, options);
params.options.skip_decorations = true;
return tml.translate(params);
},
/**
* Translates an element
*
* @param container
*/
translateElement: function (container) {
container = (typeof container === "string") ? document.getElementById(container) : container;
tml.config.currentLanguage = tml.app.getCurrentLanguage();
this.tokenizer = new DomTokenizer(container, {}, {
debug: false,
current_source: tml.app.current_source || 'index',
current_translator: tml.app.current_translator
});
if(document.readyState == "interactive") {
observer.disconnect();
if (/ded|te/.test(document.readyState)) {
this.tokenizer.translateDOM(document.body);
this.translateNow();
} else if (mutationObserver) {
if (document.body) {
this.tokenizer.translateDOM(document.body);
}
this.translateNow();
}
}
};
},
observer = new mutationObserver(moHandler);
observer.observe(document, {
subtree: true,
attributes: true,
attributeOldValue: false,
childList: true,
characterData: true,
characterDataOldValue: false
});
},
/**
* Translates DOM
*/
translateNow: function () {
var observer, tokenizer = this.tokenizer;
var moHandler = function (mutations) {
var nodeList = [];
if (mutations.length > 0) {
mutations.forEach(function (mutation) {
var target = mutation.target;
var nodes = mutation.addedNodes || [];
/**
* Translates text nodes
*
* @param parent_node
* @param text_node
* @param label
*/
translateTextNode: function(parent_node, text_node, label) {
// we need to handle empty spaces better
var sanitized_label = tml.utils.sanitizeString(label);
if (tml.utils.isNumber(sanitized_label)) return;
if (sanitized_label === null || sanitized_label.length === 0) return;
var translation = this.translate(sanitized_label);
if (nodes.length > 0) {
for (var i = nodes.length - 1; i > -1; i--) {
var node = nodes[i];
if (node.tagName && node.tagName.toLowerCase().indexOf("tml:") != -1) continue;
if (node.tagName && node.tagName.toLowerCase().indexOf("script") != -1) continue;
nodeList.push(node);
}
}
});
if (/^\s/.test(label)) translation = " " + translation;
if (/\s$/.test(label)) translation = translation + " ";
nodeList.forEach(function (n) {
tokenizer.translateDOM(n);
});
var translated_node = document.createElement("span");
// translated_node.style.border = '1px dotted green';
translated_node.innerHTML = translation;
if (document.readyState == "interactive") {
if(!tml.options.translateBody || tml.options.disableAutoTranslate) {
observer.disconnect();
}
}
}
};
// translated_node.style.border = '1px dotted red';
parent_node.replaceChild(translated_node, text_node);
},
observer = new mutationObserver(moHandler);
observer.observe(document, {
subtree: true,
attributes: true,
attributeOldValue: false,
childList: true,
characterData: true,
characterDataOldValue: false
});
},
/**
* Translates text elements
*
* @param element
*/
translateTextElements: function(element) {
if (tml.utils.element('tml_status_node')) return;
/**
* Translates text nodes
*
* @param parent_node
* @param text_node
* @param label
*/
translateTextNode: function (parent_node, text_node, label) {
// we need to handle empty spaces better
var sanitized_label = tml.utils.sanitizeString(label);
if (tml.utils.isNumber(sanitized_label)) return;
if (sanitized_label === null || sanitized_label.length === 0) return;
var translation = this.translate(sanitized_label);
console.log("Initializing text nodes...");
if (/^\s/.test(label)) translation = " " + translation;
if (/\s$/.test(label)) translation = translation + " ";
// add node to the document so it is not processed twice
var status_node = document.createElement('div');
status_node.id = 'tml_status_node';
status_node.style.display = 'none';
document.body.appendChild(status_node);
var translated_node = document.createElement("span");
// translated_node.style.border = '1px dotted green';
translated_node.innerHTML = translation;
var text_nodes = [];
var tree_walker = document.createTreeWalker(element || document.body, NodeFilter.SHOW_TEXT, null, false);
while (tree_walker.nextNode()) {
text_nodes.push(tree_walker.currentNode);
}
// translated_node.style.border = '1px dotted red';
parent_node.replaceChild(translated_node, text_node);
},
console.log("Found " + text_nodes.length + " text nodes");
/**
* Translates text elements
*
* @param element
*/
translateTextElements: function (element) {
if (tml.utils.element('tml_status_node')) return;
var disable_sentences = true;
console.log("Initializing text nodes...");
for (i = 0; i < text_nodes.length; i++) {
var current_node = text_nodes[i];
var parent_node = current_node.parentNode;
// add node to the document so it is not processed twice
var status_node = document.createElement('div');
status_node.id = 'tml_status_node';
status_node.style.display = 'none';
document.body.appendChild(status_node);
if (!parent_node) continue;
var text_nodes = [];
var tree_walker = document.createTreeWalker(element || document.body, NodeFilter.SHOW_TEXT, null, false);
while (tree_walker.nextNode()) {
text_nodes.push(tree_walker.currentNode);
}
// no scripts
if (parent_node.tagName == "script" || parent_node.tagName == "SCRIPT") continue;
console.log("Found " + text_nodes.length + " text nodes");
var label = current_node.nodeValue || "";
var disable_sentences = true;
// console.log(label);
for (i = 0; i < text_nodes.length; i++) {
var current_node = text_nodes[i];
var parent_node = current_node.parentNode;
// no html image tags
if (label.indexOf("<img") != -1) continue;
if (!parent_node) continue;
// no comments
if (label.indexOf("<!-") != -1) continue;
// no scripts
if (parent_node.tagName == "script" || parent_node.tagName == "SCRIPT") continue;
var sentences = label.split(". ");
this.translateTextNode(parent_node, current_node, label);
}
},
var label = current_node.nodeValue || "";
/**
* Returns application
*
* @returns {*}
*/
getApplication: function() {
return tml.app;
},
// console.log(label);
/**
* Returns current source
*
* @returns {*}
*/
getCurrentSource: function() {
return tml.app.current_source;
},
// no html image tags
if (label.indexOf("<img") != -1) continue;
/**
* Returns current translator
*
* @returns {*}
*/
getCurrentTranslator: function() {
return tml.app.current_translator;
},
// no comments
if (label.indexOf("<!-") != -1) continue;
/**
* Returns current language
*
* @returns {*}
*/
getCurrentLanguage: function() {
return tml.app.getCurrentLanguage();
},
var sentences = label.split(". ");
this.translateTextNode(parent_node, current_node, label);
}
},
/**
* Generates a language selector
*
* @param type
* @param options
* @returns {*}
*/
getLanguageSelector: function(type, options) {
options = tml.utils.merge(options || {}, {
current_language: tml.getCurrentLanguage(),
client_side: true
});
return tml.scripts.language_selector(tml.app, type, options);
},
/**
* Returns application
*
* @returns {*}
*/
getApplication: function () {
return tml.app;
},
/**
* Encloses block options
*
* @param options
* @param callback
*/
block: function(options, callback) {
tml.block_options.unshift(options);
callback();
tml.block_options.pop();
},
/**
* Returns current source
*
* @returns {*}
*/
getCurrentSource: function () {
return tml.app.current_source;
},
/**
* Begins block options
*
* @param options
*/
beginBlock: function(options) {
tml.block_options.unshift(options);
},
/**
* Returns current translator
*
* @returns {*}
*/
getCurrentTranslator: function () {
return tml.app.current_translator;
},
/**
* Ends block options
*/
endBlock: function() {
tml.block_options.pop();
},
/**
* Returns current language
*
* @returns {*}
*/
getCurrentLanguage: function () {
return tml.app.getCurrentLanguage();
},
/**
* Clears cache
*/
clearCache: function() {
tml.config.getCache().clear();
}
/**
* Encloses block options
*
* @param options
* @param callback
*/
block: function (options, callback) {
tml.block_options.unshift(options);
callback();
tml.block_options.pop();
},
});
/**
* Begins block options
*
* @param options
*/
beginBlock: function (options) {
tml.block_options.unshift(options);
},
/**
* Ends block options
*/
endBlock: function () {
tml.block_options.pop();
},
/**
* browser window extensions and helpers
*
* @type {Tml.translate|Function}
*/
/**
* Clears cache
*/
clearCache: function () {
tml.config.getCache().clear();
}
window.tml = tml;
window.tr = tml.translate;
window.trl = tml.translateLabel;
window.tre = tml.translateElement;
window.tml_application = tml.getApplication;
window.tml_current_source = tml.getCurrentSource;
window.tml_current_translator = tml.getCurrentTranslator;
window.tml_current_language = tml.getCurrentLanguage;
window.tml_language_selector = tml.getLanguageSelector;
window.tml_block = tml.block;
window.tml_begin_block = tml.beginBlock;
window.tml_end_block = tml.endBlock;
});
return {
tml: tml,
tr: tml.translate,
trl: tml.translateLabel,
tre: tml.translateElement,
tml_application: tml.getApplication,
tml_current_source: tml.getCurrentSource,
tml_current_translator: tml.getCurrentTranslator,
tml_current_language: tml.getCurrentLanguage,
tml_block: tml.block,
tml_begin_block: tml.beginBlock,
tml_end_block: tml.endBlock,
window.util = tml.utils; // TODO: is it being used?
util: tml.utils
};
}
));

@@ -1,37 +0,8 @@

/**
* Copyright (c) 2015 Translation Exchange, Inc.
*
* _______ _ _ _ ______ _
* |__ __| | | | | (_) | ____| | |
* | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
* | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
* | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
* |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
* __/ |
* |___/
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var tml = require('tml-js');
var config = tml.config;
var utils = tml.utils;
var dom = require('../helpers/dom-helpers');
var DomTokenizer = function(doc, context, options) {

@@ -46,5 +17,13 @@ this.doc = doc;

content_cache:[],
content_nodes:[],
contentCache :[],
contentNodes :[],
translatedNodes :[],
getOption: function(name) {
if(typeof this.options[name] === 'undefined' || this.options[name] === null) {
return utils.hashValue(config.translator_options, name);
}
return this.options[name];
},
translate: function() {

@@ -55,5 +34,5 @@ return this.translateTree(this.doc);

updateAllNodes: function(){
for(var i=0,l=this.content_cache.length;i<l;i++){
if(this.content_cache[i].container) {
this.content_cache[i].container.innerHTML = this.translateTml(this.content_cache[i].tml, this.content_cache[i].data);
for(var i=0,l=this.contentCache.length;i<l;i++){
if(this.contentCache[i].container) {
this.contentCache[i].container.innerHTML = this.translateTml(this.contentCache[i].tml, this.contentCache[i].data);
}

@@ -64,2 +43,3 @@ }

replaceNodes: function(nodes) {
var ti = document.createElement("tml:inline");

@@ -74,12 +54,10 @@ var parent = nodes[0] && nodes[0].parentNode;

if(!translation || this.isEmptyString(tml) || this.isUntranslatableText(text) || this.isNoTranslate(parent)) return;
if(!translation || this.isEmptyString(tml) || this.isUntranslatableText(text) || !this.isTranslatable(parent)) return;
if(nodes.length !== parent.childNodes.length) {
//setTimeout(function(){
parent.insertBefore(ti, nodes[0]);
ti.innerHTML = translation;
ti.insertAdjacentHTML("beforebegin", "\n");
ti.insertAdjacentHTML("afterend", "\n");
nodes.forEach(function(n){parent.removeChild(n);});
//}.bind(this),0);
parent.insertBefore(ti, nodes[0]);
ti.innerHTML = translation;
ti.insertAdjacentHTML("beforebegin", "\n");
ti.insertAdjacentHTML("afterend", "\n");
nodes.forEach(function(n){parent.removeChild(n);});
container = ti;

@@ -95,5 +73,5 @@ } else {

if(this.content_nodes.indexOf(container) == -1) {
this.content_cache.push({container: container, tml: tml, data: data});
this.content_nodes.push(container);
if(this.contentNodes.indexOf(container) == -1) {
this.contentCache.push({container: container, tml: tml, data: data});
this.contentNodes.push(container);
}

@@ -104,11 +82,3 @@

isUntranslatableText: function(text) {
return (
this.isEmptyString(text) || // empty
text.match(/^[0-9,.\s]+$/) // numbers
);
},
translatedNodes: [],
translateDOM: function(node) {

@@ -118,6 +88,3 @@ if(this.translatedNodes.indexOf(node) !== -1) return;

if (node.nodeType == 3) {
node.nodeValue = node.nodeValue;
return;
}
if (node.nodeType == 3) { return; }

@@ -129,8 +96,8 @@ var source = node.nodeType == 1 && this.getSourceBlock(node);

var l = node.childNodes.length, i = l, buffer = [];
while(i--) {
var child = node.childNodes[l-i-1];
if(!child || this.isNoTranslate(child)) continue;
var buffer = [];
for(var i=0;i<node.childNodes.length;i++) {
var child = node.childNodes[i];
if(!child || !this.isTranslatable(child)) continue;
if (child.nodeType == 3 || this.isInlineNode(child) && this.hasInlineSiblings(child)) {
if (child.nodeType == 3 || dom.isInline(child) && dom.hasInlineSiblings(child)) {
buffer.push(child);

@@ -144,3 +111,9 @@ } else {

if (buffer.length>0) this.replaceNodes(buffer);
if (buffer.length>0) {
if(buffer.length == 1 && buffer[0].nodeType == 1) {
this.translateDOM(buffer[0]);
} else {
this.replaceNodes(buffer);
}
}

@@ -151,51 +124,25 @@ if(source) {

},
matchesUntranslatableSelector: function(node){
var matcher, slctrs = this.getOption("ignore_elements") || [];
if(slctrs) {
for(var i=0,l=slctrs.length; i<l;i++) {
var slctr = slctrs[i] + "," + slctrs[i] + " *";
matcher =
(node.matches && node.matches(slctr)) ||
(node.webkitMatches && node.webkitMatches(slctr)) ||
(node.mozMatches && node.mozMatches(slctr)) ||
(node.msMatches && node.msMatches(slctr));
if(matcher) return true;
}
}
return false;
},
getSourceBlock: function(node) {
var matcher, els = config.sourceElements || [];
if (els) {
for(var i=0,l=els.length; i<l;i++) {
var slctr = els[i].selector;
var name = els[i].name;
matcher =
(node.matches && node.matches(slctr)) ||
(node.webkitMatches && node.webkitMatches(slctr)) ||
(node.mozMatches && node.mozMatches(slctr)) ||
(node.msMatches && node.msMatches(slctr));
if(matcher) return name;
if(config.sourceElements) {
var match = dom.matchesSelectors(node, config.sourceElements);
if(match) {
return node.getAttribute('name') || node.getAttribute('id') || node.getAttribute('class');
}
}
return node.getAttribute('data-tml-source') || false;
},
isNoTranslate: function(node) {
// Comments are not translatable
if (node.nodeType == 8)
return true;
// Elements
isTranslatable: function(node) {
if (node.nodeType == 8) { return false; }
if (node.nodeType == 3) { node = node.parentNode; }
if (node.nodeType == 1) {
return (
(this.getOption("nodes.scripts").indexOf(node.tagName.toLowerCase()) != -1) ||
(node.hasAttribute('notranslate')) ||
(this.matchesUntranslatableSelector(node))
);
return !dom.matchesSelectors(node, ([]).concat(
(this.getOption("nodes.scripts") || []),
(this.getOption("ignore_elements") || []),
(['[notranslate]','.notranslate','tml\\:label'])
), true);
}
return false;
return true;
},

@@ -232,28 +179,8 @@

isValidTml: function(tml) {
var tokens = /<\/?([a-z][a-z0-9]*)\b[^>]*>|{([a-z0-9_\.]+)}/gi;
return !this.isEmptyString(tml.replace(tokens, ''));
},
hasChildNodes: function(node) {
if (!node.childNodes) return false;
return (node.childNodes.length > 0);
},
isBetweenSeparators: function(node) {
if (this.isSeparatorNode(node.previousSibling) && !this.isValidTextNode(node.nextSibling))
return true;
if (this.isSeparatorNode(node.nextSibling) && !this.isValidTextNode(node.previousSibling))
return true;
return false;
},
generateTmlTags: function(node) {
if(node.nodeType == 3) {
return node.nodeValue;
}
if(node.nodeType == 3) { return node.nodeValue; }
if (this.isNoTranslate(node)) {
if (!this.isTranslatable(node)) {
var tokenName = this.contextualize(this.adjustName(node), node.innerHTML);

@@ -272,6 +199,3 @@ return "{" + tokenName + "}";

var child = node.childNodes[i];
if (child.nodeType == 3) // text node
buffer = buffer + child.nodeValue;
else
buffer = buffer + this.generateTmlTags(child);
buffer = buffer + ((child.nodeType == 3) ? child.nodeValue : this.generateTmlTags(child));
}

@@ -284,3 +208,3 @@ var tokenContext = this.generateHtmlToken(node);

if (this.isSelfClosingNode(node)){
if (dom.isSelfClosing(node)){
tml = '{' + token + '}';

@@ -322,18 +246,2 @@ } else {

getOption: function(name) {
if(typeof this.options[name] === 'undefined' || this.options[name] === null) {
return utils.hashValue(config.translator_options, name);
}
return this.options[name];
},
debugTranslation: function(translation) {
return this.getOption("debug_format").replace('{$0}', translation);
},
isEmptyString: function(tml) {
tml = tml.replace(/[\s\n\r\t\0\x0b\xa0\xc2]/g, '');
return (tml === '');
},
resetContext: function() {

@@ -347,64 +255,3 @@ this.tokens = [].concat(this.context);

isOnlyChild: function(node) {
if (!node.parentNode) return false;
return (node.parentNode.childNodes.length == 1);
},
hasInlineSiblings: function(node) {
return (
(node.parentNode && node.parentNode.childNodes.length > 1) &&
(node.previousSibling && (this.isInlineNode(node.previousSibling) || this.isValidTextNode(node.previousSibling))) ||
(node.nextSibling && (this.isInlineNode(node.nextSibling) || this.isValidTextNode(node.nextSibling)))
);
},
isInlineNode: function(node) {
return (
node.nodeType == 1 &&
this.getOption("nodes.inline").indexOf(node.tagName.toLowerCase()) != -1 &&
!this.isOnlyChild(node)
);
},
isContainerNode: function(node) {
return (node.nodeType == 1 && !this.isInlineNode(node));
},
isSelfClosingNode: function(node) {
return (!node.firstChild);
},
isIgnoredNode: function(node) {
if (node.nodeType != 1) return true;
return (this.getOption("nodes.ignored").indexOf(node.tagName.toLowerCase()) != -1);
},
isValidTextNode: function(node) {
if (!node) return false;
return (node.nodeType == 3 && !this.isEmptyString(node.nodeValue));
},
isSeparatorNode: function(node) {
if (!node) return false;
return (node.nodeType == 1 && this.getOption("nodes.splitters").indexOf(node.tagName.toLowerCase()) != -1);
},
sanitizeValue: function(value) {
return value.replace(/^\s+/,'');
},
replaceSpecialCharacters: function(text) {
if (!this.getOption("data_tokens.special.enabled")) return text;
var matches = text.match(this.getOption("data_tokens.special.regex"));
var self = this;
matches.forEach(function(match) {
token = match.substring(1, match.length - 2);
self.context[token] = match;
text = text.replace(match, "{" + token + "}");
});
return text;
},
generateDataTokens: function(text) {

@@ -454,6 +301,6 @@ var self = this;

}
return text;
},
generateHtmlToken: function(node, value) {

@@ -466,7 +313,8 @@ var name = node.tagName.toLowerCase();

if (attributes.length === 0) {
if (this.isSelfClosingNode(node)) {
if (name == "br" || name == "hr")
if (dom.isSelfClosing(node)) {
if (dom.isSeparator(node)){
return '<' + name + '/>';
else
} else {
return '<' + name + '>' + '</' + name + '>';
}
}

@@ -490,8 +338,9 @@ return '<' + name + '>' + value + '</' + name + '>';

if (this.isSelfClosingNode(node))
if (dom.isSelfClosing(node)) {
return '<' + name + ' ' + attr + '>' + '</' + name + '>';
}
return '<' + name + ' ' + attr + '>' + value + '</' + name + '>';
},
adjustName: function(node) {

@@ -504,2 +353,3 @@ var name = node.tagName.toLowerCase();

contextualize: function(name, context) {

@@ -521,2 +371,32 @@ if (this.tokens[name] && this.tokens[name] != context) {

// String Helpers
isEmptyString: function(tml) {
tml = tml.replace(/[\s\n\r\t\0\x0b\xa0\xc2]/g, '');
return (tml === '');
},
isUntranslatableText: function(text) {
return (
this.isEmptyString(text) || // empty
text.match(/^[0-9,.\s]+$/) // numbers
);
},
isValidTml: function(tml) {
var tokens = /<\/?([a-z][a-z0-9]*)\b[^>]*>|{([a-z0-9_\.]+)}/gi;
return !this.isEmptyString(tml.replace(tokens, ''));
},
sanitizeValue: function(value) {
return value.replace(/^\s+/,'');
},
// Debugging
debug: function(doc) {

@@ -529,5 +409,4 @@ this.doc = doc;

var padding = new Array(depth+1).join('=');
console.log(padding + "=> " + (typeof node) + ": " + dom.nodeInfo(node));
console.log(padding + "=> " + (typeof node) + ": " + this.nodeInfo(node));
if (node.childNodes) {

@@ -542,31 +421,10 @@ var self = this;

nodeInfo: function(node) {
var info = [];
info.push(node.nodeType);
debugTranslation: function(translation) {
return this.getOption("debug_format").replace('{$0}', translation);
}
if (node.nodeType == 1)
info.push(node.tagName);
if (this.isInlineNode(node)) {
info.push("inline");
if (this.hasInlineSiblings(node))
info.push("sentence");
else
info.push("only translatable");
}
if (this.isSelfClosingNode(node))
info.push("self closing");
if (this.isOnlyChild(node))
info.push("only child");
if (node.nodeType == 3)
return "[" + info.join(", ") + "]" + ': "' + node.nodeValue + '"';
return "[" + info.join(", ") + "]";
}
};
module.exports = DomTokenizer;
{
"name": "tml-js-browser",
"description": "Translation plugin for browsers.",
"version": "0.4.26",
"version": "0.4.28",
"author": {

@@ -47,2 +47,3 @@ "name": "Michael Berkovich",

"dependencies": {
"tiny-emitter": "^1.0.2",
"tml-js": "~0.4.9"

@@ -78,3 +79,5 @@ },

}
},
"browserify-shim": {
}
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc