You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by gr...@apache.org on 2020/12/19 22:18:22 UTC

[royale-asjs] branch XML_Notification_prototype_swap created (now a747d31)

This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a change to branch XML_Notification_prototype_swap
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git.


      at a747d31  Speculative initial WIP on XMLNotification. No consideration given to 'bubbling'. For comparison purposes only.

This branch includes the following new commits:

     new a747d31  Speculative initial WIP on XMLNotification. No consideration given to 'bubbling'. For comparison purposes only.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[royale-asjs] 01/01: Speculative initial WIP on XMLNotification. No consideration given to 'bubbling'. For comparison purposes only.

Posted by gr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch XML_Notification_prototype_swap
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit a747d311b819f3263e2a24a27066ffb58a1ad8dd
Author: greg-dove <gr...@gmail.com>
AuthorDate: Sun Dec 20 11:17:08 2020 +1300

    Speculative initial WIP on XMLNotification. No consideration given to 'bubbling'. For comparison purposes only.
---
 frameworks/projects/XML/src/main/royale/XML.as     | 133 +++++++++++--
 .../org/apache/royale/language/NotificationXML.as  | 208 +++++++++++++++++++++
 .../XML/src/test/royale/flexUnitTests/XMLTester.as |   2 +-
 3 files changed, 325 insertions(+), 18 deletions(-)

diff --git a/frameworks/projects/XML/src/main/royale/XML.as b/frameworks/projects/XML/src/main/royale/XML.as
index 27c7103..63dd10e 100644
--- a/frameworks/projects/XML/src/main/royale/XML.as
+++ b/frameworks/projects/XML/src/main/royale/XML.as
@@ -18,7 +18,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 package
 {
-	COMPILE::JS
+import org.apache.royale.language.NotificationXML;
+
+COMPILE::JS
 	/**
 	 * @royalesuppresspublicvarwarning
 	 */
@@ -929,8 +931,9 @@ package
 		/**
 		 *
 		 * @royaleignorecoercion XML
+		 * @royalesuppressexport
 		 */
-		private function appendChildInternal(child:*):void
+		protected function appendChildInternal(child:*):void
 		{
 			var kind:String;
 			var alreadyPresent:int
@@ -1227,8 +1230,9 @@ package
 		private function deleteChildAt(idx:int):void
 		{
 			var child:XML = _children[idx] as XML;
-			child._parent = null;
-			_children.splice(idx,1);
+			childRemoved(child, idx);
+			/*child._parent = null;
+			_children.splice(idx,1);*/
 		}
 		
 		/**
@@ -2137,8 +2141,9 @@ package
 			var idx:int = getIndexOf(child);
 			if(idx < 0)
 				return false;
-			removed = _children.splice(idx,1);
-			child._parent = null;
+			/*removed = *///_children.splice(idx,1);
+			//child._parent = null;
+			childRemoved(child, idx);
 			return true;
 		}
 		
@@ -2181,8 +2186,9 @@ package
 				if(name.matches(child.name()))
 				{
 					child = _children[i];
-					child._parent = null;
-					_children.splice(i,1);
+					//child._parent = null;
+					//_children.splice(i,1);
+					childRemoved(child, i);
 					removedItem = true;
 				}
 			}
@@ -2212,7 +2218,8 @@ package
 					removed.setParent(null);
 					index =_children.indexOf(removed);
 					if (index != -1){
-						_children.splice(index,1);
+						//_children.splice(index,1);
+						childRemoved(removed, index);
 					}
 				}
 				return true;
@@ -2220,7 +2227,16 @@ package
 
 			throw new TypeError("Cannot call delete on XML at index "+index);
 		}
-		
+
+		protected function childRemoved(child:XML, index:int):void{
+			child._parent = null;
+			_children.splice(index,1);
+		}
+
+		protected function attributeUpdated(attribute:XML, value:String):void{
+			attribute.setValue(value);
+		}
+
 		/**
 		 * Removes the given namespace for this object and all descendants.
 		 *
@@ -2328,10 +2344,36 @@ package
 				return this;
 			if((value is XML) || (value is XMLList))
 				value = value.copy();
-			else
+			else {
 				value = value.toString();
-			
-			return null;
+			}
+			if (uint(propertyName).toString() == propertyName) {
+				replaceChildAt(uint(propertyName), value);
+			} else {
+				var n:QName = toXMLName(propertyName);
+				var k:uint = childrenLength();
+				var all:Boolean = n.localName == '*';
+				var children:Array = _children;
+				var i:int = -1;
+				while (k) {
+					k--;
+					var xK:XML=children[k];
+					//If ((n.localName == "*") or ((x[k].[[Class]] == "element") and (x[k].[[Name]].localName==n.localName)))
+					//and ((n.uri == null) or ((x[k].[[Class]] == "element") and (n.uri == x[k].[[Name]].uri )))
+					if ((all || ((xK.getNodeRef() == ELEMENT) && xK.localName() == n.localName)) && ((n.uri == null) || ((xK.getNodeRef() == ELEMENT) && (xK.name().uri == n.uri )))) {
+						if (i != -1) {
+							removeChildAt(i);
+							//do not use 'childRemoved
+						}
+						i = k;
+					}
+				}
+				if (i != -1) {
+					replaceChildAt(i, value);
+				}
+			}
+
+			return this;
 		}
 		
 		/**
@@ -2403,7 +2445,10 @@ package
 						listIdx++;
 					}
 				} else {
-					_children.splice(idx,1);
+					//_children.splice(idx,1);
+					if (_children[idx]) {
+						childRemoved(_children[idx], idx)
+					}
 				}
 			}
 			else
@@ -2448,7 +2493,8 @@ package
 					{
 						if(_attributes[i].name().equals(attr.name()))
 						{
-							_attributes[i].setValue(value);
+							//_attributes[i].setValue(value);
+							attributeUpdated(_attributes[i], value);
 							return value;
 						}
 					}
@@ -2481,7 +2527,8 @@ package
 				{
 					if(_attributes[i].name().equals(attrXML.name()))
 					{
-						_attributes[i].setValue(value);
+						//_attributes[i].setValue(value);
+						attributeUpdated(_attributes[i], value);
 						return value;
 					}
 				}
@@ -3235,7 +3282,59 @@ package
 			}
 			return str;
 		}
-		
+
+		////////////////////////////////////////////////////////////////
+		///
+		///
+		/// METHODS to allow XML to provide notifications of internal changes - advanced use only
+		/// these methods are available for dead-code-elimination if never used.
+		///
+		///
+		////////////////////////////////////////////////////////////////
+
+		/**
+		 * this is protected only to support the runtime 'upgrade' of this instance in the setNotification method
+		 * @private
+		 * @royalesuppressexport
+		 */
+		protected var _notificationFunction:Function;
+
+		/**
+		 * This is an advanced method mainly for binding support that is not documented in the
+		 * public as3 api for XML.
+		 * available for dead-code elimination if never used
+		 *
+		 * @private
+		 * @royalesuppressexport
+		 */
+		public function setNotification(val:Function):void{
+			if (val != null ) {
+				if (_notificationFunction == null) {
+					//upgrade this instance to support notifications
+					Object.setPrototypeOf(this, NotificationXML.getUpgradeTemplate());
+				}
+
+			} else {
+				if (_notificationFunction != null) {
+					//downgrade this instance to 'normal' XML
+					Object.setPrototypeOf(this, NotificationXML.getDowngradeTemplate());
+				}
+			}
+			_notificationFunction = val;
+		}
+
+		/**
+		 * This is an advanced method mainly for binding support that is not documented in the
+		 * public as3 api for XML.
+		 * available for dead-code elimination if never used
+		 *
+		 * @private
+		 * @royalesuppressexport
+		 */
+		public function notification():Function{
+			return _notificationFunction;
+		}
+
 		////////////////////////////////////////////////////////////////
 		///
 		///
diff --git a/frameworks/projects/XML/src/main/royale/org/apache/royale/language/NotificationXML.as b/frameworks/projects/XML/src/main/royale/org/apache/royale/language/NotificationXML.as
new file mode 100644
index 0000000..b2df320
--- /dev/null
+++ b/frameworks/projects/XML/src/main/royale/org/apache/royale/language/NotificationXML.as
@@ -0,0 +1,208 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.language
+{
+
+
+
+	[ExcludeClass]
+	COMPILE::JS
+	/**
+	 * @royalesuppresspublicvarwarning
+	 * @royalesuppressexport
+	 */
+	public class NotificationXML extends XML
+	{
+
+		private static const ATTRIBUTE_ADDED:String = 'attributeAdded';
+		private static const ATTRIBUTE_CHANGED:String = 'attributeChanged';
+		private static const ATTRIBUTE_REMOVED:String = 'attributeRemoved';
+		private static const NODE_ADDED:String = 'nodeAdded';
+		private static const NODE_CHANGED:String = 'nodeChanged';
+		private static const NODE_REMOVED:String = 'nodeRemoved';
+		private static const TEXT_SET:String = 'textSet';
+		private static const NAME_SET:String = 'nameSet';
+		private static const NAMESPACE_SET:String = 'namespaceSet';
+		private static const NAMESPACE_ADDED:String = 'namespaceAdded';
+		private static const NAMESPACE_REMOVED:String = 'namespaceRemoved';
+
+
+		private static var _inst:NotificationXML;
+		private static var _instX:XML;
+		private static var _unlocked:Boolean;
+
+		private static function init():void{
+			_unlocked = true;
+			//hack so that instance.constructor points to XML class:
+			NotificationXML.prototype.constructor = XML;
+			_inst = new NotificationXML();
+			_instX = new XML();
+			_unlocked = false;
+		}
+
+		public static function getUpgradeTemplate():XML{
+			var inst:XML =_inst
+			if (!inst){
+				init();
+				inst = _inst;
+			}
+			return inst;
+		}
+
+		public static function getDowngradeTemplate():XML{
+			var inst:XML =_instX;
+			if (!inst){
+				init();
+				inst = _instX;
+			}
+			return inst;
+		}
+
+		public function NotificationXML(){
+			if (!_unlocked) throw new Error('Forbidden - internal utility class only');
+		}
+
+
+		override public function setNamespace(ns:Object):void{
+			super.setNamespace(ns);
+			/*if (_notificationFunction != null)*/ _notificationFunction(this, NAMESPACE_SET, this, ns, null);
+		}
+
+		override public function setValue(value:String):void{
+			super.setValue(value);
+		//	if (_notificationFunction != null) {
+				_notificationFunction(this, TEXT_SET, this, value, null);
+				_notificationFunction(this, NODE_ADDED, this, this, null);
+		//	}
+		}
+
+		override protected function appendChildInternal(child:*):void
+		{
+			var before:int = _children ? _children.length : 0
+			super.addChildInternal(child);
+			var after:Array = _children;
+			if (after && after.length) {
+				var l:uint = after.length;
+				//if (_notificationFunction != null) {
+					for (var i:uint = before; i < l;i++ ) {
+						var xml:XML = after[i];
+						if (xml.nodeKind() == 'text') {
+							_notificationFunction(this, TEXT_SET, xml, xml.getValue(), null);
+							_notificationFunction(xml, NODE_ADDED, xml, xml, null);
+						} else {
+							_notificationFunction(this, NODE_ADDED, this, xml, null);
+						}
+					}
+				//}
+			}
+		}
+
+		override public function removeChild(child:XML):Boolean
+		{
+			if (!child) return false;
+			var isAtt:Boolean = false;
+			if (child is XML && child.nodeKind() == 'attribute') {
+				isAtt = true;
+			} else if (child is String && (child+'').charAt(0) == '@'){
+				isAtt = true;
+			}
+			var originalAtts:Array;
+			if (isAtt) {
+				originalAtts = attributes ? _attributes.slice(): [];
+			}
+			const removed:Boolean = super.removeChild(child);
+			if (removed && originalAtts) {
+				var currentAtts:Array = _attributes;
+				var l:uint = originalAtts.length;
+				while (l) {
+					l--;
+					if (currentAtts.indexOf(originalAtts[l]) == -1) {
+						_notificationFunction(this, ATTRIBUTE_REMOVED, this, originalAtts[l].localName(), originalAtts[l].getValue());
+					}
+				}
+			}
+			return removed;
+		}
+
+		override public function replace(propertyName:Object, value:*):*
+		{
+			_replacing = true;
+			super.replace(propertyName, value);
+			_replacing = false;
+			_notificationFunction(this, NODE_CHANGED, this, value, value); //not sure what 'detail' should be here
+		}
+		private var _replacing:Boolean;
+
+		override protected function childRemoved(child:XML, index:int):void{
+			super.childRemoved(child, index);
+			if (!_replacing)
+				_notificationFunction(this, NODE_REMOVED, this, child, null);//not sure what 'detail' should be here
+		}
+
+		override protected function attributeUpdated(attribute:XML, value:String):void{
+			var oldVal:String = attribute.getValue();
+			super.attributeUpdated(attribute, value);
+			_notificationFunction(this, ATTRIBUTE_CHANGED, this,  attribute.name()+'', oldVal);
+		}
+
+		override protected function addChildInternal(child:XML):void
+		{
+			super.addChildInternal(child);
+			//if (_notificationFunction != null) {
+				if(child.nodeKind() == 'attribute') {
+					//add or update
+
+					_notificationFunction(this, ATTRIBUTE_ADDED, this,  child.name()+'', child.toString());
+				} else {
+					_notificationFunction(this, NODE_ADDED, this, child, null);//not sure what 'detail' should be here
+				}
+			//}
+		}
+
+		override public function insertChildAfter(child1:XML, child2:XML):XML
+		{
+			var result:XML = super.insertChildAfter(child1, child2);
+			if (result) {
+
+
+			}
+			return result;
+		}
+
+		override public function setAttribute(attr:*,value:String):String
+		{
+			value = super.setAttribute(attr,value);
+			//if (_notificationFunction !=null) {
+				if (attr is XML && (attr as XML).nodeKind() == 'attribute') {
+					_notificationFunction(this, ATTRIBUTE_ADDED, this, attr.name()+'', value);
+				}
+			//}
+			return value;
+		}
+
+
+		override public function setName(name:*):void
+		{
+			var detail:String = this.name()+'';
+			super.setName(name);
+			_notificationFunction(this, NAME_SET, this, name, detail);
+		}
+
+	}
+}
diff --git a/frameworks/projects/XML/src/test/royale/flexUnitTests/XMLTester.as b/frameworks/projects/XML/src/test/royale/flexUnitTests/XMLTester.as
index c709f98..c7c0347 100644
--- a/frameworks/projects/XML/src/test/royale/flexUnitTests/XMLTester.as
+++ b/frameworks/projects/XML/src/test/royale/flexUnitTests/XMLTester.as
@@ -52,7 +52,7 @@ package flexUnitTests
 
         public var xmlLiteralTest:XMLLiteralTest;
 
-       // public var xmlNotificationTest:XMLNotificationTest;
+        public var xmlNotificationTest:XMLNotificationTest;
         
     }
 }