1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/** 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @fileoverview This is a simple template engine inspired by JsTemplates 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * optimized for i18n. 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * It currently supports two handlers: 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * * i18n-content which sets the textContent of the element 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * <span i18n-content="myContent"></span> 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * i18nTemplate.process(element, {'myContent': 'Content'}); 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * * i18n-values is a list of attribute-value or property-value pairs. 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Properties are prefixed with a '.' and can contain nested properties. 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * <span i18n-values="title:myTitle;.style.fontSize:fontSize"></span> 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * i18nTemplate.process(element, { 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 'myTitle': 'Title', 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * 'fontSize': '13px' 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * }); 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvar i18nTemplate = (function() { 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * This provides the handlers for the templating engine. The key is used as 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * the attribute name and the value is the function that gets called for every 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * single node that has this attribute. 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {Object} 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var handlers = { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * This handler sets the textContent of the element. 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 'i18n-content': function(element, attributeValue, obj) { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch element.textContent = obj[attributeValue]; 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen * This handler adds options to a select element. 433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen */ 443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 'i18n-options': function(element, attributeValue, obj) { 453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen var options = obj[attributeValue]; 463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen options.forEach(function(values) { 473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen var option = typeof values == 'string' ? new Option(values) : 483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen new Option(values[1], values[0]); 493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen element.appendChild(option); 503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen }); 513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen }, 523f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen /** 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * This is used to set HTML attributes and DOM properties,. The syntax is: 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * attributename:key; 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * .domProperty:key; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * .nested.dom.property:key 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 'i18n-values': function(element, attributeValue, obj) { 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var parts = attributeValue.replace(/\s/g, '').split(/;/); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var j = 0; j < parts.length; j++) { 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var a = parts[j].match(/^([^:]+):(.+)$/); 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (a) { 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var propName = a[1]; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var propExpr = a[2]; 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ignore missing properties 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (propExpr in obj) { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var value = obj[propExpr]; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (propName.charAt(0) == '.') { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var path = propName.slice(1).split('.'); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var object = element; 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (object && path.length > 1) { 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch object = object[path.shift()]; 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (object) { 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch object[path] = value; 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // In case we set innerHTML (ignoring others) we need to 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // recursively check the content 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (path == 'innerHTML') { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch process(element, obj); 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch element.setAttribute(propName, value); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch console.warn('i18n-values: Missing value for "' + propExpr + '"'); 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var attributeNames = []; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var key in handlers) { 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch attributeNames.push(key); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var selector = '[' + attributeNames.join('],[') + ']'; 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Processes a DOM tree with the {@code obj} map. 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function process(node, obj) { 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var elements = node.querySelectorAll(selector); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var element, i = 0; element = elements[i]; i++) { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var j = 0; j < attributeNames.length; j++) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var name = attributeNames[j]; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var att = element.getAttribute(name); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (att != null) { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handlers[name](element, att, obj); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return { 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch process: process 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch})(); 121