tml-js-browser
Advanced tools
Comparing version 0.4.49 to 0.4.50
/** | ||
* Copyright (c) 2015 Translation Exchange, Inc. | ||
* Copyright (c) 2016 Translation Exchange, Inc. | ||
* | ||
@@ -4,0 +4,0 @@ * _______ _ _ _ ______ _ |
/** | ||
* Copyright (c) 2015 Translation Exchange, Inc. | ||
* Copyright (c) 2016 Translation Exchange, Inc. | ||
* | ||
@@ -4,0 +4,0 @@ * _______ _ _ _ ______ _ |
/** | ||
* Copyright (c) 2015 Translation Exchange, Inc. | ||
* Copyright (c) 2016 Translation Exchange, Inc. | ||
* | ||
@@ -4,0 +4,0 @@ * _______ _ _ _ ______ _ |
@@ -32,3 +32,3 @@ /** | ||
var tml = require('tml-js'); | ||
var tml = require('tml-js'); | ||
var utils = tml.utils; | ||
@@ -38,2 +38,7 @@ | ||
/** | ||
* Prints welcome message | ||
* | ||
* @param version | ||
*/ | ||
printWelcomeMessage: function (version) { | ||
@@ -56,3 +61,8 @@ console.log([ | ||
getBrowserLanguages: function() { | ||
/** | ||
* Gets browser preferred languages | ||
* | ||
* @returns {*|string|*[]|null} | ||
*/ | ||
getBrowserLanguages: function () { | ||
var nav = window.navigator; | ||
@@ -68,6 +78,11 @@ return ( | ||
includeLs: function(options) { | ||
/** | ||
* Adds language selector to the page | ||
* | ||
* @param options | ||
*/ | ||
includeLs: function (options) { | ||
var node = document.createElement("div"); | ||
if (utils.isObject(options)) { | ||
for(var propertyName in options) { | ||
for (var propertyName in options) { | ||
if (propertyName == 'type') | ||
@@ -84,3 +99,11 @@ node.setAttribute("data-tml-language-selector", options[propertyName]); | ||
includeAgent: function(app, options, callback) { | ||
/** | ||
* Adds agent to the page | ||
* | ||
* @param app | ||
* @param options | ||
* @param callback | ||
* @returns {*} | ||
*/ | ||
includeAgent: function (app, options, callback) { | ||
var agent_host = options.host || "https://tools.translationexchange.com/agent/stable/agent.min.js"; | ||
@@ -99,3 +122,3 @@ | ||
utils.addJS(window.document, 'tml-agent', agent_host, function() { | ||
utils.addJS(window.document, 'tml-agent', agent_host, function () { | ||
Trex.init(app.key, options); | ||
@@ -107,23 +130,34 @@ if (callback) | ||
getCurrentSource: function(options) { | ||
var current_source = null; | ||
var current_source_method = options.current_source || options.source; | ||
/** | ||
* Returns path fragments | ||
* | ||
* @param path | ||
* @returns {Array.<T>} | ||
*/ | ||
getPathFragments: function (path) { | ||
path = path || window.location.pathname; | ||
return path.split('/').filter(function (n) { | ||
return n !== ''; | ||
}); | ||
}, | ||
// current_source can be a function, hash or a string | ||
if (current_source_method) { | ||
if (utils.isFunction(current_source_method)) { | ||
current_source = current_source_method(); | ||
} else { | ||
current_source = current_source_method; | ||
} | ||
/** | ||
* Gets current source from URL path | ||
* | ||
* @param options | ||
* @returns {string} | ||
*/ | ||
getDefaultSource: function (options) { | ||
var locale_method = options.locale || options.current_locale; | ||
var current_source = window.location.pathname; | ||
if (current_source.length > 1) { | ||
current_source = current_source.replace(/\/$/, ''); | ||
} | ||
// a simple way to strip a url | ||
if (!current_source) { | ||
var parser = document.createElement('a'); | ||
parser.href = location.href; | ||
current_source = parser.pathname | ||
if(current_source.length > 1) { | ||
current_source = current_source.replace(/\/$/,''); | ||
} | ||
// for pre-path, remove the locale from path, and use the rest as the source | ||
if (utils.isObject(locale_method) && locale_method.strategy == 'pre-path') { | ||
var fragments = helpers.getPathFragments(current_source); | ||
fragments.shift(); | ||
current_source = fragments.join('/'); | ||
} | ||
@@ -133,6 +167,7 @@ | ||
if (current_source.match(/\/$/)){ | ||
if (current_source.match(/\/$/)) { | ||
current_source = current_source + 'index'; | ||
} | ||
if (current_source === ''){ | ||
if (current_source === '') { | ||
current_source = 'index'; | ||
@@ -144,24 +179,136 @@ } | ||
getCurrentLocale: function(key, locale_method) { | ||
/** | ||
* Extracts current source from the url | ||
* | ||
* @param options | ||
* @returns {*} | ||
*/ | ||
getCurrentSource: function (options) { | ||
var source_method = options.current_source || options.source; | ||
// current_source can be a function, hash or a string | ||
if (source_method) { | ||
if (utils.isString(source_method)) | ||
return source_method; | ||
if (utils.isFunction(source_method)) | ||
return source_method(); | ||
// TODO: handle the hash method - for dynamic mapping using regular expressions | ||
} | ||
return helpers.getDefaultSource(options); | ||
}, | ||
/** | ||
* Extracts locale from params | ||
* | ||
* @param param_name | ||
* @returns {*} | ||
*/ | ||
getLocaleFromParam: function (param_name) { | ||
param_name = param_name || 'locale'; | ||
var re = new RegExp("[?&]" + param_name + "=([^&]+)(&|$)"); | ||
return (window.location.search.match(re) || [])[1]; | ||
}, | ||
/** | ||
* Determines current locale | ||
* | ||
* @param options | ||
* @returns {*} | ||
*/ | ||
getCurrentLocale: function (options) { | ||
var current_locale = null; | ||
var locale_method = options.locale || options.current_locale; | ||
if (locale_method) { | ||
// locale is set/forced by the user, just use it | ||
if (utils.isString(locale_method)) { | ||
return locale_method; | ||
} | ||
// locale method is a function, execute it and use the result | ||
if (utils.isFunction(locale_method)) { | ||
current_locale = locale_method(); | ||
} else { | ||
current_locale = locale_method; | ||
return locale_method(); | ||
} | ||
} else { | ||
current_locale = (window.location.search.match(/[?&]locale=([^&]+)(&|$)/) ||[])[1]; | ||
if (current_locale) { | ||
this.updateCurrentLocale(key, current_locale); | ||
} else { | ||
var cookie = this.getCookie(key); | ||
current_locale = cookie.locale; | ||
// locale must be extracted from param | ||
// options: { | ||
// default: 'en', | ||
// strategy: 'param', | ||
// param: 'locale', | ||
// cookie: true, | ||
// redirect: false | ||
// } | ||
if (locale_method.strategy == 'param') { | ||
tml.logger.debug("extracting locale from param"); | ||
current_locale = helpers.getLocaleFromParam(locale_method.param); | ||
tml.logger.debug("detected locale: " + current_locale); | ||
// if locale was detected, and cookie is enabled, store it in the cookie | ||
if (current_locale) { | ||
if (locale_method.cookie) | ||
this.updateCurrentLocale(options.key, current_locale); | ||
} else { | ||
// if locale is not detected, but the cookie is enabled, pull the locale from the cookie | ||
if (locale_method.cookie) | ||
current_locale = this.getCookie(options.key).locale; | ||
} | ||
return current_locale; | ||
} | ||
// locale must be extracted from pre-path | ||
if (locale_method.strategy == 'pre-path') { | ||
tml.logger.debug("extracting locale from pre-path"); | ||
var fragments = window.location.pathname.split('/').filter(function (n) { | ||
return n !== ''; | ||
}); | ||
//console.log(elements); | ||
return fragments[0]; | ||
} | ||
if (locale_method.strategy == 'pre-domain') { | ||
var subdomains = window.location.hostname.split('.'); | ||
return subdomains[0]; | ||
} | ||
// options: { | ||
// strategy: 'custom-domain', | ||
// mapping: { | ||
// 'en': 'my-en.lvh.me', | ||
// 'ru': 'my-ru.lvh.me', | ||
// 'ko': 'my-ko.lvh.me' | ||
// } | ||
// } | ||
if (locale_method.strategy == 'custom-domain') { | ||
var host = window.location.hostname; | ||
var mapping = utils.swapKeys(locale_method.mapping); | ||
return mapping[host]; | ||
} | ||
tml.logger.debug("locale method is provided, but not enough information is supplied"); | ||
return null; | ||
} | ||
// default fallback uses the param locale or cookie locale - for backwards compatibility | ||
current_locale = helpers.getLocaleFromParam(); | ||
if (current_locale) { | ||
this.updateCurrentLocale(options.key, current_locale); | ||
} else { | ||
var cookie = this.getCookie(options.key); | ||
current_locale = cookie.locale; | ||
} | ||
return current_locale; | ||
}, | ||
updateCurrentLocale: function(key, locale) { | ||
/** | ||
* Updates locale in the cookie | ||
* | ||
* @param key | ||
* @param locale | ||
*/ | ||
updateCurrentLocale: function (key, locale) { | ||
var data = helpers.getCookie(key); | ||
@@ -173,11 +320,17 @@ data = data || {}; | ||
getCookie: function(key) { | ||
/** | ||
* Returns cookie | ||
* | ||
* @param key | ||
* @returns {*} | ||
*/ | ||
getCookie: function (key) { | ||
var cname = utils.getCookieName(key); | ||
var name = cname + "="; | ||
var ca = document.cookie.split(';'); | ||
for(var i=0; i<ca.length; i++) { | ||
for (var i = 0; i < ca.length; i++) { | ||
var c = ca[i]; | ||
while (c.charAt(0)==' ') c = c.substring(1); | ||
while (c.charAt(0) == ' ') c = c.substring(1); | ||
if (c.indexOf(name) != -1) | ||
return utils.decode(c.substring(name.length,c.length)); | ||
return utils.decode(c.substring(name.length, c.length)); | ||
} | ||
@@ -187,3 +340,9 @@ return {}; | ||
setCookie: function(key, data) { | ||
/** | ||
* Sets the cookie | ||
* | ||
* @param key | ||
* @param data | ||
*/ | ||
setCookie: function (key, data) { | ||
var cname = utils.getCookieName(key); | ||
@@ -196,12 +355,13 @@ document.cookie = cname + "=" + utils.encode(data) + "; path=/"; | ||
module.exports = { | ||
printWelcomeMessage: helpers.printWelcomeMessage, | ||
getBrowserLanguages: helpers.getBrowserLanguages, | ||
includeTools: helpers.includeTools, | ||
getCurrentSource: helpers.getCurrentSource, | ||
getCurrentLocale: helpers.getCurrentLocale, | ||
updateCurrentLocale: helpers.updateCurrentLocale, | ||
getCookie: helpers.getCookie, | ||
setCookie: helpers.setCookie, | ||
includeLs: helpers.includeLs, | ||
includeAgent: helpers.includeAgent | ||
printWelcomeMessage: helpers.printWelcomeMessage, | ||
getBrowserLanguages: helpers.getBrowserLanguages, | ||
includeTools: helpers.includeTools, | ||
getCurrentSource: helpers.getCurrentSource, | ||
getDefaultSource: helpers.getDefaultSource, | ||
getCurrentLocale: helpers.getCurrentLocale, | ||
updateCurrentLocale: helpers.updateCurrentLocale, | ||
getCookie: helpers.getCookie, | ||
setCookie: helpers.setCookie, | ||
includeLs: helpers.includeLs, | ||
includeAgent: helpers.includeAgent | ||
}; |
@@ -0,1 +1,32 @@ | ||
/** | ||
* Copyright (c) 2016 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 inline = ["a", "span", "i", "b", "img", "strong", "s", "em", "u", "sub", "sup", "var", "code", "kbd"]; | ||
@@ -6,2 +37,8 @@ var separators = ["br", "hr"]; | ||
/** | ||
* Checks if the string is empty | ||
* | ||
* @param str | ||
* @returns {boolean} | ||
*/ | ||
isEmptyString: function(str) { | ||
@@ -11,2 +48,8 @@ return !str.replace(/[\s\n\r\t\0\x0b\xa0\xc2]/g, ''); | ||
/** | ||
* Checks if node is inline | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isInline: function(node) { | ||
@@ -21,2 +64,8 @@ return ( | ||
/** | ||
* Count children by type | ||
* | ||
* @param node | ||
* @returns {{total: number, inline: number, breaking: number, text: number}} | ||
*/ | ||
childTypeCounts: function(node) { | ||
@@ -49,2 +98,8 @@ var children = node.childNodes; | ||
/** | ||
* Count children elements | ||
* | ||
* @param node | ||
* @returns {number} | ||
*/ | ||
childElementCount: function(node) { | ||
@@ -62,2 +117,8 @@ var count = 0; | ||
/** | ||
* Checks if all child nodes are links | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
hasOnlyLinks: function(node) { | ||
@@ -68,2 +129,8 @@ var count = this.childElementCount(node); | ||
/** | ||
* Checks if a node has only inline siblings | ||
* | ||
* @param node | ||
* @returns {*} | ||
*/ | ||
hasInlineSiblings: function(node) { | ||
@@ -81,2 +148,8 @@ if (this.hasOnlyLinks(node.parentNode)) | ||
/** | ||
* Checks if the node is self closing like <br> or <hr> | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isSelfClosing: function(node) { | ||
@@ -86,2 +159,8 @@ return (!node.firstChild); | ||
/** | ||
* Checks if node is a valid text node | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isValidText: function(node) { | ||
@@ -92,2 +171,8 @@ if (!node) return false; | ||
/** | ||
* Checks if node is a separator | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isSeparator: function(node) { | ||
@@ -98,2 +183,8 @@ if (!node) return false; | ||
/** | ||
* Checks if a node has child nodes | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
hasChildNodes: function(node) { | ||
@@ -104,2 +195,8 @@ if (!node.childNodes) return false; | ||
/** | ||
* Checks if node is between separators | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isBetweenSeparators: function(node) { | ||
@@ -111,7 +208,21 @@ if (this.isSeparator(node.previousSibling) && !this.isValidText(node.nextSibling)){ return true; } | ||
/** | ||
* Checks if node is the only child | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isOnlyChild: function(node) { | ||
if (!node.parentNode) return false; | ||
return (node.parentNode.childNodes.length == 1); | ||
}, | ||
}, | ||
/** | ||
* Checks if node matches selectors | ||
* | ||
* @param node | ||
* @param selectors | ||
* @param children | ||
* @returns {boolean} | ||
*/ | ||
matchesSelectors: function(node, selectors, children) { | ||
@@ -133,2 +244,8 @@ var matcher, slctrs = typeof selectors === "string" ? [selectors] : selectors; | ||
/** | ||
* Returns back a node info | ||
* | ||
* @param node | ||
* @returns {string} | ||
*/ | ||
nodeInfo: function(node) { | ||
@@ -135,0 +252,0 @@ var info = [node.nodeType]; |
201
lib/index.js
/** | ||
* Copyright (c) 2015 Translation Exchange, Inc. | ||
* Copyright (c) 2016 Translation Exchange, Inc. | ||
* | ||
@@ -47,3 +47,3 @@ * _______ _ _ _ ______ _ | ||
if ( typeof exports === 'object' ) { | ||
if (typeof exports === 'object') { | ||
//console.log('exports load', module); | ||
@@ -53,8 +53,7 @@ module.exports = factory(); | ||
} | ||
else if ( typeof define === 'function' && define.amd ) { | ||
else if (typeof define === 'function' && define.amd) { | ||
//console.log('amd load'); | ||
define( [], factory ); | ||
define([], factory); | ||
} | ||
else | ||
{ | ||
else { | ||
//console.log('global load'); | ||
@@ -74,3 +73,3 @@ addToRoot(factory()); | ||
tml = tml.utils.extend(tml, { | ||
version: '/* @echo VERSION */', | ||
version: '0.4.50', | ||
@@ -95,10 +94,13 @@ on: emitter.on.bind(emitter), | ||
// storing original options for later use | ||
tml.options = options; | ||
tml.config.debug = (options.debug ? options.debug : tml.config.debug); | ||
options.preferred_languages = options.preferred_languages || helpers.getBrowserLanguages(); | ||
// do we use it anywhere? - app init pulls them out | ||
//options.preferred_languages = options.preferred_languages || helpers.getBrowserLanguages(); | ||
// if current source is not set, we try to automatically extract it from the URL | ||
if (!options.current_source) { | ||
options.current_source = function () { | ||
return helpers.getCurrentSource({}); | ||
options.current_source = function() { | ||
return helpers.getDefaultSource(options); | ||
}; | ||
@@ -112,71 +114,10 @@ } | ||
tml.initApplication(options, function () { | ||
tml.startKeyListener(); | ||
tml.startKeyListener(options); | ||
tml.startSourceListener(options); | ||
if (callback) { | ||
callback(); | ||
} | ||
if (callback) callback(); | ||
}); | ||
}, | ||
// 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); | ||
} | ||
}, | ||
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; | ||
var updateSource = function () { | ||
if (self.tokenizer) { | ||
self.tokenizer.updateAllNodes(); | ||
} | ||
}; | ||
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(); | ||
} | ||
}); | ||
} | ||
}, | ||
// keep track of route changes and update source | ||
startSourceListener: function (options) { | ||
// TODO: Ian, we don't need this unless we use a fully automated mode | ||
if (!options.translateBody) return; | ||
var self = this; | ||
var app = tml.getApplication(); | ||
function setSource(method) { | ||
return function () { | ||
if (method) { | ||
method.apply(history, arguments); | ||
} | ||
self.refreshSource(options); | ||
}; | ||
} | ||
window.history.pushState = setSource(window.history.pushState); | ||
window.history.replaceState = setSource(window.history.replaceState); | ||
window.addEventListener('popstate', setSource()); | ||
}, | ||
/** | ||
* Initializes application | ||
* Initializes the application | ||
* | ||
@@ -190,3 +131,2 @@ * @param options | ||
var cookie = helpers.getCookie(options.key); | ||
var cache_version = null; | ||
@@ -197,5 +137,7 @@ | ||
// registering AJAX based adapter for all API calls | ||
tml.config.registerApiAdapter('ajax', require('./api_adapters/ajax')); | ||
tml.config.api = 'ajax'; | ||
// registering cache options - local storage or in-page block | ||
tml.config.registerCacheAdapters({ | ||
@@ -206,9 +148,21 @@ inline: require('./cache_adapters/inline'), | ||
// updating options and configuring the SDK | ||
options = tml.utils.merge(tml.config, { | ||
delayed_flush: true, | ||
api: "ajax", | ||
// current source can be a method, a hash or a string | ||
current_source: helpers.getCurrentSource(options), | ||
current_locale: helpers.getCurrentLocale(options.key, options.current_locale), | ||
// for backwards compatibility we support current_locale - but we should swtich documentation | ||
// to user "locale" instead. "locale" now supports strategies | ||
current_locale: helpers.getCurrentLocale(options), | ||
// translator information can only be extracted from the cookie | ||
current_translator: cookie.translator ? new tml.Translator(cookie.translator) : null, | ||
// get the list of locales from the browser | ||
accepted_locales: helpers.getBrowserLanguages(), | ||
// setup default cache to use local storage - unless user overwrites it | ||
cache: { | ||
@@ -242,3 +196,4 @@ enabled: true, | ||
if ((options.translateBody || options.translate_body) && !mutationObserver) { | ||
var translateBodySettings = options.translateBody || options.translate_body; | ||
if (translateBodySettings && !mutationObserver) { | ||
tml.translateElement(document.body); | ||
@@ -256,6 +211,17 @@ } | ||
if (options.language_selector) { | ||
helpers.includeLs(options.language_selector); | ||
var languageSelectorSettings = options.language_selector || options.languageSelector; | ||
if (languageSelectorSettings) { | ||
helpers.includeLs(languageSelectorSettings); | ||
} | ||
//extend({}, options.agent, { | ||
// locale_strategy: options.locale, | ||
// config: tml.config, | ||
// 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 | ||
//}); | ||
helpers.includeAgent(tml.app, { | ||
@@ -266,2 +232,4 @@ host: options.agent.host, | ||
domains: options.agent.domains || {}, | ||
locale_strategy: options.locale, | ||
config: tml.config, | ||
locale: tml.app.current_locale, | ||
@@ -284,2 +252,73 @@ source: tml.app.current_source, | ||
/** | ||
* Submits any newly registered keys every 3 seconds | ||
* | ||
* @param options | ||
*/ | ||
startKeyListener: function (options) { | ||
if (!tml.getApplication().isInlineModeEnabled()) | ||
return; | ||
var app = tml.getApplication(); | ||
var freq = options.flush_interval || 3000; | ||
setInterval(function () { | ||
app.submitMissingTranslationKeys(); | ||
}, freq); | ||
}, | ||
/** | ||
* Keeps track of route changes and update source | ||
* | ||
* @param options | ||
*/ | ||
startSourceListener: function (options) { | ||
// TODO: Ian, we don't need this unless we use a fully automated mode | ||
if (!options.translateBody) return; | ||
var self = this; | ||
var app = tml.getApplication(); | ||
function setSource(method) { | ||
return function () { | ||
if (method) { | ||
method.apply(history, arguments); | ||
} | ||
self.refreshSource(options); | ||
}; | ||
} | ||
window.history.pushState = setSource(window.history.pushState); | ||
window.history.replaceState = setSource(window.history.replaceState); | ||
window.addEventListener('popstate', setSource()); | ||
}, | ||
/** | ||
* Refreshes current source from the server | ||
* | ||
* @param 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; | ||
var updateSource = function () { | ||
if (self.tokenizer) { | ||
self.tokenizer.updateAllNodes(); | ||
} | ||
}; | ||
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(); | ||
} | ||
}); | ||
} | ||
}, | ||
/** | ||
* Fires when DOM is ready | ||
@@ -300,4 +339,2 @@ * | ||
* | ||
* | ||
* | ||
* @param locale | ||
@@ -429,3 +466,3 @@ * @param refresh | ||
if (document.readyState == "interactive") { | ||
if(!tml.options.translateBody || tml.options.disableAutoTranslate) { | ||
if (!tml.options.translateBody || tml.options.disableAutoTranslate) { | ||
observer.disconnect(); | ||
@@ -432,0 +469,0 @@ } |
@@ -0,1 +1,32 @@ | ||
/** | ||
* Copyright (c) 2016 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'); | ||
@@ -7,4 +38,2 @@ var config = tml.config; | ||
var DomTokenizer = function(doc, context, options) { | ||
@@ -23,9 +52,21 @@ this.doc = doc; | ||
getOption: function(name) { | ||
if(typeof this.options[name] === 'undefined' || this.options[name] === null) { | ||
return utils.hashValue(config.translator_options, name); | ||
} | ||
return this.options[name]; | ||
}, | ||
/** | ||
* Returns back config option value | ||
* | ||
* @param name | ||
* @returns {*} | ||
* @param default_value | ||
*/ | ||
getOption: function(name, default_value) { | ||
if(typeof this.options[name] === 'undefined' || this.options[name] === null) | ||
return utils.hashValue(config.translator_options, name) || default_value; | ||
return this.options[name] || default_value; | ||
}, | ||
/** | ||
* Translates the document | ||
* | ||
* @returns {*} | ||
*/ | ||
translate: function() { | ||
@@ -35,2 +76,5 @@ return this.translateTree(this.doc); | ||
/** | ||
* Updates all nodes with translations | ||
*/ | ||
updateAllNodes: function(){ | ||
@@ -44,2 +88,7 @@ for(var i=0,l=this.contentCache.length;i<l;i++){ | ||
/** | ||
* Replaces nodes | ||
* | ||
* @param nodes | ||
*/ | ||
replaceNodes: function(nodes) { | ||
@@ -84,2 +133,7 @@ | ||
/** | ||
* Translates DOM | ||
* | ||
* @param node | ||
*/ | ||
translateDOM: function(node) { | ||
@@ -122,5 +176,11 @@ if(this.translatedNodes.indexOf(node) !== -1) return; | ||
}, | ||
/** | ||
* Determine a source block | ||
* | ||
* @param node | ||
* @returns {*} | ||
*/ | ||
getSourceBlock: function(node) { | ||
if(config.sourceElements) { | ||
if (config.sourceElements) { | ||
var match = dom.matchesSelectors(node, config.sourceElements); | ||
@@ -135,2 +195,8 @@ if(match) { | ||
/** | ||
* Checks if node is translatable | ||
* | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
isTranslatable: function(node) { | ||
@@ -149,2 +215,9 @@ if (node.nodeType == 8) { return false; } | ||
/** | ||
* Translates TML string with data tokens | ||
* | ||
* @param tml | ||
* @param data | ||
* @returns {*} | ||
*/ | ||
translateTml: function(tml, data) { | ||
@@ -180,3 +253,8 @@ tml = this.generateDataTokens(tml); | ||
/** | ||
* Generates TML tags | ||
* | ||
* @param node | ||
* @returns {*} | ||
*/ | ||
generateTmlTags: function(node) { | ||
@@ -227,2 +305,8 @@ if(node.nodeType == 3) { | ||
/** | ||
* Creates a data token from a variable node element | ||
* | ||
* @param node | ||
* @returns {string} | ||
*/ | ||
registerDataTokenFromVar: function(node) { | ||
@@ -247,2 +331,5 @@ var object = {}; | ||
/** | ||
* Resets context | ||
*/ | ||
resetContext: function() { | ||
@@ -252,2 +339,9 @@ this.tokens = [].concat(this.context); | ||
/** | ||
* Checks if the token is a short token | ||
* | ||
* @param token | ||
* @param value | ||
* @returns {boolean} | ||
*/ | ||
isShortToken: function(token, value) { | ||
@@ -257,3 +351,8 @@ return (this.getOption("nodes.short").indexOf(token.toLowerCase()) != -1 || value.length < 20); | ||
/** | ||
* Generates data tokens | ||
* | ||
* @param text | ||
* @returns {*|void|XML|string} | ||
*/ | ||
generateDataTokens: function(text) { | ||
@@ -270,3 +369,3 @@ var self = this; | ||
var regex = format[0]; | ||
var date_format = format[1]; | ||
//var date_format = format[1]; | ||
@@ -276,5 +375,5 @@ var matches = text.match(regex); | ||
matches.forEach(function (match) { | ||
var date = match; | ||
//var date = match; | ||
//var date = self.localizeDate(match, date_format); | ||
var token = self.contextualize(tokenName, date); | ||
var token = self.contextualize(tokenName, match); | ||
var replacement = "{" + token + "}"; | ||
@@ -308,3 +407,9 @@ text = text.replace(match, replacement); | ||
/** | ||
* Generates HTML tokens | ||
* | ||
* @param node | ||
* @param value | ||
* @returns {string} | ||
*/ | ||
generateHtmlToken: function(node, value) { | ||
@@ -348,2 +453,8 @@ var name = node.tagName.toLowerCase(); | ||
/** | ||
* Uses token name mapping to create token names from HTML tags | ||
* | ||
* @param node | ||
* @returns {*} | ||
*/ | ||
adjustName: function(node) { | ||
@@ -359,3 +470,9 @@ if(node && node.tagName) { | ||
/** | ||
* Generates tokens by name | ||
* | ||
* @param name | ||
* @param context | ||
* @returns {*} | ||
*/ | ||
contextualize: function(name, context) { | ||
@@ -378,5 +495,10 @@ if (this.tokens[name] && this.tokens[name] != context) { | ||
// String Helpers | ||
/** | ||
* Checks if string is empty | ||
* | ||
* @param tml | ||
* @returns {boolean} | ||
*/ | ||
isEmptyString: function(tml) { | ||
@@ -387,2 +509,8 @@ tml = tml.replace(/[\s\n\r\t\0\x0b\xa0\xc2]/g, ''); | ||
/** | ||
* Checks if string can be translated | ||
* | ||
* @param text | ||
* @returns {*|boolean|Boolean|Array|{index: number, input: string}} | ||
*/ | ||
isUntranslatableText: function(text) { | ||
@@ -395,7 +523,19 @@ return ( | ||
/** | ||
* Checks if TML is valid | ||
* | ||
* @param tml | ||
* @returns {boolean} | ||
*/ | ||
isValidTml: function(tml) { | ||
var tokens = /<\/?([a-z][a-z0-9]*)\b[^>]*>|{([a-z0-9_\.]+)}|{}/gi; | ||
var tokens = /<\/?([a-z][a-z0-9]*)\b[^>]*>|{([a-z0-9_\.]+)}|\{\}/gi; | ||
return !this.isEmptyString(tml.replace(tokens, '')); | ||
}, | ||
/** | ||
* Cleans up string value | ||
* | ||
* @param value | ||
* @returns {*|void|XML|string} | ||
*/ | ||
sanitizeValue: function(value) { | ||
@@ -405,2 +545,8 @@ return value.replace(/^\s+/,''); | ||
/** | ||
* Escapes HTML | ||
* | ||
* @param str | ||
* @returns {string} | ||
*/ | ||
escapeHtml: function(str) { | ||
@@ -413,3 +559,2 @@ var div = document.createElement('div'); | ||
// Debugging | ||
@@ -416,0 +561,0 @@ |
{ | ||
"name": "tml-js-browser", | ||
"description": "Translation plugin for browsers.", | ||
"version": "0.4.49", | ||
"version": "0.4.50", | ||
"author": { | ||
@@ -6,0 +6,0 @@ "name": "Michael Berkovich", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
564190
12510