📄 serial.js
字号:
/** * Tools for serializing components, stylesheets, and property instances to and from XML. * @namespace */Echo.Serial = { /** * Map between property class names and property translators. * Property translators stored in this map will be used when an object * provides a "className" property. */ _translatorMap: { }, /** * Array describing mapping between object constructors and property translators. * Even indices of the map contain constructors, and the subsequent odd indices * contain the property translator suitable for the constructor at the previous * index. This array is iterated to determine the appropriate property translator. * This array is only used for a very small number of non-primitive * property types which are provided by JavaScript itself, e.g., Date. */ _translatorTypeData: [ ], /** * Adds a property translator for a specific class name. * * @param {String} className the class name * @param {Echo.Serial.PropertyTranslator} translator the property translator singleton (static class) */ addPropertyTranslator: function(className, translator) { this._translatorMap[className] = translator; }, /** * Adds a property translator for a specific constructor. * * @param {Function} type the constructor * @param {Echo.Serial.PropertyTranslator} translator the property translator singleton (static class) */ addPropertyTranslatorByType: function(type, translator) { this._translatorTypeData.push(type, translator); }, /** * Retrieves a property translator for a specific class name. * * @param {String} className the class name * @return {Echo.Serial.PropertyTranslator} the property translator */ getPropertyTranslator: function(className) { return this._translatorMap[className]; }, /** * Retrieves a property translator for a specific constructor. * * @param {Function} type the constructor * @return {Echo.Serial.PropertyTranslator} the property translator */ getPropertyTranslatorByType: function(type) { for (var i = 0; i < this._translatorTypeData.length; i += 2) { if (this._translatorTypeData[i] == type) { return this._translatorTypeData[i + 1]; } } return null; }, /** * Deserializes an XML representation of a component into a component instance. * Any child components will be added to the created component instance. * Events properties will be registered with the client by invoking the * "addComponentListener()" method on the provided 'client', passing in * the properties 'component' (the component instance) and 'event' (the event * type as a string). * * @param {Echo.Client} client the containing client * @param {Element} cElement the 'c' DOM element to deserialize * @param propertyMap (optional) a mapping between property identifiers and property values for referenced properties * (properties which were rendered elsewhere in the document and are potentially referenced by multiple components) * @param styleMap (optional) a mapping between style identifiers and style values for referenced styles (styles which were * rendered elsewhere in the document and are potentially referenced by multiple components) * @return the instantiated component */ loadComponent: function(client, cElement, propertyMap, styleMap) { if (!cElement.nodeName == "c") { throw new Error("Element is not a component."); } var type = cElement.getAttribute("t"); var id = cElement.getAttribute("i"); var component = Echo.ComponentFactory.newInstance(type, id); var styleData = component.getLocalStyleData(); var element = cElement.firstChild; while (element) { if (element.nodeType == 1) { switch (element.nodeName) { case "c": // Child component var childComponent = this.loadComponent(client, element, propertyMap, styleMap); component.add(childComponent); break; case "p": // Property this.loadProperty(client, element, component, styleData, propertyMap); break; case "s": // Style name component.setStyleName(element.firstChild ? element.firstChild.nodeValue : null); break; case "sr": // Style reference component.setStyle(styleMap ? styleMap[element.firstChild.nodeValue] : null); break; case "e": // Event this._loadComponentEvent(client, element, component); break; case "en": // Enabled state component.setEnabled(element.firstChild.nodeValue == "true"); break; case "locale": // Locale component.setLocale(element.firstChild ? element.firstChild.nodeValue : null); break; case "dir": // Layout direction component.setLayoutDirection(element.firstChild ? (element.firstChild.nodeValue == "rtl" ? Echo.LayoutDirection.RTL : Echo.LayoutDirection.LTR) : null); } } element = element.nextSibling; } return component; }, /** * Processes an event registration directive element. * * @param {Echo.Client} client the client * @param {Element} eventElement the event element * @param {Echo.Component} the component */ _loadComponentEvent: function(client, eventElement, component) { if (client.addComponentListener) { var eventType = eventElement.getAttribute("t"); client.addComponentListener(component, eventType); } }, /** * Deserializes an XML representation of a property into an instance, * and assigns it to the specified object. * * @param {Echo.Client} client the containing client * @param {Element} pElement the property element to parse * @param object the object on which the properties should be set (this object * must contain set() and setIndex() methods * @param styleData (optional) an associative array on which properties can * be directly set * @param propertyMap (optional) a mapping between property identifiers and property values for referenced properties * (properties which were rendered elsewhere in the document and are potentially referenced by multiple components) * @param styleMap (optional) a mapping between style identifiers and style values for referenced styles (styles which were * rendered elsewhere in the document and are potentially referenced by multiple components) */ loadProperty: function(client, pElement, object, styleData, propertyMap) { var name = pElement.getAttribute("n"); var type = pElement.getAttribute("t"); var index = pElement.getAttribute("x"); var value; if (type) { // Invoke custom property processor. var translator = Echo.Serial._translatorMap[type]; if (!translator) { throw new Error("Translator not available for property type: " + type); } value = translator.toProperty(client, pElement); } else { if (propertyMap) { var propertyReference = pElement.getAttribute("r"); if (propertyReference) { value = propertyMap[propertyReference]; } else { value = Echo.Serial.String.toProperty(client, pElement); } } else { value = Echo.Serial.String.toProperty(client, pElement); } } if (name) { if (styleData) { if (index == null) { styleData[name] = value; } else { var indexValues = styleData[name]; if (!indexValues) { indexValues = []; styleData[name] = indexValues; } indexValues[index] = value; } } else { // Property has property name: invoke set(Indexed)Property. if (index == null) { object.set(name, value); } else { object.setIndex(name, index, value); } } } else { // Property has method name: invoke method. var propertyMethod = pElement.getAttribute("m"); if (index == null) { object[propertyMethod](value); } else { object[propertyMethod](index, value); } } }, /** * Deserializes an XML representation of a style sheet into a * StyleSheet instance. * * @param {Echo.Client} client the client instance * @param {Element} ssElement the "ss" element representing the root of the style sheet * @param propertyMap the (optional) property map containing referenced property information */ loadStyleSheet: function(client, ssElement, propertyMap) { var styleSheet = new Echo.StyleSheet(); var ssChild = ssElement.firstChild; while (ssChild) { if (ssChild.nodeType == 1) { if (ssChild.nodeName == "s") { var style = {}; var sChild = ssChild.firstChild; while (sChild) { if (sChild.nodeType == 1) { if (sChild.nodeName == "p") { this.loadProperty(client, sChild, null, style, propertyMap); } } sChild = sChild.nextSibling; } styleSheet.setStyle(ssChild.getAttribute("n"), ssChild.getAttribute("t"), style); } } ssChild = ssChild.nextSibling; } return styleSheet; }, /** * Serializes a property value into an XML representation. * * @param {Echo.Client} client the client instance * @param {Element} pElement the "p" element representing the property * @param value the value to render to the "p" element */ storeProperty: function(client, pElement, value) { if (value == null) { // Set no value to indicate null. } else if (typeof (value) == "object") { var translator = null; if (value.className) { translator = this._translatorMap[value.className]; } else { translator = this.getPropertyTranslatorByType(value.constructor); } if (!translator || !translator.toXml) { // If appropriate translator does not exist, or translator does not support to-XML translation, // simply ignore the property. return; } translator.toXml(client, pElement, value); } else { // call toString here, IE will otherwise convert boolean values to integers pElement.appendChild(pElement.ownerDocument.createTextNode(value.toString())); } }};/** * Abstract base class for property translators. */Echo.Serial.PropertyTranslator = Core.extend({ $abstract: true, $static: { /** * Converts an XML property value to a property instance. * * @param {Echo.Client} client the client * @param {Element} the "p" DOM element describing the property value * @return the generated property instance */ toProperty: function(client, pElement) { return null; }, /** * Optional: converts a property instance to an XML property element. * * @param {Echo.Client} client the client * @param {Element} pElement the "p" DOM element in which the property value should be stored * @param value the property instance */ toXml: null }});/** * Null Property Translator Singleton. */Echo.Serial.Null = Core.extend(Echo.Serial.PropertyTranslator, { $static: { /** @see Echo.Serial.PropertyTranslator#toProperty */ toProperty: function(client, pElement) { return null; } }, $load: function() { Echo.Serial.addPropertyTranslator("0", this); }});/** * Boolean Property Translator Singleton. */Echo.Serial.Boolean = Core.extend(Echo.Serial.PropertyTranslator, { $static: { /** @see Echo.Serial.PropertyTranslator#toProperty */ toProperty: function(client, pElement) { return pElement.firstChild.data == "true"; } }, $load: function() { Echo.Serial.addPropertyTranslator("b", this); }});/** * Float Property Translator Singleton. */Echo.Serial.Float = Core.extend(Echo.Serial.PropertyTranslator, { $static: { /** @see Echo.Serial.PropertyTranslator#toProperty */ toProperty: function(client, pElement) { return parseFloat(pElement.firstChild.data); } }, $load: function() { Echo.Serial.addPropertyTranslator("f", this); }});/** * Integer Property Translator Singleton. */Echo.Serial.Integer = Core.extend(Echo.Serial.PropertyTranslator, { $static: { /** @see Echo.Serial.PropertyTranslator#toProperty */ toProperty: function(client, pElement) { return parseInt(pElement.firstChild.data, 10); } }, $load: function() { Echo.Serial.addPropertyTranslator("i", this); }});/** * String Property Translator Singleton. */Echo.Serial.String = Core.extend(Echo.Serial.PropertyTranslator, { $static: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -