"use strict"; // Root element and localization manager for a Toolkit application Toolkit.Application = class Application extends Toolkit.Panel { // Object constructor constructor(options) { super(null, options); // Configure instance fields this.application = this; this.components = []; this.locale = null; this.locales = { first: null }; this.propagationListeners = []; // Configure element this.element.setAttribute("application", ""); this.element.addEventListener("mousedown" , e=>this.onpropagation(e)); this.element.addEventListener("pointerdown", e=>this.onpropagation(e)); } ///////////////////////////// Public Methods ////////////////////////////// // Add a component for localization management addComponent(component) { if (this.components.indexOf(component) != -1) return; this.components.push(component); component.localize(); } // Register a locale with the application addLocale(source) { let loc = null; // Process the locale object from the source try { loc = new Function("return (" + source + ");")(); } catch(e) { console.log(e); } // Error checking if ( !loc || typeof loc != "object" || !("key" in loc) || !("name" in loc) ) return null; // Register the locale if (this.locales.first == null) this.locales.first = loc; this.locales[loc.key] = loc; return loc.key; } // Add a callback for propagation events addPropagationListener(listener) { if (this.propagationListeners.indexOf(listener) == -1) this.propagationListeners.push(listener); } // Produce a list of all registered locale keys listLocales() { return Object.values(this.locales); } // Remove a compnent from being localized removeComponent(component) { let index = this.components.indexOf(component); if (index == -1) return false; this.components.splice(index, 1); return true; } // Specify which localized strings to use for application controls setLocale(lang) { // Error checking if (this.locales.first == null) return null; // Working variables lang = lang.toLowerCase(); let parts = lang.split("-"); let best = null; // Check all locales for (let loc of Object.values(this.locales)) { let key = loc.key.toLowerCase(); // The language is an exact match if (key == lang) { best = loc; break; } // The language matches, but the region may not if (best == null && key.split("-")[0] == parts[0]) best = loc; } // The language did not match: use the first locale that was registered if (best == null) best = this.locales.first; // Select the locale this.locale = best; return best.key; } // Localize text for a component translate(text, properties) { properties = !properties ? {} : properties instanceof Toolkit.Component ? properties.properties : properties; // Process all characters from the input let sub = { text: "", parent: null }; for (let x = 0; x < text.length; x++) { let c = text[x]; let last = x == text.length - 1; // Left curly brace if (c == '{') { // Literal left curly brace if (!last && text[x + 1] == '{') { sub.text += c; x++; continue; } // Open a substring sub = { text: "", parent: sub }; continue; } // Right curly brace if (c == '}') { // Literal right curly brace if (!last && text[x + 1] == '}') { sub.text += c; x++; continue; } // Close a sub (if there are any to close) if (sub.parent != null) { // Text comes from component property if (sub.text in properties) { sub.parent.text += properties[sub.text]; sub = sub.parent; continue; } // Text comes from locale let value = this.fromLocale(sub.text, true); if (value !== null) { text = value + text.substring(x + 1); x = -1; sub = sub.parent; continue; } // Take the text as-is sub.parent.text += "{" + sub.text + "}"; sub = sub.parent; continue; } } // Append the character to the sub's text sub.text += c; } // Close any remaining subs (should never happen) for (; sub.parent != null; sub = sub.parent) sub.parent.text += sub.text; return sub.text; } ///////////////////////////// Private Methods ///////////////////////////// // Retrieve the text for a key in the locale fromLocale(key) { let locale = this.locale || {}; for (let part of key.split(".")) { if (!(part in locale)) return null; locale = locale[part]; } return typeof locale == "string" ? locale : null; } // A pointer or mouse down even has propagated onpropagation(e) { e.stopPropagation(); for (let listener of this.propagationListeners) listener(e, this); } };