OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 cr.define('bmm', function() { |
| 6 /** |
| 7 * An inorder (document order) iterator for iterating over a bookmark tree. |
| 8 * |
| 9 * <pre> |
| 10 * var it = new TreeIterator(node); |
| 11 * while (it.moveNext()) { |
| 12 * print(it.current.title); |
| 13 * } |
| 14 * </pre> |
| 15 * |
| 16 * @param {!BookmarkTreeNode} node The node to start at. |
| 17 * @constructor |
| 18 */ |
| 19 function TreeIterator(node) { |
| 20 this.current_ = node; |
| 21 this.parentStack_ = []; |
| 22 this.indexStack_ = []; |
| 23 } |
| 24 |
| 25 /** |
| 26 * Helper function for {@code TreeIterator.prototype.next}. This returns the |
| 27 * next node in document order. |
| 28 * @param {BookmarkTreeNode} node The current node. |
| 29 * @param {!Array.<!BookmarkTreeNode>} parents A stack of parents. |
| 30 * @param {!Array.<number>} index A stack of indexes. |
| 31 * @return {BookmarkTreeNode} The next node or null if no more nodes can be |
| 32 * found. |
| 33 */ |
| 34 function getNext(node, parents, index) { |
| 35 var i, p; |
| 36 |
| 37 if (!node) |
| 38 return null; |
| 39 |
| 40 // If the node has children return first child. |
| 41 if (node.children && node.children.length) { |
| 42 parents.push(node); |
| 43 index.push(0); |
| 44 return node.children[0]; |
| 45 } |
| 46 |
| 47 if (!parents.length) |
| 48 return null; |
| 49 |
| 50 // Walk up the parent stack until we find a node that has a next sibling. |
| 51 while (node) { |
| 52 p = parents[parents.length - 1]; |
| 53 if (!p) |
| 54 return null; |
| 55 i = index[index.length - 1]; |
| 56 if (i + 1 < p.children.length) |
| 57 break; |
| 58 node = parents.pop(); |
| 59 index.pop(); |
| 60 } |
| 61 |
| 62 // Walked out of subtree. |
| 63 if (!parents.length || !node) |
| 64 return null; |
| 65 |
| 66 // Return next child. |
| 67 i = ++index[index.length - 1]; |
| 68 p = parents[parents.length - 1]; |
| 69 return p.children[i]; |
| 70 } |
| 71 |
| 72 TreeIterator.prototype = { |
| 73 /** |
| 74 * Whether the next move will be the first move. |
| 75 * @type {boolean} |
| 76 * @private |
| 77 */ |
| 78 first_: true, |
| 79 |
| 80 /** |
| 81 * Moves the iterator to the next item. |
| 82 * @return {boolean} Whether we succeeded moving to the next item. This |
| 83 * returns false when we have moved off the end of the iterator. |
| 84 */ |
| 85 moveNext: function() { |
| 86 // The first call to this should move us to the first node. |
| 87 if (this.first_) { |
| 88 this.first_ = false; |
| 89 return true; |
| 90 } |
| 91 this.current_ = getNext(this.current_, this.parentStack_, |
| 92 this.indexStack_); |
| 93 |
| 94 return !!this.current_; |
| 95 }, |
| 96 |
| 97 /** |
| 98 * The current item. This throws an exception if trying to access after |
| 99 * {@code moveNext} has returned false or before {@code moveNext} has been |
| 100 * called. |
| 101 * @type {!BookmarkTreeNode} |
| 102 */ |
| 103 get current() { |
| 104 if (!this.current_ || this.first_) |
| 105 throw Error('No such element'); |
| 106 return this.current_; |
| 107 } |
| 108 }; |
| 109 |
| 110 return { |
| 111 TreeIterator: TreeIterator |
| 112 }; |
| 113 }); |
OLD | NEW |