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

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

commit 463cb05bae25f4d6fe9e7d3c30fe04ab61e59178
Author: greg-dove <[email protected]>
AuthorDate: Thu Sep 1 14:58:22 2022 +1200

    Adding an initial Simple Text Highlighter component (JS-only functionality, 
compiles-only for SWF)
---
 .../Basic/src/main/resources/basic-manifest.xml    |   2 +
 .../projects/Basic/src/main/resources/defaults.css |  19 +
 .../projects/Basic/src/main/royale/BasicClasses.as |   2 +
 .../apache/royale/html/SimpleTextHighlighter.as    | 557 +++++++++++++++++++++
 .../html/supportClasses/HighlightTextSpan.as       | 256 ++++++++++
 5 files changed, 836 insertions(+)

diff --git a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml 
b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
index 64d184c470..e800947b36 100644
--- a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
+++ b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
@@ -303,6 +303,8 @@
     <component id="BrowserRouter" 
class="org.apache.royale.routing.BrowserRouter"/>
 
     <component id="UIGraphicsBase" 
class="org.apache.royale.display.UIGraphicsBase"/>
+
+    <component id="SimpleTextHighlighter" 
class="org.apache.royale.html.SimpleTextHighlighter"/>
        
        <component id="CollectionSelectedItemByField" 
class="org.apache.royale.html.beads.CollectionSelectedItemByField"/>      
     <component id="ErrorImage" 
class="org.apache.royale.html.beads.ErrorImage"/>
diff --git a/frameworks/projects/Basic/src/main/resources/defaults.css 
b/frameworks/projects/Basic/src/main/resources/defaults.css
index 4ed871e658..260aa56397 100644
--- a/frameworks/projects/Basic/src/main/resources/defaults.css
+++ b/frameworks/projects/Basic/src/main/resources/defaults.css
@@ -544,6 +544,8 @@ TableCell
        /* use browser default style */
 }
 
+
+
 MultiSelectionTree
 {
        IBeadModel: 
ClassReference("org.apache.royale.html.beads.models.MultiSelectionTreeModel");
@@ -827,6 +829,23 @@ global
        effectTimerInterval: 10;
 }
 
+
+.SimpleTextHighlighter {
+       border: 1px #808080 solid;
+       white-space: pre-wrap;
+       overflow-y: auto;
+}
+
+.SimpleTextHighlighter *:focus-visible {
+       outline: none;
+}
+
+.HighlightTextSpan {
+       background-color: #00ffff;
+       border-radius: 2px;
+}
+
+
 @media -royale-swf
 {
        /* Global style declaration for Flash only.  This will effectively be 
the same
diff --git a/frameworks/projects/Basic/src/main/royale/BasicClasses.as 
b/frameworks/projects/Basic/src/main/royale/BasicClasses.as
index 670ce46cdc..fab74b8242 100644
--- a/frameworks/projects/Basic/src/main/royale/BasicClasses.as
+++ b/frameworks/projects/Basic/src/main/royale/BasicClasses.as
@@ -361,6 +361,8 @@ internal class BasicClasses
                import org.apache.royale.html.util.DialogPolyfill; 
DialogPolyfill;
                import org.apache.royale.html.beads.OverflowTooltipNeeded; 
OverflowTooltipNeeded;
        }
+
+       import org.apache.royale.html.SimpleTextHighlighter; 
SimpleTextHighlighter;
 }
 
 }
diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/SimpleTextHighlighter.as
 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/SimpleTextHighlighter.as
new file mode 100644
index 0000000000..29c5d313c0
--- /dev/null
+++ 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/SimpleTextHighlighter.as
@@ -0,0 +1,557 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.html
+{
+       import org.apache.royale.core.ITextModel;
+       import org.apache.royale.core.UIBase;
+    import org.apache.royale.events.Event;
+    import org.apache.royale.events.IEventDispatcher;
+    import org.apache.royale.html.supportClasses.HighlightTextSpan;
+
+    COMPILE::JS
+    {
+        import goog.events;
+        import org.apache.royale.core.WrappedHTMLElement;
+        import org.apache.royale.html.util.addElementToWrapper;
+    }
+
+    /**
+     *  Dispatched when the user changes the text.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.9.0
+     */
+    [Event(name="change", type="org.apache.royale.events.Event")]
+
+    /**
+     *  This class is a utility class for simple highlighting of
+     *  editable text.
+     *
+     *  @toplevel
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+       public class SimpleTextHighlighter extends UIBase
+       {
+
+
+
+
+
+        /**
+         *  Constructor.
+         *
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.0
+         */
+               public function SimpleTextHighlighter()
+               {
+                       super();
+
+            COMPILE::SWF
+            {
+                model.addEventListener("textChange", textChangeHandler);
+            }
+               }
+
+        private var _parentRef:Object;
+
+
+        COMPILE::JS
+        private var _textContainer:HTMLSpanElement;
+
+        private var _textLength:uint;
+
+        private var _lengthValid:Boolean = true;
+
+        private function textLength():uint{
+            if (!_lengthValid) {
+                _textLength = text.length;
+                _lengthValid = true;
+            }
+            return _textLength;
+        }
+
+        /**
+         *  @copy org.apache.royale.html.Label#text
+         *
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.0
+         *  @royaleignorecoercion HTMLTextAreaElement
+         */
+       [Bindable(event="change")]
+               public function get text():String
+               {
+            COMPILE::SWF
+            {
+                return ITextModel(model).text;
+            }
+            COMPILE::JS
+            {
+                return  _textContainer.textContent;
+            }
+               }
+
+        /**
+         *  @private
+         *  @royaleignorecoercion HTMLDivElement
+         */
+               public function set text(value:String):void
+               {
+            COMPILE::SWF
+            {
+                inSetter = true;
+                ITextModel(model).text = value;
+                inSetter = false;
+            }
+            COMPILE::JS
+            {
+                if (value != _textContainer.textContent) {
+                    _textContainer.textContent = value;
+                    dispatchEvent(new Event('textChange'));
+                }
+            }
+
+            _lengthValid = false;
+               }
+
+
+        protected var _highLights:Array = [];
+
+        public function removeHighlights():void{
+            COMPILE::JS
+            {
+
+                //this will quickly remove all html (highlight blocks)
+                var selection:Selection = window.getSelection();
+                var reselect:Boolean;
+                var offset:uint = 0;
+                var end:uint = 0;
+                if (selection.rangeCount) {
+                    var selectionRange:Range = selection.getRangeAt(0);
+                    if (_textContainer == 
selectionRange.commonAncestorContainer || 
_textContainer.contains(selectionRange.commonAncestorContainer)) {
+                        var foundStart:Boolean;
+                        reselect = true;
+                        var node:Node = _textContainer.firstChild;
+                        while(node) {
+                            var tn:Node = node.nodeType == Node.TEXT_NODE ? 
node : node.firstChild;
+                            if (!foundStart) {
+                                if (selectionRange.startContainer == node || 
selectionRange.startContainer == tn) {
+                                    foundStart = true;
+                                    offset += selectionRange.startOffset;
+
+                                    if (selectionRange.endContainer == node || 
selectionRange.endContainer == tn) {
+                                        end = offset + 
(selectionRange.endOffset - selectionRange.startOffset);
+                                        break;
+                                    } else {
+                                        end += node.textContent.length;
+                                    }
+                                } else {
+                                    offset += node.textContent.length;
+                                    end = offset;
+                                }
+                            } else {
+                                if (selectionRange.endContainer == node || 
selectionRange.endContainer == tn) {
+                                    end += selectionRange.endOffset;
+                                    break;
+                                } else {
+                                    end += node.textContent.length;
+                                }
+                            }
+                            node = node.nextSibling;
+                        }
+                    }
+                }
+
+                var plainText:String = text;
+                _textContainer.textContent = plainText;
+                _highLights.length = 0;
+                if (reselect) {
+                    selectionRange = document.createRange();
+                    node = _textContainer.firstChild ? 
_textContainer.firstChild : _textContainer;
+                    selectionRange.setStart(node,offset);
+                    selectionRange.setEnd(node,end);
+                    selection.removeAllRanges();
+                    selection.addRange(selectionRange);
+                }
+            }
+        }
+
+        /**
+         *
+         * can be overridden in subclasses
+         */
+        protected function createHighlightSpan(begin:int, 
end:int):HighlightTextSpan{
+            return new HighlightTextSpan(begin,end,_parentRef);
+        }
+
+        private var _autoRemoveHighlightChanges:Boolean;
+        public function get autoRemoveHighlightChanges():Boolean{
+            return _autoRemoveHighlightChanges
+        }
+
+        public function set autoRemoveHighlightChanges(value:Boolean):void{
+            _autoRemoveHighlightChanges = value;
+        }
+
+        /**
+         * @royaleignorecoercion org.apache.royale.core.WrappedHTMLElement
+         */
+        private function restoreIfNeeded():void{
+            COMPILE::JS{
+                //"undo" editing can restore items that were previously 
'removed'
+                var l:uint = _highLights.length;
+                if (_textContainer.childElementCount > l) {
+                    var collect:Array = [];
+                    var wrappedElement:WrappedHTMLElement = 
WrappedHTMLElement(_textContainer.firstElementChild);
+                    while (wrappedElement) {
+                        var highlight:HighlightTextSpan = 
wrappedElement.royale_wrapper as HighlightTextSpan;
+                        if (highlight) collect.push(highlight);
+                        wrappedElement = 
WrappedHTMLElement(wrappedElement.nextElementSibling)
+                    }
+                    _highLights = collect;
+                }
+            }
+        }
+
+
+        private function performAutoRemove():void{
+            var l:uint = _highLights.length;
+            if (l) {
+                var retained:Array = [];
+                for (var i:int = 0;i<l;i++) {
+                    var removeCheck:HighlightTextSpan = _highLights[i] as 
HighlightTextSpan;
+                    if (_autoRemoveHighlightChanges) {
+                        if (removeCheck.isUnchanged) {
+                            retained.push(removeCheck)
+                            removeCheck = null;
+                        }
+                    } else {
+                        if (removeCheck.isPresent) {
+                            retained.push(removeCheck)
+                            removeCheck = null;
+                        }
+                    }
+                    if (removeCheck) {
+                        removeCheck.unapply();
+                    }
+                }
+                _highLights = retained;
+            }
+        }
+
+        /**
+         *
+         * Utility method for unHighlighting text.
+         *
+         * returns true if highlighting occurred, false otherwise
+         */
+        public function removeHighlightForText(string:String, 
fromIndex:uint=0, all:Boolean=false):Boolean{
+            var l:uint = _highLights.length;
+            var success:Boolean;
+            if (l && string) {
+                if (string) {
+                    var idx:int = text.indexOf(string,fromIndex);
+                    while (idx != -1) {
+                        success =  removeHighlightForRange(idx) || success;
+                        if (all || !success) {
+                            idx = text.indexOf(string,idx + string.length);
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            }
+            return success;
+        }
+
+
+        public function removeHighlightForRange(containsIndex:uint):Boolean{
+            var l:uint = _highLights.length;
+            if (l) {
+                for (var i:int = 0;i<l;i++) {
+                    var highlight:HighlightTextSpan = _highLights[i] as 
HighlightTextSpan;
+                    if (highlight.containsIndex(containsIndex)) {
+                        _highLights.splice(i,1);
+                        highlight.unapply();
+                        return true;
+                        break;
+                    }
+                }
+            }
+            return false;
+        }
+
+
+        /**
+         *
+         * Utility method for highlighting text.
+         *
+         * returns true if highlighting occurred, false otherwise
+         */
+        public function highlightText(string:String, fromIndex:uint=0, 
all:Boolean=false):Boolean{
+            var ret:Boolean;
+            if (string) {
+                var text:String = this.text;
+                var idx:int = text.indexOf(string,fromIndex);
+                while (idx != -1) {
+                    ret = highlightOffsetRange(idx, string.length, !all) || 
ret;
+                    if (all && text.length > idx + string.length) {
+                        idx = text.indexOf(string, idx + string.length);
+                    } else idx = -1;
+                }
+            }
+            return ret;
+        }
+
+        /**
+         *
+         * This method uses the same range logic as String.substr
+         * (begin: first char index, length: char count to be included)
+         * if 'single' is true, any previous highlights will be removed prior 
to the new highlight range
+         * being added
+         *
+         * returns true if highlighting occurred, false otherwise
+         *
+         */
+        public function highlightOffsetRange(begin:uint, length:uint, 
single:Boolean):Boolean{
+            if (length > 0) {
+                return highlightRange(begin,begin+length,single);
+            }
+            return false;
+        }
+
+
+        /**
+         *
+         * This method uses the same range logic as String.substring
+         * (begin: first char index, end: char index after last)
+         * if 'single' is true, any previous highlights will be removed prior 
to the new highlight range
+         * being added
+         *
+         * returns true if highlighting occurred, false otherwise
+         *
+         * @royaleignorecoercion 
org.apache.royale.html.supportClasses.HighlightTextSpan
+         */
+        public function highlightRange(begin:uint, end:uint, 
single:Boolean):Boolean{
+            var tl:uint = textLength();
+            if (end > tl) end = tl;
+            if (begin >= end) return false;
+            var l:uint = _highLights.length;
+            if (single) {
+                if (l) {
+                    removeHighlights();
+                    l = 0;
+                }
+            }
+
+            var insertAt:int = -1;
+            if (l) {
+                for (var i:int = 0;i<l;i++) {
+                    var highlight:HighlightTextSpan = _highLights[i] as 
HighlightTextSpan;
+                    if (highlight.intersectsRange(begin,end)) {
+                        //for now, simple exclusions apply
+                       // throw new Error('Highlight ranges must be exclusive')
+
+                        return false;
+                    }
+                    if (highlight.beginIndex >= end ) {
+                        if (insertAt == -1) //we need the first location
+                            insertAt = i;
+                    }
+                }
+            }
+            if (insertAt == -1) insertAt = l;
+            var newHighLight:HighlightTextSpan = 
createHighlightSpan(begin,end);
+            if (insertAt == l) {
+                _highLights[insertAt] = newHighLight
+            } else {
+                _highLights.splice(insertAt,0,newHighLight);
+            }
+
+            newHighLight.apply();
+            return true;
+        }
+
+        COMPILE::JS
+        private var docListening:Boolean;
+
+        COMPILE::JS
+        private function enforceUnselectable(selection:Selection):void{
+
+            var selectionRange:Range = selection.getRangeAt(0);
+            var location:Node = selectionRange.endContainer;
+            var endOffset:uint = selectionRange.endOffset;
+            if (location != selectionRange.startContainer || 
selectionRange.startOffset != selectionRange.endOffset) {
+                selection.removeAllRanges();
+                selectionRange = document.createRange();
+                selectionRange.setStart(location,endOffset);
+                selectionRange.collapse(true);
+                selection.addRange(selectionRange);
+            }
+        }
+
+        COMPILE::JS
+        protected function onLostFocus(event:Event):void{
+            if (docListening){
+                document.removeEventListener('selectionchange',onSelectEvent);
+                docListening = false;
+            }
+        }
+
+        protected function onSelectEvent(event:Event):void{
+
+            COMPILE::JS{
+                var selection:Selection;
+                if (!docListening) {
+                    document.addEventListener('selectionchange',onSelectEvent);
+                    docListening = true;
+                }
+                if (!_selectable) {
+                    if (docListening){
+                        selection = window.getSelection();
+                        if (event.type == 'selectionchange') {
+                            if (selection.baseNode != _textContainer && 
!_textContainer.contains(selection.baseNode)) {
+                                
document.removeEventListener('selectionchange',onSelectEvent);
+                                docListening = false;
+                                return;
+                            }
+                        }
+                    }
+                    enforceUnselectable(selection);
+                }
+                selection = window.getSelection();
+
+            }
+
+            //trace(event)
+        }
+
+
+        private var _wordWrap:Boolean = true;
+        public function get wordWrap():Boolean {
+            return _wordWrap;
+        }
+
+        public function set wordWrap(value:Boolean):void {
+            if (_wordWrap != value) {
+                _wordWrap = value;
+                COMPILE::JS{
+                    if (value) {
+                        element.style.whiteSpace = 'pre-wrap';
+                    } else {
+                        element.style.whiteSpace = 'pre';
+                    }
+                }
+            }
+        }
+
+
+        private var _selectable:Boolean = true;
+        public function get selectable():Boolean {
+            return _selectable;
+        }
+
+        public function set selectable(value:Boolean):void {
+            if (_selectable != value) {
+                _selectable = value;
+                COMPILE::JS{
+                    if (value) {
+                        _textContainer.style.userSelect = '';
+                    } else {
+                        _textContainer.style.userSelect = 'none';
+                    }
+                }
+            }
+        }
+
+        private var _editable:Boolean = true;
+        public function get editable():Boolean {
+            return _editable;
+        }
+
+        public function set editable(value:Boolean):void {
+            if (_editable != value) {
+                _editable = value;
+                COMPILE::JS{
+                    _textContainer.contentEditable = String(value) ;
+                    if (value) {
+                        // element.addEventListener('input', onInput)
+                        goog.events.listen(_textContainer, 'input', 
textChangeHandler);
+                    } else {
+                        // element.removeEventListener('input', onInput);
+                        goog.events.unlisten(_textContainer, 'input', 
textChangeHandler);
+                    }
+                }
+            }
+        }
+
+        /**
+         * @royaleignorecoercion org.apache.royale.core.WrappedHTMLElement
+         * @royaleignorecoercion HTMLSpanElement
+         */
+        COMPILE::JS
+        override protected function createElement():WrappedHTMLElement
+        {
+                       addElementToWrapper(this,'div');
+            _textContainer = document.createElement('span') as HTMLSpanElement;
+            _textContainer.onselectstart = onSelectEvent;
+            _textContainer.onblur = onLostFocus;
+            //for JS the parentRef is the parent span
+            _parentRef = _textContainer;
+            element.appendChild(_textContainer);
+            _textContainer.contentEditable = "true";
+            goog.events.listen(_textContainer, 'input', textChangeHandler);
+            typeNames = 'SimpleTextHighlighter';
+            return element;
+        }
+
+        private var inSetter:Boolean;
+
+        /**
+         *  dispatch change event in response to a textChange event
+         *
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.9.0
+         */
+        public function textChangeHandler(event:Event):void
+        {
+            COMPILE::JS{
+                if (!inSetter)
+                {
+                    _lengthValid = false;
+                    restoreIfNeeded();
+                    performAutoRemove();
+                    dispatchEvent(new Event(Event.CHANGE));
+                }
+            }
+
+        }
+       }
+}
diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/supportClasses/HighlightTextSpan.as
 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/supportClasses/HighlightTextSpan.as
new file mode 100644
index 0000000000..2143c757dd
--- /dev/null
+++ 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/supportClasses/HighlightTextSpan.as
@@ -0,0 +1,256 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.html.supportClasses {
+
+
+COMPILE::JS{
+        import org.apache.royale.core.WrappedHTMLElement
+    }
+
+
+    /**
+     * @royalesuppressexport
+     */
+    public class HighlightTextSpan{
+
+        private var _beginIndex: uint ;
+        private var _endIndex: uint ;
+       // private var _className:String = 'HighlightTextSpan';
+
+        COMPILE::JS
+        private static var _ranges:WeakMap = new WeakMap();
+
+        COMPILE::JS
+        protected var _parentSpan:HTMLSpanElement;
+
+        COMPILE::JS
+        protected var _span:HTMLSpanElement;
+
+        /**
+         *
+         * @royaleignorecoercion HTMLSpanElement
+         */
+        public function HighlightTextSpan(beginIndex: uint=0, endIndex: uint=0,
+                                          parent:Object=null, className:String 
= null) {
+            _beginIndex = beginIndex;
+            _endIndex = endIndex;
+            COMPILE::JS{
+                _parentSpan = parent as HTMLSpanElement
+                _text = _parentSpan.textContent.substring(beginIndex,endIndex);
+            }
+            if (className) {
+                this.className = className;
+            }
+        }
+
+
+
+        public function isValid():Boolean{
+            return _endIndex > _beginIndex;
+        }
+
+        COMPILE::JS
+        private function getRange():Range{
+            var range:Range = _ranges.get(_parentSpan);
+            if (!range) {
+                range = document.createRange();
+                _ranges.set(_parentSpan, range);
+                range.selectNodeContents(_parentSpan);
+            }
+            return range;
+        }
+
+        public function get beginIndex():uint {
+            return _beginIndex;
+        }
+
+        public function get endIndex():uint {
+            return _endIndex;
+        }
+
+        public function get textRepresentation():String{
+            var ret:String;
+            COMPILE::JS{
+                if (_span) {
+                    ret = _span.textContent;
+                }
+                else if (_parentSpan) {
+                    ret = 
_parentSpan.textContent.substring(_beginIndex,_endIndex);
+                }
+            }
+
+            return ret;
+        }
+
+        private var _text:String;
+        /**
+         * the original text at the time of construction
+         */
+        public function get text():String{
+            return _text;
+        }
+
+        public function get isUnchanged():Boolean{
+            return _text == textRepresentation && isPresent;
+        }
+
+        public function get isPresent():Boolean{
+            var absent:Boolean;
+            COMPILE::JS{
+                absent = _span.parentNode != _parentSpan;
+            }
+            return !absent;
+        }
+
+
+        private var _className:String;
+
+        public function get className():String {
+            return _className;
+        }
+
+        public function set className(value:String):void {
+            COMPILE::JS{
+                if (_span && _className) {
+                    _span.classList.remove(_className);
+                }
+            }
+            _className = value;
+            COMPILE::JS{
+                if (_span && value) {
+                    _span.classList.add(value);
+                }
+            }
+        }
+
+        public function unapply():void{
+            COMPILE::JS{
+                if (_span) {
+                    if(_span.parentNode == _parentSpan) {
+                        while(_span.firstChild) {
+                            _parentSpan.insertBefore(_span.firstChild,_span)
+                        }
+                        _parentSpan.removeChild(_span);
+                    }
+                    //_span = null;
+                }
+            }
+        }
+
+        /**
+         *
+         * @royaleignorecoercion HTMLSpanElement
+         * @royaleignorecoercion org.apache.royale.core.WrappedHTMLElement
+         */
+        public function apply():void{
+            COMPILE::JS{
+                if (!_span) {
+                    _span = document.createElement('span') as HTMLSpanElement;
+                    element = (_span as WrappedHTMLElement)
+                    element.royale_wrapper = this;
+                    _span.className = 'HighlightTextSpan';
+                    var c:String = className;
+                    if (c) {
+                        _span.classList.add(c)
+                    }
+
+                    var range:Range = getRange();
+                    var node:Node = _parentSpan.firstChild;
+                    var beginNode:Node;
+                    var beginOffset:uint;
+                    var endNode:Node;
+                    var endOffset:uint;
+                    var offset:uint = _beginIndex;
+                    var l:uint;
+                    while(node) {
+                        l = node.textContent.length;
+                        if (l <= offset) {
+                            offset -= l;
+                        } else {
+                            //no need to distinguish between nodes (nodeType 
== Node.TEXT_NODE etc),
+                            //because we are only ever a sequence of text 
nodes or span nodes
+                            if (!beginNode) {
+                                beginNode = node;
+                                beginOffset = offset;
+                                offset = offset + (_endIndex - _beginIndex);
+                                if (l < offset) {
+                                    offset -= l;
+                                } else {
+                                    endNode = node;
+                                    endOffset = offset;
+                                    break;
+                                }
+                            } else {
+                                endNode = node;
+                                endOffset = offset;
+                                break;
+                            }
+                        }
+                        node = node.nextSibling;
+                    }
+                    range.setStart(beginNode,beginOffset);
+                    range.setEnd(endNode,endOffset);
+
+                    range.surroundContents(_span);
+                }
+
+            }
+        }
+        
+
+        public function containsIndex(index:uint):Boolean{
+            return index >=_beginIndex && index < _endIndex;
+        }
+
+        public function equalsRange(beginIndex:uint, endIndex:uint):Boolean{
+            if (beginIndex > endIndex) {
+                var temp:uint = endIndex;
+                endIndex = beginIndex;
+                beginIndex = temp;
+            }
+            return _beginIndex == beginIndex && _endIndex == endIndex;
+        }
+
+        public function containsRange(beginIndex:uint, endIndex:uint):Boolean{
+            if (beginIndex > endIndex) {
+                var temp:uint = endIndex;
+                endIndex = beginIndex;
+                beginIndex = temp;
+            }
+            return _beginIndex <= beginIndex &&  _endIndex >= endIndex;
+        }
+
+        public function intersectsRange(beginIndex:uint, 
endIndex:uint):Boolean{
+            if (beginIndex > endIndex) {
+                var temp:uint = endIndex;
+                endIndex = beginIndex;
+                beginIndex = temp;
+            }
+            return Math.max(_beginIndex, beginIndex) < Math.min(_endIndex, 
endIndex);
+        }
+
+
+        COMPILE::JS
+        public var element:WrappedHTMLElement;
+
+
+
+    }
+}
+

Reply via email to