📄 serial.js
字号:
/** * Tools for serializing components, stylesheets, and property instances to and from XML. */EchoSerial = { /** * Map between property class names and property translators. * Property translators stored in this map will be used when an object * provides a "className" property. */ _propertyTranslatorMap: { }, /** * 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. */ _propertyTranslatorTypeData: [ ], /** * Adds a property translator for a specific class name. * * @param className the class name * @param propertyTranslator the property translator */ addPropertyTranslator: function(className, propertyTranslator) { this._propertyTranslatorMap[className] = propertyTranslator; }, /** * Adds a property translator for a specific constructor. * * @param type the constructor * @param propertyTranslator the property translator */ addPropertyTranslatorByType: function(type, propertyTranslator) { this._propertyTranslatorTypeData.push(type, propertyTranslator); }, /** * Retrieves a property translator for a specific class name. * * @param className the class name * @return the property translator */ getPropertyTranslator: function(className) { return this._propertyTranslatorMap[className]; }, /** * Retrieves a property translator for a specific constructor. * * @param type the constructor * @return the property translator */ getPropertyTranslatorByType: function(type) { for (var i = 0; i < this._propertyTranslatorTypeData.length; i += 2) { if (this._propertyTranslatorTypeData[i] == type) { return this._propertyTranslatorTypeData[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 client the containing client * @param componentElement the 'c' DOM element to deserialize * @return the instantiated component. */ loadComponent: function(client, componentElement, referenceMap) { if (!componentElement.nodeName == "c") { throw new Error("Element is not a component."); } var type = componentElement.getAttribute("t"); var id = componentElement.getAttribute("i"); var component = EchoApp.ComponentFactory.newInstance(type, id); if (componentElement.getAttribute("en") == "false") { component.setEnabled(false); } var styleName = componentElement.getAttribute("s"); if (styleName) { component.setStyleName(styleName); } var styleData = component.getLocalStyleData(); var element = componentElement.firstChild; while (element) { if (element.nodeType == 1) { switch (element.nodeName) { case "c": // Child Component var childComponent = this.loadComponent(client, element, referenceMap); component.add(childComponent); break; case "p": // Property this.loadProperty(client, element, component, styleData, referenceMap); break; case "e": // Event this._loadComponentEvent(client, element, component); break; } } element = element.nextSibling; } return component; }, _loadComponentEvent: function(client, eventElement, component) { 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 client the containing client * @param {Element} propertyElement 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 referenceMap (optional) an associative array containing previously * loaded reference-based properties */ loadProperty: function(client, propertyElement, object, styleData, referenceMap) { var propertyName = propertyElement.getAttribute("n"); var propertyType = propertyElement.getAttribute("t"); var propertyIndex = propertyElement.getAttribute("x"); var propertyValue; if (propertyType) { // Invoke custom property processor. var translator = EchoSerial._propertyTranslatorMap[propertyType]; if (!translator) { throw new Error("Translator not available for property type: " + propertyType); } propertyValue = translator.toProperty(client, propertyElement); } else { if (referenceMap) { var propertyReference = propertyElement.getAttribute("r"); if (propertyReference) { propertyValue = referenceMap[propertyReference]; } else { propertyValue = EchoSerial.PropertyTranslator.String.toProperty(client, propertyElement); } } else { propertyValue = EchoSerial.PropertyTranslator.String.toProperty(client, propertyElement); } } if (propertyName) { if (styleData) { if (propertyIndex == null) { styleData[propertyName] = propertyValue; } else { var indexValues = styleData[propertyName]; if (!indexValues) { indexValues = []; styleData[propertyName] = indexValues; } indexValues[propertyIndex] = propertyValue; } } else { // Property has property name: invoke set(Indexed)Property. if (propertyIndex == null) { object.set(propertyName, propertyValue); } else { object.setIndex(propertyName, propertyIndex, propertyValue); } } } else { // Property has method name: invoke method. var propertyMethod = propertyElement.getAttribute("m"); if (propertyIndex == null) { object[propertyMethod](propertyValue); } else { object[propertyMethod](propertyIndex, propertyValue); } } }, /** * Deserializes an XML representation of a style sheet into a * StyleSheet instance. */ loadStyleSheet: function(client, ssElement, referenceMap) { var styleSheet = new EchoApp.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) { switch (sChild.nodeName) { case "p": this.loadProperty(client, sChild, null, style, referenceMap); break; } } 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. */ storeProperty: function(client, propertyElement, propertyValue) { if (propertyValue == null) { //FIXME. Send nulled values. } else if (typeof (propertyValue) == "object") { var translator = null; if (propertyValue.className) { translator = this._propertyTranslatorMap[propertyValue.className]; } else { translator = this.getPropertyTranslatorByType(propertyValue.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, propertyElement, propertyValue); } else { // call toString here, IE will otherwise convert boolean values to integers propertyElement.appendChild(propertyElement.ownerDocument.createTextNode(propertyValue.toString())); } }};/** * Namespace for property translator implementations. */EchoSerial.PropertyTranslator = { };/** * Null PropertyTranslator Singleton. */EchoSerial.PropertyTranslator.Null = { toProperty: function(client, propertyElement) { return null; }};EchoSerial.addPropertyTranslator("0", EchoSerial.PropertyTranslator.Null);/** * Boolean PropertyTranslator Singleton. */EchoSerial.PropertyTranslator.Boolean = { toProperty: function(client, propertyElement) { return propertyElement.firstChild.data == "true"; }};EchoSerial.addPropertyTranslator("b", EchoSerial.PropertyTranslator.Boolean);/** * Float PropertyTranslator Singleton. */EchoSerial.PropertyTranslator.Float = { toProperty: function(client, propertyElement) { return parseFloat(propertyElement.firstChild.data); }};EchoSerial.addPropertyTranslator("f", EchoSerial.PropertyTranslator.Float);/** * Integer PropertyTranslator Singleton. */EchoSerial.PropertyTranslator.Integer = { toProperty: function(client, propertyElement) { return parseInt(propertyElement.firstChild.data); }};EchoSerial.addPropertyTranslator("i", EchoSerial.PropertyTranslator.Integer);/** * String PropertyTranslator Singleton. */EchoSerial.PropertyTranslator.String = { toProperty: function(client, propertyElement) { var textNode = propertyElement.firstChild; if (!textNode) { return ""; } var text = textNode.data; while (textNode.nextSibling) { textNode = textNode.nextSibling; text += textNode.data; } return text; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -