| // Copyright 2009 Google Inc. All Rights Reserved. |
| // |
| // Licensed 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. |
| |
| /** |
| * @fileoverview Walker to listen to DOM events and dispatch events representing |
| * same-directionality sequences of text in the same block-level element of the |
| * DOM. |
| */ |
| |
| |
| goog.provide('bidichecker.DirChunkWalker'); |
| |
| goog.require('bidichecker.DirChunk'); |
| goog.require('bidichecker.DomWalker'); |
| goog.require('bidichecker.NullDirChunk'); |
| goog.require('goog.events.Event'); |
| goog.require('goog.events.EventHandler'); |
| goog.require('goog.events.EventTarget'); |
| |
| |
| /** |
| * A walker which dispatches an event for each same-directionality chunk of text |
| * within a block in the DOM. |
| * @param {bidichecker.DomWalker} domWalker A walker which dispatches DOM node |
| * events while walking the DOM of a particular block. |
| * @constructor |
| * @extends {goog.events.EventTarget} |
| */ |
| bidichecker.DirChunkWalker = function(domWalker) { |
| goog.events.EventTarget.call(this); |
| |
| /** |
| * The current chunk under assembly. When complete, a DirChunk event is |
| * dispatched and a listener can access the chunk using {@code getChunk()}. |
| * @type {bidichecker.DirChunk} |
| * @private |
| */ |
| this.chunk_ = bidichecker.NullDirChunk; |
| |
| /** |
| * Service object to manage cleanup of event listeners. |
| * @type {goog.events.EventHandler} |
| * @private |
| */ |
| this.eventHandler_ = new goog.events.EventHandler(this); |
| |
| // Listen for text node events and the end-of-DOM event. |
| this.eventHandler_.listen(domWalker, |
| bidichecker.DomWalker.EventTypes.TEXT_NODE, |
| this.handleTextNode_); |
| this.eventHandler_.listenOnce(domWalker, |
| bidichecker.DomWalker.EventTypes.END_OF_DOM, |
| this.handleEndOfDom_); |
| }; |
| goog.inherits(bidichecker.DirChunkWalker, goog.events.EventTarget); |
| |
| |
| /** |
| * Event types dispatched by {@code bidichecker.DirChunkWalker}. |
| * @enum {string} |
| */ |
| bidichecker.DirChunkWalker.EventTypes = { |
| DIR_CHUNK: 'DirChunk', |
| END_OF_CHUNKS: 'EndOfChunks' |
| }; |
| |
| |
| /** |
| * Handles events indicating a text node in the DOM by updating the current |
| * chunk or creating an new one. Dispatches a DirChunk event if the end of a |
| * chunk is encountered. |
| * @param {!goog.events.Event} event A TextNode event. |
| * @private |
| */ |
| bidichecker.DirChunkWalker.prototype.handleTextNode_ = function(event) { |
| var domWalker = event.target; |
| var node = domWalker.getNode(); |
| if (this.chunk_.hasSameContext(domWalker.inRtl(), |
| domWalker.getCurrentBlock(), |
| domWalker.inDeclaredDir())) { |
| // No change of directionality context - just accumulate the content. |
| this.chunk_.append(node.data, node); |
| } else { |
| // When the direction changes or the block changes, return the previous |
| // chunk and start a new one. |
| // TODO(user): Also handle Unicode BiDi marks in node.data, including |
| // LRE, RLE, RLO, LRO and PDF. |
| if (!this.chunk_.isEmpty()) { |
| this.dispatchEvent(bidichecker.DirChunkWalker.EventTypes.DIR_CHUNK); |
| } |
| |
| this.chunk_ = new bidichecker.DirChunk( |
| node.data, |
| domWalker.inRtl(), |
| node, |
| domWalker.getCurrentBlock(), |
| domWalker.inDeclaredDir()); |
| } |
| }; |
| |
| |
| /** |
| * Handles an end-of-DOM event by dispatching a DirChunk event if a non-empty |
| * chunk is available, then dispatching an EndOfChunks event (always). Also |
| * unlistens from all DOM events. |
| * @param {!goog.events.Event} event An EndOfDom event. |
| * @private |
| */ |
| bidichecker.DirChunkWalker.prototype.handleEndOfDom_ = function(event) { |
| if (!this.chunk_.isEmpty()) { |
| // Need to handle leftovers at end. |
| this.dispatchEvent(bidichecker.DirChunkWalker.EventTypes.DIR_CHUNK); |
| } |
| this.dispatchEvent(bidichecker.DirChunkWalker.EventTypes.END_OF_CHUNKS); |
| |
| // Stop listening to DOM events. |
| this.eventHandler_.removeAll(); |
| }; |
| |
| |
| /** |
| * Returns the current chunk (either complete or under construction). |
| * @return {bidichecker.DirChunk} The chunk. |
| */ |
| bidichecker.DirChunkWalker.prototype.getChunk = function() { |
| return this.chunk_; |
| }; |