yellow-brick-road 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.rst +10 -5
  2. data/lib/yellow-brick-road/directive_processor.rb +10 -3
  3. data/lib/yellow-brick-road/version.rb +1 -1
  4. data/test/dummy/app/assets/javascripts/closure-deps.js +3 -3
  5. data/test/dummy/log/development.log +159 -0
  6. data/test/dummy/tmp/cache/assets/C1E/0C0/sprockets%2F9c2f7430126aff8d8514326208712832 +165 -0
  7. data/test/dummy/tmp/cache/assets/C29/5D0/sprockets%2F1498f4451d0836a53c7c302c49920996 +0 -0
  8. data/test/dummy/tmp/cache/assets/C7E/9F0/sprockets%2F89862076204c62c4593ac20de32da909 +6 -6
  9. data/test/dummy/tmp/cache/assets/CB4/5B0/sprockets%2Ff17618b71eca9a4621f68626572a75b2 +103 -0
  10. data/test/dummy/tmp/cache/assets/CC2/240/sprockets%2F9f41da672330830c3366594f7ff5e7f6 +590 -0
  11. data/test/dummy/tmp/cache/assets/CC4/2C0/sprockets%2F715db78c7d974ea64406ed9711793f42 +494 -0
  12. data/test/dummy/tmp/cache/assets/CE1/610/sprockets%2F50c01109ecf86153176ccf577595fab4 +53 -0
  13. data/test/dummy/tmp/cache/assets/CE1/C20/sprockets%2F58a7b0499656c97a2204b5821eadab84 +207 -0
  14. data/test/dummy/tmp/cache/assets/CE4/DE0/sprockets%2Fb3aab0604ee02598f339965ec583a746 +204 -0
  15. data/test/dummy/tmp/cache/assets/CE9/B00/sprockets%2F80b139f66661444d6a781bfe56aee076 +0 -0
  16. data/test/dummy/tmp/cache/assets/CEB/840/sprockets%2F38fe57c2a5963f36a49404f672cc707b +0 -0
  17. data/test/dummy/tmp/cache/assets/CEC/6C0/sprockets%2F01b982295748dbd09683557aebd358bd +0 -0
  18. data/test/dummy/tmp/cache/assets/CF0/140/sprockets%2F3974b046fe949e86ef851a0271eb9d50 +1545 -0
  19. data/test/dummy/tmp/cache/assets/D01/DF0/sprockets%2F2ce268622b41a173bb209465a2ced6b9 +806 -0
  20. data/test/dummy/tmp/cache/assets/D05/920/sprockets%2F909507434dcc270db4853e4c147f0aac +4 -5
  21. data/test/dummy/tmp/cache/assets/D0A/C10/sprockets%2Fd050d5ee6a2073aa708a26c589a4c974 +283 -0
  22. data/test/dummy/tmp/cache/assets/D0F/360/sprockets%2Fa18927874a5e02c58c14c5b5df19ec04 +300 -0
  23. data/test/dummy/tmp/cache/assets/D15/700/sprockets%2F2987192f402d2bdc72792b5ae17f9a2f +142 -0
  24. data/test/dummy/tmp/cache/assets/D15/F60/sprockets%2Fa28394e3f80365b5bc86794dd46daa22 +0 -0
  25. data/test/dummy/tmp/cache/assets/D1F/E60/sprockets%2Fe65796b72231e36f5573ce71e2c8bbf8 +511 -0
  26. data/test/dummy/tmp/cache/assets/D22/200/sprockets%2F874bd1079c304ae88fbec8434d6d7794 +187 -0
  27. data/test/dummy/tmp/cache/assets/D3B/6A0/sprockets%2Ff8a978a3672b4f7ba513303b91ad15fc +127 -0
  28. data/test/dummy/tmp/cache/assets/D3C/530/sprockets%2Fe6730ff143273d9a7471b4afc3e1c19d +0 -0
  29. data/test/dummy/tmp/cache/assets/D41/B30/sprockets%2Fba1b93913dd01d83ac9a96df334456f8 +0 -0
  30. data/test/dummy/tmp/cache/assets/D49/570/sprockets%2Fd76be81d59871518ea06d3668f2c4bbb +239 -0
  31. data/test/dummy/tmp/cache/assets/D49/DA0/sprockets%2Fa84f85a305cde80a4d53785d7be0892f +457 -0
  32. data/test/dummy/tmp/cache/assets/D5C/760/sprockets%2F5cd491e0f9106cfd4ec4938896c97de7 +256 -0
  33. data/test/dummy/tmp/cache/assets/D5C/A00/sprockets%2Fefe291b3012745251e2641defbe4cad0 +1529 -0
  34. data/test/dummy/tmp/cache/assets/D68/2B0/sprockets%2Fe51ab0aca893e08c40f9672edef71106 +0 -0
  35. data/test/dummy/tmp/cache/assets/D6E/EA0/sprockets%2Fb52cbc47414c9e60ad4c46824928fbbe +115 -0
  36. data/test/dummy/tmp/cache/assets/D70/0B0/sprockets%2F1ae574bacfb86b4d51281b5e47fe1892 +505 -0
  37. data/test/dummy/tmp/cache/assets/D75/A60/sprockets%2Fab64285176f11f975fb6bb40af8bce76 +0 -0
  38. data/test/dummy/tmp/cache/assets/D76/0A0/sprockets%2F3ad3bd078c47096b34d5bcce886d7b47 +794 -0
  39. data/test/dummy/tmp/cache/assets/D79/C00/sprockets%2F94449fa386c370a1ebd7628eba9afe72 +72 -0
  40. data/test/dummy/tmp/cache/assets/D7B/310/sprockets%2Ff56e44be18b2d65efda80e588e5229a4 +0 -0
  41. data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +7 -8
  42. data/test/dummy/tmp/cache/assets/D95/D20/sprockets%2F05b19351f203fb1eadf8ef1f0e6f9a60 +173 -0
  43. data/test/dummy/tmp/cache/assets/D9F/250/sprockets%2F40dcbb8f852f0e6360c4afb1f39964eb +0 -0
  44. data/test/dummy/tmp/cache/assets/DA8/0E0/sprockets%2F1351359f5bbdb94ef7d247df9af38bd1 +2556 -0
  45. data/test/dummy/tmp/cache/assets/DB3/070/sprockets%2Fd98f91680433cec456e6eb7485dcfdbc +522 -0
  46. data/test/dummy/tmp/cache/assets/DC4/6E0/sprockets%2F72117f09fccb98e6aac4cd1124edae42 +2539 -0
  47. data/test/dummy/tmp/cache/assets/DCC/D50/sprockets%2F9b2b027991c15af6f8afeacdd183c14e +1260 -0
  48. data/test/dummy/tmp/cache/assets/DD9/FF0/sprockets%2Fdf5dcfe86e199b272742a52a4b7e5fbd +823 -0
  49. data/test/dummy/tmp/cache/assets/DE7/0D0/sprockets%2Fe4d9fe29b6d96cdeb070d9b595af83d7 +1354 -0
  50. data/test/dummy/tmp/cache/assets/E00/3A0/sprockets%2Fc1db8cbfbc94bd2736f9f067a4c06cc7 +811 -0
  51. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  52. data/test/dummy/tmp/cache/assets/E0C/C80/sprockets%2F55805edb5f27aaef88eef6632fd08ade +1277 -0
  53. data/test/dummy/tmp/cache/assets/E1B/CF0/sprockets%2Feb58b29b94f29d7da8d9fbe666e4a8dd +474 -0
  54. data/test/dummy/tmp/cache/assets/E1E/E00/sprockets%2Fb005d4fa3dc6cfc1c5098e0fdb3f6b2b +1371 -0
  55. data/test/dummy/tmp/cache/assets/E30/8E0/sprockets%2Fef4fdb83b3eefb027cbc8e19b274ec80 +607 -0
  56. metadata +96 -8
@@ -0,0 +1,72 @@
1
+ o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325729947.547544: @value{ I" length:EFi�I" digest;
2
+ F"%b034dc22bdc028fea740393c33184dbfI" source;
3
+ FI"�// Copyright 2010 The Closure Library Authors. All Rights Reserved.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS-IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ /**
18
+ * @fileoverview Browser capability checks for the dom package.
19
+ *
20
+ */
21
+
22
+
23
+
24
+ goog.provide('goog.dom.BrowserFeature');
25
+
26
+ goog.require('goog.userAgent');
27
+
28
+
29
+ /**
30
+ * Enum of browser capabilities.
31
+ * @enum {boolean}
32
+ */
33
+ goog.dom.BrowserFeature = {
34
+ /**
35
+ * Whether attributes 'name' and 'type' can be added to an element after it's
36
+ * created. False in Internet Explorer prior to version 9.
37
+ */
38
+ CAN_ADD_NAME_OR_TYPE_ATTRIBUTES: !goog.userAgent.IE ||
39
+ goog.userAgent.isDocumentMode(9),
40
+
41
+ /**
42
+ * Whether we can use element.children to access an element's Element
43
+ * children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment
44
+ * nodes in the collection.)
45
+ */
46
+ CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE ||
47
+ goog.userAgent.IE && goog.userAgent.isDocumentMode(9) ||
48
+ goog.userAgent.GECKO && goog.userAgent.isVersion('1.9.1'),
49
+
50
+ /**
51
+ * Opera, Safari 3, and Internet Explorer 9 all support innerText but they
52
+ * include text nodes in script and style tags. Not document-mode-dependent.
53
+ */
54
+ CAN_USE_INNER_TEXT: goog.userAgent.IE && !goog.userAgent.isVersion('9'),
55
+
56
+ /**
57
+ * MSIE, Opera, and Safari>=4 support element.parentElement to access an
58
+ * element's parent if it is an Element.
59
+ */
60
+ CAN_USE_PARENT_ELEMENT_PROPERTY: goog.userAgent.IE || goog.userAgent.OPERA ||
61
+ goog.userAgent.WEBKIT,
62
+
63
+ /**
64
+ * Whether NoScope elements need a scoped element written before them in
65
+ * innerHTML.
66
+ * MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1
67
+ */
68
+ INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE
69
+ };
70
+ ;
71
+ FI"
72
+ F"%494f34f809c11df03639c6522695f3bb
@@ -1,6 +1,6 @@
1
- o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325549267.5179808: @value{ I" length:EFi��I" digest;
2
- F"%ce4572730417eaca9ad9cbf6287e9b79I" source;
3
- FI"��/*!
1
+ o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325729945.666527: @value{ I" length:EFi��I" digest;
2
+ F"%b95339cd0198624d0afeea4ba8c9e630I" source;
3
+ FI"��/*!
4
4
  * jQuery JavaScript Library v1.7.1
5
5
  * http://jquery.com/
6
6
  *
@@ -11165,10 +11165,10 @@ goog.scope = function(fn) {
11165
11165
  };
11166
11166
 
11167
11167
 
11168
- // This file was autogenerated by /Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-b30bab11ab83/vendor/closure-library/closure/bin/build/depswriter.py.
11168
+ // This file was autogenerated by /Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-031d1d0f0e50/vendor/closure-library/closure/bin/build/depswriter.py.
11169
11169
  // Please do not edit.
11170
- goog.addDependency('../../soyutils_usegoog.js', ['soy', 'soy.StringBuilder', 'soy.esc', 'soydata', 'soydata.SanitizedHtml', 'soydata.SanitizedHtmlAttribute', 'soydata.SanitizedJsStrChars', 'soydata.SanitizedUri'], ['goog.asserts', 'goog.dom.DomHelper', 'goog.format', 'goog.i18n.BidiFormatter', 'goog.i18n.bidi', 'goog.soy', 'goog.string', 'goog.string.StringBuffer']);
11171
- goog.addDependency('../../start.js', ['myproject.start'], ['goog.dom', 'myproject.templates']);
11170
+ goog.addDependency('../../my-closure/start.js', ['myproject.start'], ['goog.dom', 'myproject.templates']);
11171
+ goog.addDependency('/soyutils_usegoog.js', ['soy', 'soy.StringBuilder', 'soy.esc', 'soydata', 'soydata.SanitizedHtml', 'soydata.SanitizedHtmlAttribute', 'soydata.SanitizedJsStrChars', 'soydata.SanitizedUri'], ['goog.asserts', 'goog.dom.DomHelper', 'goog.format', 'goog.i18n.BidiFormatter', 'goog.i18n.bidi', 'goog.soy', 'goog.string', 'goog.string.StringBuffer']);
11172
11172
  // This file was automatically generated from simple.js.soy.
11173
11173
  // Please don't edit this file by hand.
11174
11174
 
@@ -11214,7 +11214,6 @@ myproject.start = function() {
11214
11214
 
11215
11215
  // Ensures the symbol will be visible after compiler renaming.
11216
11216
  goog.exportSymbol('myproject.start', myproject.start);
11217
-
11218
11217
  // This is a manifest file that'll be compiled into including all the files listed below.
11219
11218
  // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
11220
11219
  // be included in the compiled file accessible from http://example.com/assets/application.js
@@ -11225,4 +11224,4 @@ goog.exportSymbol('myproject.start', myproject.start);
11225
11224
  ;
11226
11225
  ;
11227
11226
  FI"
11228
- F"%82a93df9a5c8b9d9a50dadd9437c4c88
11227
+ F"%6c02e0110e226e2af7f02b790ff7689e
@@ -0,0 +1,173 @@
1
+ o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325729948.0133371: @value{ I" length:EFiI" digest;
2
+ F"%6c9c6de4d95a1566338ea1406209605aI" source;
3
+ FI"// Copyright 2006 The Closure Library Authors. All Rights Reserved.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS-IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ /**
18
+ * @fileoverview Utility for fast string concatenation.
19
+ */
20
+
21
+
22
+ goog.provide('goog.string.StringBuffer');
23
+
24
+ goog.require('goog.userAgent.jscript');
25
+
26
+
27
+
28
+ /**
29
+ * Utility class to facilitate much faster string concatenation in IE,
30
+ * using Array.join() rather than the '+' operator. For other browsers
31
+ * we simply use the '+' operator.
32
+ *
33
+ * @param {Object|number|string|boolean=} opt_a1 Optional first initial item
34
+ * to append.
35
+ * @param {...Object|number|string|boolean} var_args Other initial items to
36
+ * append, e.g., new goog.string.StringBuffer('foo', 'bar').
37
+ * @constructor
38
+ */
39
+ goog.string.StringBuffer = function(opt_a1, var_args) {
40
+ /**
41
+ * Internal buffer for the string to be concatenated.
42
+ * @type {string|Array}
43
+ * @private
44
+ */
45
+ this.buffer_ = goog.userAgent.jscript.HAS_JSCRIPT ? [] : '';
46
+
47
+ if (opt_a1 != null) {
48
+ this.append.apply(this, arguments);
49
+ }
50
+ };
51
+
52
+
53
+ /**
54
+ * Sets the contents of the string buffer object, replacing what's currently
55
+ * there.
56
+ *
57
+ * @param {string} s String to set.
58
+ */
59
+ goog.string.StringBuffer.prototype.set = function(s) {
60
+ this.clear();
61
+ this.append(s);
62
+ };
63
+
64
+
65
+ if (goog.userAgent.jscript.HAS_JSCRIPT) {
66
+ /**
67
+ * Length of internal buffer (faster than calling buffer_.length).
68
+ * Only used if buffer_ is an array.
69
+ * @type {number}
70
+ * @private
71
+ */
72
+ goog.string.StringBuffer.prototype.bufferLength_ = 0;
73
+
74
+ /**
75
+ * Appends one or more items to the buffer.
76
+ *
77
+ * Calling this with null, undefined, or empty arguments is an error.
78
+ *
79
+ * @param {Object|number|string|boolean} a1 Required first string.
80
+ * @param {Object|number|string|boolean=} opt_a2 Optional second string.
81
+ * @param {...Object|number|string|boolean} var_args Other items to append,
82
+ * e.g., sb.append('foo', 'bar', 'baz').
83
+ * @return {goog.string.StringBuffer} This same StringBuffer object.
84
+ */
85
+ goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
86
+ // IE version.
87
+
88
+ if (opt_a2 == null) { // second argument is undefined (null == undefined)
89
+ // Array assignment is 2x faster than Array push. Also, use a1
90
+ // directly to avoid arguments instantiation, another 2x improvement.
91
+ this.buffer_[this.bufferLength_++] = a1;
92
+ } else {
93
+ this.buffer_.push.apply(/** @type {Array} */ (this.buffer_), arguments);
94
+ this.bufferLength_ = this.buffer_.length;
95
+ }
96
+ return this;
97
+ };
98
+ } else {
99
+
100
+ /**
101
+ * Appends one or more items to the buffer.
102
+ *
103
+ * Calling this with null, undefined, or empty arguments is an error.
104
+ *
105
+ * @param {Object|number|string|boolean} a1 Required first string.
106
+ * @param {Object|number|string|boolean=} opt_a2 Optional second string.
107
+ * @param {...Object|number|string|boolean} var_args Other items to append,
108
+ * e.g., sb.append('foo', 'bar', 'baz').
109
+ * @return {goog.string.StringBuffer} This same StringBuffer object.
110
+ * @suppress {duplicate}
111
+ */
112
+ goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
113
+ // W3 version.
114
+
115
+ // Use a1 directly to avoid arguments instantiation for single-arg case.
116
+ this.buffer_ += a1;
117
+ if (opt_a2 != null) { // second argument is undefined (null == undefined)
118
+ for (var i = 1; i < arguments.length; i++) {
119
+ this.buffer_ += arguments[i];
120
+ }
121
+ }
122
+ return this;
123
+ };
124
+ }
125
+
126
+
127
+ /**
128
+ * Clears the internal buffer.
129
+ */
130
+ goog.string.StringBuffer.prototype.clear = function() {
131
+ if (goog.userAgent.jscript.HAS_JSCRIPT) {
132
+ this.buffer_.length = 0; // Reuse the array to avoid creating new object.
133
+ this.bufferLength_ = 0;
134
+ } else {
135
+ this.buffer_ = '';
136
+ }
137
+ };
138
+
139
+
140
+ /**
141
+ * Returns the length of the current contents of the buffer. In IE, this is
142
+ * O(n) where n = number of appends, so to avoid quadratic behavior, do not call
143
+ * this after every append.
144
+ *
145
+ * @return {number} the length of the current contents of the buffer.
146
+ */
147
+ goog.string.StringBuffer.prototype.getLength = function() {
148
+ return this.toString().length;
149
+ };
150
+
151
+
152
+ /**
153
+ * Returns the concatenated string.
154
+ *
155
+ * @return {string} The concatenated string.
156
+ */
157
+ goog.string.StringBuffer.prototype.toString = function() {
158
+ if (goog.userAgent.jscript.HAS_JSCRIPT) {
159
+ var str = this.buffer_.join('');
160
+ // Given a string with the entire contents, simplify the StringBuffer by
161
+ // setting its contents to only be this string, rather than many fragments.
162
+ this.clear();
163
+ if (str) {
164
+ this.append(str);
165
+ }
166
+ return str;
167
+ } else {
168
+ return /** @type {string} */ (this.buffer_);
169
+ }
170
+ };
171
+ ;
172
+ FI"
173
+ F"%a7c43b42e842c3f7abe6f1be0a410745
@@ -0,0 +1,2556 @@
1
+ o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1325729947.695264: @value{I"
2
+ class:EFI"BundledAsset;
3
+ FI"id;
4
+ F"%f84ee569bf8302371052cb63b4258c11I"logical_path;
5
+ FI"closure/goog/dom/dom.js;
6
+ TI"
7
+ F"�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-031d1d0f0e50/vendor/closure-library/closure/goog/dom/dom.jsI"content_type;
8
+ FI"application/javascript;
9
+ FI"
10
+ mtime;
11
+ FI"2012-01-03T00:52:24+00:00;
12
+ FI" body;
13
+ FI"�C// Copyright 2006 The Closure Library Authors. All Rights Reserved.
14
+ //
15
+ // Licensed under the Apache License, Version 2.0 (the "License");
16
+ // you may not use this file except in compliance with the License.
17
+ // You may obtain a copy of the License at
18
+ //
19
+ // http://www.apache.org/licenses/LICENSE-2.0
20
+ //
21
+ // Unless required by applicable law or agreed to in writing, software
22
+ // distributed under the License is distributed on an "AS-IS" BASIS,
23
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
+ // See the License for the specific language governing permissions and
25
+ // limitations under the License.
26
+
27
+ /**
28
+ * @fileoverview Utilities for manipulating the browser's Document Object Model
29
+ * Inspiration taken *heavily* from mochikit (http://mochikit.com/).
30
+ *
31
+ * You can use {@link goog.dom.DomHelper} to create new dom helpers that refer
32
+ * to a different document object. This is useful if you are working with
33
+ * frames or multiple windows.
34
+ *
35
+ */
36
+
37
+
38
+ // TODO(arv): Rename/refactor getTextContent and getRawTextContent. The problem
39
+ // is that getTextContent should mimic the DOM3 textContent. We should add a
40
+ // getInnerText (or getText) which tries to return the visible text, innerText.
41
+
42
+
43
+ goog.provide('goog.dom');
44
+ goog.provide('goog.dom.DomHelper');
45
+ goog.provide('goog.dom.NodeType');
46
+
47
+ goog.require('goog.array');
48
+ goog.require('goog.dom.BrowserFeature');
49
+ goog.require('goog.dom.TagName');
50
+ goog.require('goog.dom.classes');
51
+ goog.require('goog.math.Coordinate');
52
+ goog.require('goog.math.Size');
53
+ goog.require('goog.object');
54
+ goog.require('goog.string');
55
+ goog.require('goog.userAgent');
56
+
57
+
58
+ /**
59
+ * @define {boolean} Whether we know at compile time that the browser is in
60
+ * quirks mode.
61
+ */
62
+ goog.dom.ASSUME_QUIRKS_MODE = false;
63
+
64
+
65
+ /**
66
+ * @define {boolean} Whether we know at compile time that the browser is in
67
+ * standards compliance mode.
68
+ */
69
+ goog.dom.ASSUME_STANDARDS_MODE = false;
70
+
71
+
72
+ /**
73
+ * Whether we know the compatibility mode at compile time.
74
+ * @type {boolean}
75
+ * @private
76
+ */
77
+ goog.dom.COMPAT_MODE_KNOWN_ =
78
+ goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE;
79
+
80
+
81
+ /**
82
+ * Enumeration for DOM node types (for reference)
83
+ * @enum {number}
84
+ */
85
+ goog.dom.NodeType = {
86
+ ELEMENT: 1,
87
+ ATTRIBUTE: 2,
88
+ TEXT: 3,
89
+ CDATA_SECTION: 4,
90
+ ENTITY_REFERENCE: 5,
91
+ ENTITY: 6,
92
+ PROCESSING_INSTRUCTION: 7,
93
+ COMMENT: 8,
94
+ DOCUMENT: 9,
95
+ DOCUMENT_TYPE: 10,
96
+ DOCUMENT_FRAGMENT: 11,
97
+ NOTATION: 12
98
+ };
99
+
100
+
101
+ /**
102
+ * Gets the DomHelper object for the document where the element resides.
103
+ * @param {Node|Window=} opt_element If present, gets the DomHelper for this
104
+ * element.
105
+ * @return {!goog.dom.DomHelper} The DomHelper.
106
+ */
107
+ goog.dom.getDomHelper = function(opt_element) {
108
+ return opt_element ?
109
+ new goog.dom.DomHelper(goog.dom.getOwnerDocument(opt_element)) :
110
+ (goog.dom.defaultDomHelper_ ||
111
+ (goog.dom.defaultDomHelper_ = new goog.dom.DomHelper()));
112
+ };
113
+
114
+
115
+ /**
116
+ * Cached default DOM helper.
117
+ * @type {goog.dom.DomHelper}
118
+ * @private
119
+ */
120
+ goog.dom.defaultDomHelper_;
121
+
122
+
123
+ /**
124
+ * Gets the document object being used by the dom library.
125
+ * @return {!Document} Document object.
126
+ */
127
+ goog.dom.getDocument = function() {
128
+ return document;
129
+ };
130
+
131
+
132
+ /**
133
+ * Alias for getElementById. If a DOM node is passed in then we just return
134
+ * that.
135
+ * @param {string|Element} element Element ID or a DOM node.
136
+ * @return {Element} The element with the given ID, or the node passed in.
137
+ */
138
+ goog.dom.getElement = function(element) {
139
+ return goog.isString(element) ?
140
+ document.getElementById(element) : element;
141
+ };
142
+
143
+
144
+ /**
145
+ * Alias for getElement.
146
+ * @param {string|Element} element Element ID or a DOM node.
147
+ * @return {Element} The element with the given ID, or the node passed in.
148
+ * @deprecated Use {@link goog.dom.getElement} instead.
149
+ */
150
+ goog.dom.$ = goog.dom.getElement;
151
+
152
+
153
+ /**
154
+ * Looks up elements by both tag and class name, using browser native functions
155
+ * ({@code querySelectorAll}, {@code getElementsByTagName} or
156
+ * {@code getElementsByClassName}) where possible. This function
157
+ * is a useful, if limited, way of collecting a list of DOM elements
158
+ * with certain characteristics. {@code goog.dom.query} offers a
159
+ * more powerful and general solution which allows matching on CSS3
160
+ * selector expressions, but at increased cost in code size. If all you
161
+ * need is particular tags belonging to a single class, this function
162
+ * is fast and sleek.
163
+ *
164
+ * @see {goog.dom.query}
165
+ *
166
+ * @param {?string=} opt_tag Element tag name.
167
+ * @param {?string=} opt_class Optional class name.
168
+ * @param {Document|Element=} opt_el Optional element to look in.
169
+ * @return { {length: number} } Array-like list of elements (only a length
170
+ * property and numerical indices are guaranteed to exist).
171
+ */
172
+ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {
173
+ return goog.dom.getElementsByTagNameAndClass_(document, opt_tag, opt_class,
174
+ opt_el);
175
+ };
176
+
177
+
178
+ /**
179
+ * Returns an array of all the elements with the provided className.
180
+ * @see {goog.dom.query}
181
+ * @param {string} className the name of the class to look for.
182
+ * @param {Document|Element=} opt_el Optional element to look in.
183
+ * @return { {length: number} } The items found with the class name provided.
184
+ */
185
+ goog.dom.getElementsByClass = function(className, opt_el) {
186
+ var parent = opt_el || document;
187
+ if (goog.dom.canUseQuerySelector_(parent)) {
188
+ return parent.querySelectorAll('.' + className);
189
+ } else if (parent.getElementsByClassName) {
190
+ return parent.getElementsByClassName(className);
191
+ }
192
+ return goog.dom.getElementsByTagNameAndClass_(
193
+ document, '*', className, opt_el);
194
+ };
195
+
196
+
197
+ /**
198
+ * Returns the first element with the provided className.
199
+ * @see {goog.dom.query}
200
+ * @param {string} className the name of the class to look for.
201
+ * @param {Element|Document=} opt_el Optional element to look in.
202
+ * @return {Element} The first item with the class name provided.
203
+ */
204
+ goog.dom.getElementByClass = function(className, opt_el) {
205
+ var parent = opt_el || document;
206
+ var retVal = null;
207
+ if (goog.dom.canUseQuerySelector_(parent)) {
208
+ retVal = parent.querySelector('.' + className);
209
+ } else {
210
+ retVal = goog.dom.getElementsByClass(className, opt_el)[0];
211
+ }
212
+ return retVal || null;
213
+ };
214
+
215
+
216
+ /**
217
+ * Prefer the standardized (http://www.w3.org/TR/selectors-api/), native and
218
+ * fast W3C Selectors API. However, the version of WebKit that shipped with
219
+ * Safari 3.1 and Chrome has a bug where it will not correctly match mixed-
220
+ * case class name selectors in quirks mode.
221
+ * @param {!Element|Document} parent The parent document object.
222
+ * @return {boolean} whether or not we can use parent.querySelector* APIs.
223
+ * @private
224
+ */
225
+ goog.dom.canUseQuerySelector_ = function(parent) {
226
+ return parent.querySelectorAll &&
227
+ parent.querySelector &&
228
+ (!goog.userAgent.WEBKIT || goog.dom.isCss1CompatMode_(document) ||
229
+ goog.userAgent.isVersion('528'));
230
+ };
231
+
232
+
233
+ /**
234
+ * Helper for {@code getElementsByTagNameAndClass}.
235
+ * @param {!Document} doc The document to get the elements in.
236
+ * @param {?string=} opt_tag Element tag name.
237
+ * @param {?string=} opt_class Optional class name.
238
+ * @param {Document|Element=} opt_el Optional element to look in.
239
+ * @return { {length: number} } Array-like list of elements (only a length
240
+ * property and numerical indices are guaranteed to exist).
241
+ * @private
242
+ */
243
+ goog.dom.getElementsByTagNameAndClass_ = function(doc, opt_tag, opt_class,
244
+ opt_el) {
245
+ var parent = opt_el || doc;
246
+ var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : '';
247
+
248
+ if (goog.dom.canUseQuerySelector_(parent) &&
249
+ (tagName || opt_class)) {
250
+ var query = tagName + (opt_class ? '.' + opt_class : '');
251
+ return parent.querySelectorAll(query);
252
+ }
253
+
254
+ // Use the native getElementsByClassName if available, under the assumption
255
+ // that even when the tag name is specified, there will be fewer elements to
256
+ // filter through when going by class than by tag name
257
+ if (opt_class && parent.getElementsByClassName) {
258
+ var els = parent.getElementsByClassName(opt_class);
259
+
260
+ if (tagName) {
261
+ var arrayLike = {};
262
+ var len = 0;
263
+
264
+ // Filter for specific tags if requested.
265
+ for (var i = 0, el; el = els[i]; i++) {
266
+ if (tagName == el.nodeName) {
267
+ arrayLike[len++] = el;
268
+ }
269
+ }
270
+ arrayLike.length = len;
271
+
272
+ return arrayLike;
273
+ } else {
274
+ return els;
275
+ }
276
+ }
277
+
278
+ var els = parent.getElementsByTagName(tagName || '*');
279
+
280
+ if (opt_class) {
281
+ var arrayLike = {};
282
+ var len = 0;
283
+ for (var i = 0, el; el = els[i]; i++) {
284
+ var className = el.className;
285
+ // Check if className has a split function since SVG className does not.
286
+ if (typeof className.split == 'function' &&
287
+ goog.array.contains(className.split(/\s+/), opt_class)) {
288
+ arrayLike[len++] = el;
289
+ }
290
+ }
291
+ arrayLike.length = len;
292
+ return arrayLike;
293
+ } else {
294
+ return els;
295
+ }
296
+ };
297
+
298
+
299
+ /**
300
+ * Alias for {@code getElementsByTagNameAndClass}.
301
+ * @param {?string=} opt_tag Element tag name.
302
+ * @param {?string=} opt_class Optional class name.
303
+ * @param {Element=} opt_el Optional element to look in.
304
+ * @return { {length: number} } Array-like list of elements (only a length
305
+ * property and numerical indices are guaranteed to exist).
306
+ * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead.
307
+ */
308
+ goog.dom.$$ = goog.dom.getElementsByTagNameAndClass;
309
+
310
+
311
+ /**
312
+ * Sets multiple properties on a node.
313
+ * @param {Element} element DOM node to set properties on.
314
+ * @param {Object} properties Hash of property:value pairs.
315
+ */
316
+ goog.dom.setProperties = function(element, properties) {
317
+ goog.object.forEach(properties, function(val, key) {
318
+ if (key == 'style') {
319
+ element.style.cssText = val;
320
+ } else if (key == 'class') {
321
+ element.className = val;
322
+ } else if (key == 'for') {
323
+ element.htmlFor = val;
324
+ } else if (key in goog.dom.DIRECT_ATTRIBUTE_MAP_) {
325
+ element.setAttribute(goog.dom.DIRECT_ATTRIBUTE_MAP_[key], val);
326
+ } else if (goog.string.startsWith(key, 'aria-')) {
327
+ element.setAttribute(key, val);
328
+ } else {
329
+ element[key] = val;
330
+ }
331
+ });
332
+ };
333
+
334
+
335
+ /**
336
+ * Map of attributes that should be set using
337
+ * element.setAttribute(key, val) instead of element[key] = val. Used
338
+ * by goog.dom.setProperties.
339
+ *
340
+ * @type {Object}
341
+ * @private
342
+ */
343
+ goog.dom.DIRECT_ATTRIBUTE_MAP_ = {
344
+ 'cellpadding': 'cellPadding',
345
+ 'cellspacing': 'cellSpacing',
346
+ 'colspan': 'colSpan',
347
+ 'rowspan': 'rowSpan',
348
+ 'valign': 'vAlign',
349
+ 'height': 'height',
350
+ 'width': 'width',
351
+ 'usemap': 'useMap',
352
+ 'frameborder': 'frameBorder',
353
+ 'maxlength': 'maxLength',
354
+ 'type': 'type'
355
+ };
356
+
357
+
358
+ /**
359
+ * Gets the dimensions of the viewport.
360
+ *
361
+ * Gecko Standards mode:
362
+ * docEl.clientWidth Width of viewport excluding scrollbar.
363
+ * win.innerWidth Width of viewport including scrollbar.
364
+ * body.clientWidth Width of body element.
365
+ *
366
+ * docEl.clientHeight Height of viewport excluding scrollbar.
367
+ * win.innerHeight Height of viewport including scrollbar.
368
+ * body.clientHeight Height of document.
369
+ *
370
+ * Gecko Backwards compatible mode:
371
+ * docEl.clientWidth Width of viewport excluding scrollbar.
372
+ * win.innerWidth Width of viewport including scrollbar.
373
+ * body.clientWidth Width of viewport excluding scrollbar.
374
+ *
375
+ * docEl.clientHeight Height of document.
376
+ * win.innerHeight Height of viewport including scrollbar.
377
+ * body.clientHeight Height of viewport excluding scrollbar.
378
+ *
379
+ * IE6/7 Standards mode:
380
+ * docEl.clientWidth Width of viewport excluding scrollbar.
381
+ * win.innerWidth Undefined.
382
+ * body.clientWidth Width of body element.
383
+ *
384
+ * docEl.clientHeight Height of viewport excluding scrollbar.
385
+ * win.innerHeight Undefined.
386
+ * body.clientHeight Height of document element.
387
+ *
388
+ * IE5 + IE6/7 Backwards compatible mode:
389
+ * docEl.clientWidth 0.
390
+ * win.innerWidth Undefined.
391
+ * body.clientWidth Width of viewport excluding scrollbar.
392
+ *
393
+ * docEl.clientHeight 0.
394
+ * win.innerHeight Undefined.
395
+ * body.clientHeight Height of viewport excluding scrollbar.
396
+ *
397
+ * Opera 9 Standards and backwards compatible mode:
398
+ * docEl.clientWidth Width of viewport excluding scrollbar.
399
+ * win.innerWidth Width of viewport including scrollbar.
400
+ * body.clientWidth Width of viewport excluding scrollbar.
401
+ *
402
+ * docEl.clientHeight Height of document.
403
+ * win.innerHeight Height of viewport including scrollbar.
404
+ * body.clientHeight Height of viewport excluding scrollbar.
405
+ *
406
+ * WebKit:
407
+ * Safari 2
408
+ * docEl.clientHeight Same as scrollHeight.
409
+ * docEl.clientWidth Same as innerWidth.
410
+ * win.innerWidth Width of viewport excluding scrollbar.
411
+ * win.innerHeight Height of the viewport including scrollbar.
412
+ * frame.innerHeight Height of the viewport exluding scrollbar.
413
+ *
414
+ * Safari 3 (tested in 522)
415
+ *
416
+ * docEl.clientWidth Width of viewport excluding scrollbar.
417
+ * docEl.clientHeight Height of viewport excluding scrollbar in strict mode.
418
+ * body.clientHeight Height of viewport excluding scrollbar in quirks mode.
419
+ *
420
+ * @param {Window=} opt_window Optional window element to test.
421
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
422
+ */
423
+ goog.dom.getViewportSize = function(opt_window) {
424
+ // TODO(arv): This should not take an argument
425
+ return goog.dom.getViewportSize_(opt_window || window);
426
+ };
427
+
428
+
429
+ /**
430
+ * Helper for {@code getViewportSize}.
431
+ * @param {Window} win The window to get the view port size for.
432
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
433
+ * @private
434
+ */
435
+ goog.dom.getViewportSize_ = function(win) {
436
+ var doc = win.document;
437
+
438
+ if (goog.userAgent.WEBKIT && !goog.userAgent.isVersion('500') &&
439
+ !goog.userAgent.MOBILE) {
440
+ // TODO(user): Sometimes we get something that isn't a valid window
441
+ // object. In this case we just revert to the current window. We need to
442
+ // figure out when this happens and find a real fix for it.
443
+ // See the comments on goog.dom.getWindow.
444
+ if (typeof win.innerHeight == 'undefined') {
445
+ win = window;
446
+ }
447
+ var innerHeight = win.innerHeight;
448
+ var scrollHeight = win.document.documentElement.scrollHeight;
449
+
450
+ if (win == win.top) {
451
+ if (scrollHeight < innerHeight) {
452
+ innerHeight -= 15; // Scrollbars are 15px wide on Mac
453
+ }
454
+ }
455
+ return new goog.math.Size(win.innerWidth, innerHeight);
456
+ }
457
+
458
+ var el = goog.dom.isCss1CompatMode_(doc) ? doc.documentElement : doc.body;
459
+
460
+ return new goog.math.Size(el.clientWidth, el.clientHeight);
461
+ };
462
+
463
+
464
+ /**
465
+ * Calculates the height of the document.
466
+ *
467
+ * @return {number} The height of the current document.
468
+ */
469
+ goog.dom.getDocumentHeight = function() {
470
+ return goog.dom.getDocumentHeight_(window);
471
+ };
472
+
473
+
474
+ /**
475
+ * Calculates the height of the document of the given window.
476
+ *
477
+ * Function code copied from the opensocial gadget api:
478
+ * gadgets.window.adjustHeight(opt_height)
479
+ *
480
+ * @private
481
+ * @param {Window} win The window whose document height to retrieve.
482
+ * @return {number} The height of the document of the given window.
483
+ */
484
+ goog.dom.getDocumentHeight_ = function(win) {
485
+ // NOTE(eae): This method will return the window size rather than the document
486
+ // size in webkit quirks mode.
487
+ var doc = win.document;
488
+ var height = 0;
489
+
490
+ if (doc) {
491
+ // Calculating inner content height is hard and different between
492
+ // browsers rendering in Strict vs. Quirks mode. We use a combination of
493
+ // three properties within document.body and document.documentElement:
494
+ // - scrollHeight
495
+ // - offsetHeight
496
+ // - clientHeight
497
+ // These values differ significantly between browsers and rendering modes.
498
+ // But there are patterns. It just takes a lot of time and persistence
499
+ // to figure out.
500
+
501
+ // Get the height of the viewport
502
+ var vh = goog.dom.getViewportSize_(win).height;
503
+ var body = doc.body;
504
+ var docEl = doc.documentElement;
505
+ if (goog.dom.isCss1CompatMode_(doc) && docEl.scrollHeight) {
506
+ // In Strict mode:
507
+ // The inner content height is contained in either:
508
+ // document.documentElement.scrollHeight
509
+ // document.documentElement.offsetHeight
510
+ // Based on studying the values output by different browsers,
511
+ // use the value that's NOT equal to the viewport height found above.
512
+ height = docEl.scrollHeight != vh ?
513
+ docEl.scrollHeight : docEl.offsetHeight;
514
+ } else {
515
+ // In Quirks mode:
516
+ // documentElement.clientHeight is equal to documentElement.offsetHeight
517
+ // except in IE. In most browsers, document.documentElement can be used
518
+ // to calculate the inner content height.
519
+ // However, in other browsers (e.g. IE), document.body must be used
520
+ // instead. How do we know which one to use?
521
+ // If document.documentElement.clientHeight does NOT equal
522
+ // document.documentElement.offsetHeight, then use document.body.
523
+ var sh = docEl.scrollHeight;
524
+ var oh = docEl.offsetHeight;
525
+ if (docEl.clientHeight != oh) {
526
+ sh = body.scrollHeight;
527
+ oh = body.offsetHeight;
528
+ }
529
+
530
+ // Detect whether the inner content height is bigger or smaller
531
+ // than the bounding box (viewport). If bigger, take the larger
532
+ // value. If smaller, take the smaller value.
533
+ if (sh > vh) {
534
+ // Content is larger
535
+ height = sh > oh ? sh : oh;
536
+ } else {
537
+ // Content is smaller
538
+ height = sh < oh ? sh : oh;
539
+ }
540
+ }
541
+ }
542
+
543
+ return height;
544
+ };
545
+
546
+
547
+ /**
548
+ * Gets the page scroll distance as a coordinate object.
549
+ *
550
+ * @param {Window=} opt_window Optional window element to test.
551
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
552
+ * @deprecated Use {@link goog.dom.getDocumentScroll} instead.
553
+ */
554
+ goog.dom.getPageScroll = function(opt_window) {
555
+ var win = opt_window || goog.global || window;
556
+ return goog.dom.getDomHelper(win.document).getDocumentScroll();
557
+ };
558
+
559
+
560
+ /**
561
+ * Gets the document scroll distance as a coordinate object.
562
+ *
563
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
564
+ */
565
+ goog.dom.getDocumentScroll = function() {
566
+ return goog.dom.getDocumentScroll_(document);
567
+ };
568
+
569
+
570
+ /**
571
+ * Helper for {@code getDocumentScroll}.
572
+ *
573
+ * @param {!Document} doc The document to get the scroll for.
574
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
575
+ * @private
576
+ */
577
+ goog.dom.getDocumentScroll_ = function(doc) {
578
+ var el = goog.dom.getDocumentScrollElement_(doc);
579
+ var win = goog.dom.getWindow_(doc);
580
+ return new goog.math.Coordinate(win.pageXOffset || el.scrollLeft,
581
+ win.pageYOffset || el.scrollTop);
582
+ };
583
+
584
+
585
+ /**
586
+ * Gets the document scroll element.
587
+ * @return {Element} Scrolling element.
588
+ */
589
+ goog.dom.getDocumentScrollElement = function() {
590
+ return goog.dom.getDocumentScrollElement_(document);
591
+ };
592
+
593
+
594
+ /**
595
+ * Helper for {@code getDocumentScrollElement}.
596
+ * @param {!Document} doc The document to get the scroll element for.
597
+ * @return {Element} Scrolling element.
598
+ * @private
599
+ */
600
+ goog.dom.getDocumentScrollElement_ = function(doc) {
601
+ // Safari (2 and 3) needs body.scrollLeft in both quirks mode and strict mode.
602
+ return !goog.userAgent.WEBKIT && goog.dom.isCss1CompatMode_(doc) ?
603
+ doc.documentElement : doc.body;
604
+ };
605
+
606
+
607
+ /**
608
+ * Gets the window object associated with the given document.
609
+ *
610
+ * @param {Document=} opt_doc Document object to get window for.
611
+ * @return {!Window} The window associated with the given document.
612
+ */
613
+ goog.dom.getWindow = function(opt_doc) {
614
+ // TODO(arv): This should not take an argument.
615
+ return opt_doc ? goog.dom.getWindow_(opt_doc) : window;
616
+ };
617
+
618
+
619
+ /**
620
+ * Helper for {@code getWindow}.
621
+ *
622
+ * @param {!Document} doc Document object to get window for.
623
+ * @return {!Window} The window associated with the given document.
624
+ * @private
625
+ */
626
+ goog.dom.getWindow_ = function(doc) {
627
+ return doc.parentWindow || doc.defaultView;
628
+ };
629
+
630
+
631
+ /**
632
+ * Returns a dom node with a set of attributes. This function accepts varargs
633
+ * for subsequent nodes to be added. Subsequent nodes will be added to the
634
+ * first node as childNodes.
635
+ *
636
+ * So:
637
+ * <code>createDom('div', null, createDom('p'), createDom('p'));</code>
638
+ * would return a div with two child paragraphs
639
+ *
640
+ * @param {string} tagName Tag to create.
641
+ * @param {Object|Array.<string>|string=} opt_attributes If object, then a map
642
+ * of name-value pairs for attributes. If a string, then this is the
643
+ * className of the new element. If an array, the elements will be joined
644
+ * together as the className of the new element.
645
+ * @param {...Object|string|Array|NodeList} var_args Further DOM nodes or
646
+ * strings for text nodes. If one of the var_args is an array or NodeList,i
647
+ * its elements will be added as childNodes instead.
648
+ * @return {!Element} Reference to a DOM node.
649
+ */
650
+ goog.dom.createDom = function(tagName, opt_attributes, var_args) {
651
+ return goog.dom.createDom_(document, arguments);
652
+ };
653
+
654
+
655
+ /**
656
+ * Helper for {@code createDom}.
657
+ * @param {!Document} doc The document to create the DOM in.
658
+ * @param {!Arguments} args Argument object passed from the callers. See
659
+ * {@code goog.dom.createDom} for details.
660
+ * @return {!Element} Reference to a DOM node.
661
+ * @private
662
+ */
663
+ goog.dom.createDom_ = function(doc, args) {
664
+ var tagName = args[0];
665
+ var attributes = args[1];
666
+
667
+ // Internet Explorer is dumb: http://msdn.microsoft.com/workshop/author/
668
+ // dhtml/reference/properties/name_2.asp
669
+ // Also does not allow setting of 'type' attribute on 'input' or 'button'.
670
+ if (!goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES && attributes &&
671
+ (attributes.name || attributes.type)) {
672
+ var tagNameArr = ['<', tagName];
673
+ if (attributes.name) {
674
+ tagNameArr.push(' name="', goog.string.htmlEscape(attributes.name),
675
+ '"');
676
+ }
677
+ if (attributes.type) {
678
+ tagNameArr.push(' type="', goog.string.htmlEscape(attributes.type),
679
+ '"');
680
+
681
+ // Clone attributes map to remove 'type' without mutating the input.
682
+ var clone = {};
683
+ goog.object.extend(clone, attributes);
684
+ attributes = clone;
685
+ delete attributes.type;
686
+ }
687
+ tagNameArr.push('>');
688
+ tagName = tagNameArr.join('');
689
+ }
690
+
691
+ var element = doc.createElement(tagName);
692
+
693
+ if (attributes) {
694
+ if (goog.isString(attributes)) {
695
+ element.className = attributes;
696
+ } else if (goog.isArray(attributes)) {
697
+ goog.dom.classes.add.apply(null, [element].concat(attributes));
698
+ } else {
699
+ goog.dom.setProperties(element, attributes);
700
+ }
701
+ }
702
+
703
+ if (args.length > 2) {
704
+ goog.dom.append_(doc, element, args, 2);
705
+ }
706
+
707
+ return element;
708
+ };
709
+
710
+
711
+ /**
712
+ * Appends a node with text or other nodes.
713
+ * @param {!Document} doc The document to create new nodes in.
714
+ * @param {!Node} parent The node to append nodes to.
715
+ * @param {!Arguments} args The values to add. See {@code goog.dom.append}.
716
+ * @param {number} startIndex The index of the array to start from.
717
+ * @private
718
+ */
719
+ goog.dom.append_ = function(doc, parent, args, startIndex) {
720
+ function childHandler(child) {
721
+ // TODO(user): More coercion, ala MochiKit?
722
+ if (child) {
723
+ parent.appendChild(goog.isString(child) ?
724
+ doc.createTextNode(child) : child);
725
+ }
726
+ }
727
+
728
+ for (var i = startIndex; i < args.length; i++) {
729
+ var arg = args[i];
730
+ // TODO(attila): Fix isArrayLike to return false for a text node.
731
+ if (goog.isArrayLike(arg) && !goog.dom.isNodeLike(arg)) {
732
+ // If the argument is a node list, not a real array, use a clone,
733
+ // because forEach can't be used to mutate a NodeList.
734
+ goog.array.forEach(goog.dom.isNodeList(arg) ?
735
+ goog.array.clone(arg) : arg,
736
+ childHandler);
737
+ } else {
738
+ childHandler(arg);
739
+ }
740
+ }
741
+ };
742
+
743
+
744
+ /**
745
+ * Alias for {@code createDom}.
746
+ * @param {string} tagName Tag to create.
747
+ * @param {string|Object=} opt_attributes If object, then a map of name-value
748
+ * pairs for attributes. If a string, then this is the className of the new
749
+ * element.
750
+ * @param {...Object|string|Array|NodeList} var_args Further DOM nodes or
751
+ * strings for text nodes. If one of the var_args is an array, its
752
+ * children will be added as childNodes instead.
753
+ * @return {!Element} Reference to a DOM node.
754
+ * @deprecated Use {@link goog.dom.createDom} instead.
755
+ */
756
+ goog.dom.$dom = goog.dom.createDom;
757
+
758
+
759
+ /**
760
+ * Creates a new element.
761
+ * @param {string} name Tag name.
762
+ * @return {!Element} The new element.
763
+ */
764
+ goog.dom.createElement = function(name) {
765
+ return document.createElement(name);
766
+ };
767
+
768
+
769
+ /**
770
+ * Creates a new text node.
771
+ * @param {string} content Content.
772
+ * @return {!Text} The new text node.
773
+ */
774
+ goog.dom.createTextNode = function(content) {
775
+ return document.createTextNode(content);
776
+ };
777
+
778
+
779
+ /**
780
+ * Create a table.
781
+ * @param {number} rows The number of rows in the table. Must be >= 1.
782
+ * @param {number} columns The number of columns in the table. Must be >= 1.
783
+ * @param {boolean=} opt_fillWithNbsp If true, fills table entries with nsbps.
784
+ * @return {!Element} The created table.
785
+ */
786
+ goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) {
787
+ return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp);
788
+ };
789
+
790
+
791
+ /**
792
+ * Create a table.
793
+ * @param {!Document} doc Document object to use to create the table.
794
+ * @param {number} rows The number of rows in the table. Must be >= 1.
795
+ * @param {number} columns The number of columns in the table. Must be >= 1.
796
+ * @param {boolean} fillWithNbsp If true, fills table entries with nsbps.
797
+ * @return {!Element} The created table.
798
+ * @private
799
+ */
800
+ goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) {
801
+ var rowHtml = ['<tr>'];
802
+ for (var i = 0; i < columns; i++) {
803
+ rowHtml.push(fillWithNbsp ? '<td>&nbsp;</td>' : '<td></td>');
804
+ }
805
+ rowHtml.push('</tr>');
806
+ rowHtml = rowHtml.join('');
807
+ var totalHtml = ['<table>'];
808
+ for (i = 0; i < rows; i++) {
809
+ totalHtml.push(rowHtml);
810
+ }
811
+ totalHtml.push('</table>');
812
+
813
+ var elem = doc.createElement(goog.dom.TagName.DIV);
814
+ elem.innerHTML = totalHtml.join('');
815
+ return /** @type {!Element} */ (elem.removeChild(elem.firstChild));
816
+ };
817
+
818
+
819
+ /**
820
+ * Converts an HTML string into a document fragment.
821
+ *
822
+ * @param {string} htmlString The HTML string to convert.
823
+ * @return {!Node} The resulting document fragment.
824
+ */
825
+ goog.dom.htmlToDocumentFragment = function(htmlString) {
826
+ return goog.dom.htmlToDocumentFragment_(document, htmlString);
827
+ };
828
+
829
+
830
+ /**
831
+ * Helper for {@code htmlToDocumentFragment}.
832
+ *
833
+ * @param {!Document} doc The document.
834
+ * @param {string} htmlString The HTML string to convert.
835
+ * @return {!Node} The resulting document fragment.
836
+ * @private
837
+ */
838
+ goog.dom.htmlToDocumentFragment_ = function(doc, htmlString) {
839
+ var tempDiv = doc.createElement('div');
840
+ if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) {
841
+ tempDiv.innerHTML = '<br>' + htmlString;
842
+ tempDiv.removeChild(tempDiv.firstChild);
843
+ } else {
844
+ tempDiv.innerHTML = htmlString;
845
+ }
846
+ if (tempDiv.childNodes.length == 1) {
847
+ return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild));
848
+ } else {
849
+ var fragment = doc.createDocumentFragment();
850
+ while (tempDiv.firstChild) {
851
+ fragment.appendChild(tempDiv.firstChild);
852
+ }
853
+ return fragment;
854
+ }
855
+ };
856
+
857
+
858
+ /**
859
+ * Returns the compatMode of the document.
860
+ * @return {string} The result is either CSS1Compat or BackCompat.
861
+ * @deprecated use goog.dom.isCss1CompatMode instead.
862
+ */
863
+ goog.dom.getCompatMode = function() {
864
+ return goog.dom.isCss1CompatMode() ? 'CSS1Compat' : 'BackCompat';
865
+ };
866
+
867
+
868
+ /**
869
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
870
+ * mode, false otherwise.
871
+ * @return {boolean} True if in CSS1-compatible mode.
872
+ */
873
+ goog.dom.isCss1CompatMode = function() {
874
+ return goog.dom.isCss1CompatMode_(document);
875
+ };
876
+
877
+
878
+ /**
879
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
880
+ * mode, false otherwise.
881
+ * @param {Document} doc The document to check.
882
+ * @return {boolean} True if in CSS1-compatible mode.
883
+ * @private
884
+ */
885
+ goog.dom.isCss1CompatMode_ = function(doc) {
886
+ if (goog.dom.COMPAT_MODE_KNOWN_) {
887
+ return goog.dom.ASSUME_STANDARDS_MODE;
888
+ }
889
+
890
+ return doc.compatMode == 'CSS1Compat';
891
+ };
892
+
893
+
894
+ /**
895
+ * Determines if the given node can contain children, intended to be used for
896
+ * HTML generation.
897
+ *
898
+ * IE natively supports node.canHaveChildren but has inconsistent behavior.
899
+ * Prior to IE8 the base tag allows children and in IE9 all nodes return true
900
+ * for canHaveChildren.
901
+ *
902
+ * In practice all non-IE browsers allow you to add children to any node, but
903
+ * the behavior is inconsistent:
904
+ *
905
+ * <pre>
906
+ * var a = document.createElement('br');
907
+ * a.appendChild(document.createTextNode('foo'));
908
+ * a.appendChild(document.createTextNode('bar'));
909
+ * console.log(a.childNodes.length); // 2
910
+ * console.log(a.innerHTML); // Chrome: "", IE9: "foobar", FF3.5: "foobar"
911
+ * </pre>
912
+ *
913
+ * TODO(user): Rename shouldAllowChildren() ?
914
+ *
915
+ * @param {Node} node The node to check.
916
+ * @return {boolean} Whether the node can contain children.
917
+ */
918
+ goog.dom.canHaveChildren = function(node) {
919
+ if (node.nodeType != goog.dom.NodeType.ELEMENT) {
920
+ return false;
921
+ }
922
+ switch (node.tagName) {
923
+ case goog.dom.TagName.APPLET:
924
+ case goog.dom.TagName.AREA:
925
+ case goog.dom.TagName.BASE:
926
+ case goog.dom.TagName.BR:
927
+ case goog.dom.TagName.COL:
928
+ case goog.dom.TagName.FRAME:
929
+ case goog.dom.TagName.HR:
930
+ case goog.dom.TagName.IMG:
931
+ case goog.dom.TagName.INPUT:
932
+ case goog.dom.TagName.IFRAME:
933
+ case goog.dom.TagName.ISINDEX:
934
+ case goog.dom.TagName.LINK:
935
+ case goog.dom.TagName.NOFRAMES:
936
+ case goog.dom.TagName.NOSCRIPT:
937
+ case goog.dom.TagName.META:
938
+ case goog.dom.TagName.OBJECT:
939
+ case goog.dom.TagName.PARAM:
940
+ case goog.dom.TagName.SCRIPT:
941
+ case goog.dom.TagName.STYLE:
942
+ return false;
943
+ }
944
+ return true;
945
+ };
946
+
947
+
948
+ /**
949
+ * Appends a child to a node.
950
+ * @param {Node} parent Parent.
951
+ * @param {Node} child Child.
952
+ */
953
+ goog.dom.appendChild = function(parent, child) {
954
+ parent.appendChild(child);
955
+ };
956
+
957
+
958
+ /**
959
+ * Appends a node with text or other nodes.
960
+ * @param {!Node} parent The node to append nodes to.
961
+ * @param {...goog.dom.Appendable} var_args The things to append to the node.
962
+ * If this is a Node it is appended as is.
963
+ * If this is a string then a text node is appended.
964
+ * If this is an array like object then fields 0 to length - 1 are appended.
965
+ */
966
+ goog.dom.append = function(parent, var_args) {
967
+ goog.dom.append_(goog.dom.getOwnerDocument(parent), parent, arguments, 1);
968
+ };
969
+
970
+
971
+ /**
972
+ * Removes all the child nodes on a DOM node.
973
+ * @param {Node} node Node to remove children from.
974
+ */
975
+ goog.dom.removeChildren = function(node) {
976
+ // Note: Iterations over live collections can be slow, this is the fastest
977
+ // we could find. The double parenthesis are used to prevent JsCompiler and
978
+ // strict warnings.
979
+ var child;
980
+ while ((child = node.firstChild)) {
981
+ node.removeChild(child);
982
+ }
983
+ };
984
+
985
+
986
+ /**
987
+ * Inserts a new node before an existing reference node (i.e. as the previous
988
+ * sibling). If the reference node has no parent, then does nothing.
989
+ * @param {Node} newNode Node to insert.
990
+ * @param {Node} refNode Reference node to insert before.
991
+ */
992
+ goog.dom.insertSiblingBefore = function(newNode, refNode) {
993
+ if (refNode.parentNode) {
994
+ refNode.parentNode.insertBefore(newNode, refNode);
995
+ }
996
+ };
997
+
998
+
999
+ /**
1000
+ * Inserts a new node after an existing reference node (i.e. as the next
1001
+ * sibling). If the reference node has no parent, then does nothing.
1002
+ * @param {Node} newNode Node to insert.
1003
+ * @param {Node} refNode Reference node to insert after.
1004
+ */
1005
+ goog.dom.insertSiblingAfter = function(newNode, refNode) {
1006
+ if (refNode.parentNode) {
1007
+ refNode.parentNode.insertBefore(newNode, refNode.nextSibling);
1008
+ }
1009
+ };
1010
+
1011
+
1012
+ /**
1013
+ * Insert a child at a given index. If index is larger than the number of child
1014
+ * nodes that the parent currently has, the node is inserted as the last child
1015
+ * node.
1016
+ * @param {Element} parent The element into which to insert the child.
1017
+ * @param {Node} child The element to insert.
1018
+ * @param {number} index The index at which to insert the new child node. Must
1019
+ * not be negative.
1020
+ */
1021
+ goog.dom.insertChildAt = function(parent, child, index) {
1022
+ // Note that if the second argument is null, insertBefore
1023
+ // will append the child at the end of the list of children.
1024
+ parent.insertBefore(child, parent.childNodes[index] || null);
1025
+ };
1026
+
1027
+
1028
+ /**
1029
+ * Removes a node from its parent.
1030
+ * @param {Node} node The node to remove.
1031
+ * @return {Node} The node removed if removed; else, null.
1032
+ */
1033
+ goog.dom.removeNode = function(node) {
1034
+ return node && node.parentNode ? node.parentNode.removeChild(node) : null;
1035
+ };
1036
+
1037
+
1038
+ /**
1039
+ * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no
1040
+ * parent.
1041
+ * @param {Node} newNode Node to insert.
1042
+ * @param {Node} oldNode Node to replace.
1043
+ */
1044
+ goog.dom.replaceNode = function(newNode, oldNode) {
1045
+ var parent = oldNode.parentNode;
1046
+ if (parent) {
1047
+ parent.replaceChild(newNode, oldNode);
1048
+ }
1049
+ };
1050
+
1051
+
1052
+ /**
1053
+ * Flattens an element. That is, removes it and replace it with its children.
1054
+ * Does nothing if the element is not in the document.
1055
+ * @param {Element} element The element to flatten.
1056
+ * @return {Element|undefined} The original element, detached from the document
1057
+ * tree, sans children; or undefined, if the element was not in the
1058
+ * document to begin with.
1059
+ */
1060
+ goog.dom.flattenElement = function(element) {
1061
+ var child, parent = element.parentNode;
1062
+ if (parent && parent.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT) {
1063
+ // Use IE DOM method (supported by Opera too) if available
1064
+ if (element.removeNode) {
1065
+ return /** @type {Element} */ (element.removeNode(false));
1066
+ } else {
1067
+ // Move all children of the original node up one level.
1068
+ while ((child = element.firstChild)) {
1069
+ parent.insertBefore(child, element);
1070
+ }
1071
+
1072
+ // Detach the original element.
1073
+ return /** @type {Element} */ (goog.dom.removeNode(element));
1074
+ }
1075
+ }
1076
+ };
1077
+
1078
+
1079
+ /**
1080
+ * Returns an array containing just the element children of the given element.
1081
+ * @param {Element} element The element whose element children we want.
1082
+ * @return {Array|NodeList} An array or array-like list of just the element
1083
+ * children of the given element.
1084
+ */
1085
+ goog.dom.getChildren = function(element) {
1086
+ // We check if the children attribute is supported for child elements
1087
+ // since IE8 misuses the attribute by also including comments.
1088
+ if (goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE &&
1089
+ element.children != undefined) {
1090
+ return element.children;
1091
+ }
1092
+ // Fall back to manually filtering the element's child nodes.
1093
+ return goog.array.filter(element.childNodes, function(node) {
1094
+ return node.nodeType == goog.dom.NodeType.ELEMENT;
1095
+ });
1096
+ };
1097
+
1098
+
1099
+ /**
1100
+ * Returns the first child node that is an element.
1101
+ * @param {Node} node The node to get the first child element of.
1102
+ * @return {Element} The first child node of {@code node} that is an element.
1103
+ */
1104
+ goog.dom.getFirstElementChild = function(node) {
1105
+ if (node.firstElementChild != undefined) {
1106
+ return /** @type {Element} */(node).firstElementChild;
1107
+ }
1108
+ return goog.dom.getNextElementNode_(node.firstChild, true);
1109
+ };
1110
+
1111
+
1112
+ /**
1113
+ * Returns the last child node that is an element.
1114
+ * @param {Node} node The node to get the last child element of.
1115
+ * @return {Element} The last child node of {@code node} that is an element.
1116
+ */
1117
+ goog.dom.getLastElementChild = function(node) {
1118
+ if (node.lastElementChild != undefined) {
1119
+ return /** @type {Element} */(node).lastElementChild;
1120
+ }
1121
+ return goog.dom.getNextElementNode_(node.lastChild, false);
1122
+ };
1123
+
1124
+
1125
+ /**
1126
+ * Returns the first next sibling that is an element.
1127
+ * @param {Node} node The node to get the next sibling element of.
1128
+ * @return {Element} The next sibling of {@code node} that is an element.
1129
+ */
1130
+ goog.dom.getNextElementSibling = function(node) {
1131
+ if (node.nextElementSibling != undefined) {
1132
+ return /** @type {Element} */(node).nextElementSibling;
1133
+ }
1134
+ return goog.dom.getNextElementNode_(node.nextSibling, true);
1135
+ };
1136
+
1137
+
1138
+ /**
1139
+ * Returns the first previous sibling that is an element.
1140
+ * @param {Node} node The node to get the previous sibling element of.
1141
+ * @return {Element} The first previous sibling of {@code node} that is
1142
+ * an element.
1143
+ */
1144
+ goog.dom.getPreviousElementSibling = function(node) {
1145
+ if (node.previousElementSibling != undefined) {
1146
+ return /** @type {Element} */(node).previousElementSibling;
1147
+ }
1148
+ return goog.dom.getNextElementNode_(node.previousSibling, false);
1149
+ };
1150
+
1151
+
1152
+ /**
1153
+ * Returns the first node that is an element in the specified direction,
1154
+ * starting with {@code node}.
1155
+ * @param {Node} node The node to get the next element from.
1156
+ * @param {boolean} forward Whether to look forwards or backwards.
1157
+ * @return {Element} The first element.
1158
+ * @private
1159
+ */
1160
+ goog.dom.getNextElementNode_ = function(node, forward) {
1161
+ while (node && node.nodeType != goog.dom.NodeType.ELEMENT) {
1162
+ node = forward ? node.nextSibling : node.previousSibling;
1163
+ }
1164
+
1165
+ return /** @type {Element} */ (node);
1166
+ };
1167
+
1168
+
1169
+ /**
1170
+ * Returns the next node in source order from the given node.
1171
+ * @param {Node} node The node.
1172
+ * @return {Node} The next node in the DOM tree, or null if this was the last
1173
+ * node.
1174
+ */
1175
+ goog.dom.getNextNode = function(node) {
1176
+ if (!node) {
1177
+ return null;
1178
+ }
1179
+
1180
+ if (node.firstChild) {
1181
+ return node.firstChild;
1182
+ }
1183
+
1184
+ while (node && !node.nextSibling) {
1185
+ node = node.parentNode;
1186
+ }
1187
+
1188
+ return node ? node.nextSibling : null;
1189
+ };
1190
+
1191
+
1192
+ /**
1193
+ * Returns the previous node in source order from the given node.
1194
+ * @param {Node} node The node.
1195
+ * @return {Node} The previous node in the DOM tree, or null if this was the
1196
+ * first node.
1197
+ */
1198
+ goog.dom.getPreviousNode = function(node) {
1199
+ if (!node) {
1200
+ return null;
1201
+ }
1202
+
1203
+ if (!node.previousSibling) {
1204
+ return node.parentNode;
1205
+ }
1206
+
1207
+ node = node.previousSibling;
1208
+ while (node && node.lastChild) {
1209
+ node = node.lastChild;
1210
+ }
1211
+
1212
+ return node;
1213
+ };
1214
+
1215
+
1216
+ /**
1217
+ * Whether the object looks like a DOM node.
1218
+ * @param {*} obj The object being tested for node likeness.
1219
+ * @return {boolean} Whether the object looks like a DOM node.
1220
+ */
1221
+ goog.dom.isNodeLike = function(obj) {
1222
+ return goog.isObject(obj) && obj.nodeType > 0;
1223
+ };
1224
+
1225
+
1226
+ /**
1227
+ * Whether the object looks like an Element.
1228
+ * @param {*} obj The object being tested for Element likeness.
1229
+ * @return {boolean} Whether the object looks like an Element.
1230
+ */
1231
+ goog.dom.isElement = function(obj) {
1232
+ return goog.isObject(obj) && obj.nodeType == goog.dom.NodeType.ELEMENT;
1233
+ };
1234
+
1235
+
1236
+ /**
1237
+ * Returns true if the specified value is a Window object. This includes the
1238
+ * global window for HTML pages, and iframe windows.
1239
+ * @param {*} obj Variable to test.
1240
+ * @return {boolean} Whether the variable is a window.
1241
+ */
1242
+ goog.dom.isWindow = function(obj) {
1243
+ return goog.isObject(obj) && obj['window'] == obj;
1244
+ };
1245
+
1246
+
1247
+ /**
1248
+ * Returns an element's parent, if it's an Element.
1249
+ * @param {Element} element The DOM element.
1250
+ * @return {Element} The parent, or null if not an Element.
1251
+ */
1252
+ goog.dom.getParentElement = function(element) {
1253
+ if (goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY) {
1254
+ return element.parentElement;
1255
+ }
1256
+ var parent = element.parentNode;
1257
+ return goog.dom.isElement(parent) ? (/** @type {!Element} */ parent) : null;
1258
+ };
1259
+
1260
+
1261
+ /**
1262
+ * Whether a node contains another node.
1263
+ * @param {Node} parent The node that should contain the other node.
1264
+ * @param {Node} descendant The node to test presence of.
1265
+ * @return {boolean} Whether the parent node contains the descendent node.
1266
+ */
1267
+ goog.dom.contains = function(parent, descendant) {
1268
+ // We use browser specific methods for this if available since it is faster
1269
+ // that way.
1270
+
1271
+ // IE DOM
1272
+ if (parent.contains && descendant.nodeType == goog.dom.NodeType.ELEMENT) {
1273
+ return parent == descendant || parent.contains(descendant);
1274
+ }
1275
+
1276
+ // W3C DOM Level 3
1277
+ if (typeof parent.compareDocumentPosition != 'undefined') {
1278
+ return parent == descendant ||
1279
+ Boolean(parent.compareDocumentPosition(descendant) & 16);
1280
+ }
1281
+
1282
+ // W3C DOM Level 1
1283
+ while (descendant && parent != descendant) {
1284
+ descendant = descendant.parentNode;
1285
+ }
1286
+ return descendant == parent;
1287
+ };
1288
+
1289
+
1290
+ /**
1291
+ * Compares the document order of two nodes, returning 0 if they are the same
1292
+ * node, a negative number if node1 is before node2, and a positive number if
1293
+ * node2 is before node1. Note that we compare the order the tags appear in the
1294
+ * document so in the tree <b><i>text</i></b> the B node is considered to be
1295
+ * before the I node.
1296
+ *
1297
+ * @param {Node} node1 The first node to compare.
1298
+ * @param {Node} node2 The second node to compare.
1299
+ * @return {number} 0 if the nodes are the same node, a negative number if node1
1300
+ * is before node2, and a positive number if node2 is before node1.
1301
+ */
1302
+ goog.dom.compareNodeOrder = function(node1, node2) {
1303
+ // Fall out quickly for equality.
1304
+ if (node1 == node2) {
1305
+ return 0;
1306
+ }
1307
+
1308
+ // Use compareDocumentPosition where available
1309
+ if (node1.compareDocumentPosition) {
1310
+ // 4 is the bitmask for FOLLOWS.
1311
+ return node1.compareDocumentPosition(node2) & 2 ? 1 : -1;
1312
+ }
1313
+
1314
+ // Process in IE using sourceIndex - we check to see if the first node has
1315
+ // a source index or if its parent has one.
1316
+ if ('sourceIndex' in node1 ||
1317
+ (node1.parentNode && 'sourceIndex' in node1.parentNode)) {
1318
+ var isElement1 = node1.nodeType == goog.dom.NodeType.ELEMENT;
1319
+ var isElement2 = node2.nodeType == goog.dom.NodeType.ELEMENT;
1320
+
1321
+ if (isElement1 && isElement2) {
1322
+ return node1.sourceIndex - node2.sourceIndex;
1323
+ } else {
1324
+ var parent1 = node1.parentNode;
1325
+ var parent2 = node2.parentNode;
1326
+
1327
+ if (parent1 == parent2) {
1328
+ return goog.dom.compareSiblingOrder_(node1, node2);
1329
+ }
1330
+
1331
+ if (!isElement1 && goog.dom.contains(parent1, node2)) {
1332
+ return -1 * goog.dom.compareParentsDescendantNodeIe_(node1, node2);
1333
+ }
1334
+
1335
+
1336
+ if (!isElement2 && goog.dom.contains(parent2, node1)) {
1337
+ return goog.dom.compareParentsDescendantNodeIe_(node2, node1);
1338
+ }
1339
+
1340
+ return (isElement1 ? node1.sourceIndex : parent1.sourceIndex) -
1341
+ (isElement2 ? node2.sourceIndex : parent2.sourceIndex);
1342
+ }
1343
+ }
1344
+
1345
+ // For Safari, we compare ranges.
1346
+ var doc = goog.dom.getOwnerDocument(node1);
1347
+
1348
+ var range1, range2;
1349
+ range1 = doc.createRange();
1350
+ range1.selectNode(node1);
1351
+ range1.collapse(true);
1352
+
1353
+ range2 = doc.createRange();
1354
+ range2.selectNode(node2);
1355
+ range2.collapse(true);
1356
+
1357
+ return range1.compareBoundaryPoints(goog.global['Range'].START_TO_END,
1358
+ range2);
1359
+ };
1360
+
1361
+
1362
+ /**
1363
+ * Utility function to compare the position of two nodes, when
1364
+ * {@code textNode}'s parent is an ancestor of {@code node}. If this entry
1365
+ * condition is not met, this function will attempt to reference a null object.
1366
+ * @param {Node} textNode The textNode to compare.
1367
+ * @param {Node} node The node to compare.
1368
+ * @return {number} -1 if node is before textNode, +1 otherwise.
1369
+ * @private
1370
+ */
1371
+ goog.dom.compareParentsDescendantNodeIe_ = function(textNode, node) {
1372
+ var parent = textNode.parentNode;
1373
+ if (parent == node) {
1374
+ // If textNode is a child of node, then node comes first.
1375
+ return -1;
1376
+ }
1377
+ var sibling = node;
1378
+ while (sibling.parentNode != parent) {
1379
+ sibling = sibling.parentNode;
1380
+ }
1381
+ return goog.dom.compareSiblingOrder_(sibling, textNode);
1382
+ };
1383
+
1384
+
1385
+ /**
1386
+ * Utility function to compare the position of two nodes known to be non-equal
1387
+ * siblings.
1388
+ * @param {Node} node1 The first node to compare.
1389
+ * @param {Node} node2 The second node to compare.
1390
+ * @return {number} -1 if node1 is before node2, +1 otherwise.
1391
+ * @private
1392
+ */
1393
+ goog.dom.compareSiblingOrder_ = function(node1, node2) {
1394
+ var s = node2;
1395
+ while ((s = s.previousSibling)) {
1396
+ if (s == node1) {
1397
+ // We just found node1 before node2.
1398
+ return -1;
1399
+ }
1400
+ }
1401
+
1402
+ // Since we didn't find it, node1 must be after node2.
1403
+ return 1;
1404
+ };
1405
+
1406
+
1407
+ /**
1408
+ * Find the deepest common ancestor of the given nodes.
1409
+ * @param {...Node} var_args The nodes to find a common ancestor of.
1410
+ * @return {Node} The common ancestor of the nodes, or null if there is none.
1411
+ * null will only be returned if two or more of the nodes are from different
1412
+ * documents.
1413
+ */
1414
+ goog.dom.findCommonAncestor = function(var_args) {
1415
+ var i, count = arguments.length;
1416
+ if (!count) {
1417
+ return null;
1418
+ } else if (count == 1) {
1419
+ return arguments[0];
1420
+ }
1421
+
1422
+ var paths = [];
1423
+ var minLength = Infinity;
1424
+ for (i = 0; i < count; i++) {
1425
+ // Compute the list of ancestors.
1426
+ var ancestors = [];
1427
+ var node = arguments[i];
1428
+ while (node) {
1429
+ ancestors.unshift(node);
1430
+ node = node.parentNode;
1431
+ }
1432
+
1433
+ // Save the list for comparison.
1434
+ paths.push(ancestors);
1435
+ minLength = Math.min(minLength, ancestors.length);
1436
+ }
1437
+ var output = null;
1438
+ for (i = 0; i < minLength; i++) {
1439
+ var first = paths[0][i];
1440
+ for (var j = 1; j < count; j++) {
1441
+ if (first != paths[j][i]) {
1442
+ return output;
1443
+ }
1444
+ }
1445
+ output = first;
1446
+ }
1447
+ return output;
1448
+ };
1449
+
1450
+
1451
+ /**
1452
+ * Returns the owner document for a node.
1453
+ * @param {Node|Window} node The node to get the document for.
1454
+ * @return {!Document} The document owning the node.
1455
+ */
1456
+ goog.dom.getOwnerDocument = function(node) {
1457
+ // TODO(arv): Remove IE5 code.
1458
+ // IE5 uses document instead of ownerDocument
1459
+ return /** @type {!Document} */ (
1460
+ node.nodeType == goog.dom.NodeType.DOCUMENT ? node :
1461
+ node.ownerDocument || node.document);
1462
+ };
1463
+
1464
+
1465
+ /**
1466
+ * Cross-browser function for getting the document element of a frame or iframe.
1467
+ * @param {Element} frame Frame element.
1468
+ * @return {!Document} The frame content document.
1469
+ */
1470
+ goog.dom.getFrameContentDocument = function(frame) {
1471
+ var doc = frame.contentDocument || frame.contentWindow.document;
1472
+ return doc;
1473
+ };
1474
+
1475
+
1476
+ /**
1477
+ * Cross-browser function for getting the window of a frame or iframe.
1478
+ * @param {HTMLIFrameElement|HTMLFrameElement} frame Frame element.
1479
+ * @return {Window} The window associated with the given frame.
1480
+ */
1481
+ goog.dom.getFrameContentWindow = function(frame) {
1482
+ return frame.contentWindow ||
1483
+ goog.dom.getWindow_(goog.dom.getFrameContentDocument(frame));
1484
+ };
1485
+
1486
+
1487
+ /**
1488
+ * Cross-browser function for setting the text content of an element.
1489
+ * @param {Element} element The element to change the text content of.
1490
+ * @param {string} text The string that should replace the current element
1491
+ * content.
1492
+ */
1493
+ goog.dom.setTextContent = function(element, text) {
1494
+ if ('textContent' in element) {
1495
+ element.textContent = text;
1496
+ } else if (element.firstChild &&
1497
+ element.firstChild.nodeType == goog.dom.NodeType.TEXT) {
1498
+ // If the first child is a text node we just change its data and remove the
1499
+ // rest of the children.
1500
+ while (element.lastChild != element.firstChild) {
1501
+ element.removeChild(element.lastChild);
1502
+ }
1503
+ element.firstChild.data = text;
1504
+ } else {
1505
+ goog.dom.removeChildren(element);
1506
+ var doc = goog.dom.getOwnerDocument(element);
1507
+ element.appendChild(doc.createTextNode(text));
1508
+ }
1509
+ };
1510
+
1511
+
1512
+ /**
1513
+ * Gets the outerHTML of a node, which islike innerHTML, except that it
1514
+ * actually contains the HTML of the node itself.
1515
+ * @param {Element} element The element to get the HTML of.
1516
+ * @return {string} The outerHTML of the given element.
1517
+ */
1518
+ goog.dom.getOuterHtml = function(element) {
1519
+ // IE, Opera and WebKit all have outerHTML.
1520
+ if ('outerHTML' in element) {
1521
+ return element.outerHTML;
1522
+ } else {
1523
+ var doc = goog.dom.getOwnerDocument(element);
1524
+ var div = doc.createElement('div');
1525
+ div.appendChild(element.cloneNode(true));
1526
+ return div.innerHTML;
1527
+ }
1528
+ };
1529
+
1530
+
1531
+ /**
1532
+ * Finds the first descendant node that matches the filter function, using
1533
+ * a depth first search. This function offers the most general purpose way
1534
+ * of finding a matching element. You may also wish to consider
1535
+ * {@code goog.dom.query} which can express many matching criteria using
1536
+ * CSS selector expressions. These expressions often result in a more
1537
+ * compact representation of the desired result.
1538
+ * @see goog.dom.query
1539
+ *
1540
+ * @param {Node} root The root of the tree to search.
1541
+ * @param {function(Node) : boolean} p The filter function.
1542
+ * @return {Node|undefined} The found node or undefined if none is found.
1543
+ */
1544
+ goog.dom.findNode = function(root, p) {
1545
+ var rv = [];
1546
+ var found = goog.dom.findNodes_(root, p, rv, true);
1547
+ return found ? rv[0] : undefined;
1548
+ };
1549
+
1550
+
1551
+ /**
1552
+ * Finds all the descendant nodes that match the filter function, using a
1553
+ * a depth first search. This function offers the most general-purpose way
1554
+ * of finding a set of matching elements. You may also wish to consider
1555
+ * {@code goog.dom.query} which can express many matching criteria using
1556
+ * CSS selector expressions. These expressions often result in a more
1557
+ * compact representation of the desired result.
1558
+
1559
+ * @param {Node} root The root of the tree to search.
1560
+ * @param {function(Node) : boolean} p The filter function.
1561
+ * @return {Array.<Node>} The found nodes or an empty array if none are found.
1562
+ */
1563
+ goog.dom.findNodes = function(root, p) {
1564
+ var rv = [];
1565
+ goog.dom.findNodes_(root, p, rv, false);
1566
+ return rv;
1567
+ };
1568
+
1569
+
1570
+ /**
1571
+ * Finds the first or all the descendant nodes that match the filter function,
1572
+ * using a depth first search.
1573
+ * @param {Node} root The root of the tree to search.
1574
+ * @param {function(Node) : boolean} p The filter function.
1575
+ * @param {Array.<Node>} rv The found nodes are added to this array.
1576
+ * @param {boolean} findOne If true we exit after the first found node.
1577
+ * @return {boolean} Whether the search is complete or not. True in case findOne
1578
+ * is true and the node is found. False otherwise.
1579
+ * @private
1580
+ */
1581
+ goog.dom.findNodes_ = function(root, p, rv, findOne) {
1582
+ if (root != null) {
1583
+ var child = root.firstChild;
1584
+ while (child) {
1585
+ if (p(child)) {
1586
+ rv.push(child);
1587
+ if (findOne) {
1588
+ return true;
1589
+ }
1590
+ }
1591
+ if (goog.dom.findNodes_(child, p, rv, findOne)) {
1592
+ return true;
1593
+ }
1594
+ child = child.nextSibling;
1595
+ }
1596
+ }
1597
+ return false;
1598
+ };
1599
+
1600
+
1601
+ /**
1602
+ * Map of tags whose content to ignore when calculating text length.
1603
+ * @type {Object}
1604
+ * @private
1605
+ */
1606
+ goog.dom.TAGS_TO_IGNORE_ = {
1607
+ 'SCRIPT': 1,
1608
+ 'STYLE': 1,
1609
+ 'HEAD': 1,
1610
+ 'IFRAME': 1,
1611
+ 'OBJECT': 1
1612
+ };
1613
+
1614
+
1615
+ /**
1616
+ * Map of tags which have predefined values with regard to whitespace.
1617
+ * @type {Object}
1618
+ * @private
1619
+ */
1620
+ goog.dom.PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'};
1621
+
1622
+
1623
+ /**
1624
+ * Returns true if the element has a tab index that allows it to receive
1625
+ * keyboard focus (tabIndex >= 0), false otherwise. Note that form elements
1626
+ * natively support keyboard focus, even if they have no tab index.
1627
+ * @param {Element} element Element to check.
1628
+ * @return {boolean} Whether the element has a tab index that allows keyboard
1629
+ * focus.
1630
+ * @see http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1631
+ */
1632
+ goog.dom.isFocusableTabIndex = function(element) {
1633
+ // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(),
1634
+ // which returns an object with a 'specified' property if tabIndex is
1635
+ // specified. This works on other browsers, too.
1636
+ var attrNode = element.getAttributeNode('tabindex'); // Must be lowercase!
1637
+ if (attrNode && attrNode.specified) {
1638
+ var index = element.tabIndex;
1639
+ // NOTE: IE9 puts tabIndex in 16-bit int, e.g. -2 is 65534.
1640
+ return goog.isNumber(index) && index >= 0 && index < 32768;
1641
+ }
1642
+ return false;
1643
+ };
1644
+
1645
+
1646
+ /**
1647
+ * Enables or disables keyboard focus support on the element via its tab index.
1648
+ * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true
1649
+ * (or elements that natively support keyboard focus, like form elements) can
1650
+ * receive keyboard focus. See http://go/tabindex for more info.
1651
+ * @param {Element} element Element whose tab index is to be changed.
1652
+ * @param {boolean} enable Whether to set or remove a tab index on the element
1653
+ * that supports keyboard focus.
1654
+ */
1655
+ goog.dom.setFocusableTabIndex = function(element, enable) {
1656
+ if (enable) {
1657
+ element.tabIndex = 0;
1658
+ } else {
1659
+ // Set tabIndex to -1 first, then remove it. This is a workaround for
1660
+ // Safari (confirmed in version 4 on Windows). When removing the attribute
1661
+ // without setting it to -1 first, the element remains keyboard focusable
1662
+ // despite not having a tabIndex attribute anymore.
1663
+ element.tabIndex = -1;
1664
+ element.removeAttribute('tabIndex'); // Must be camelCase!
1665
+ }
1666
+ };
1667
+
1668
+
1669
+ /**
1670
+ * Returns the text content of the current node, without markup and invisible
1671
+ * symbols. New lines are stripped and whitespace is collapsed,
1672
+ * such that each character would be visible.
1673
+ *
1674
+ * In browsers that support it, innerText is used. Other browsers attempt to
1675
+ * simulate it via node traversal. Line breaks are canonicalized in IE.
1676
+ *
1677
+ * @param {Node} node The node from which we are getting content.
1678
+ * @return {string} The text content.
1679
+ */
1680
+ goog.dom.getTextContent = function(node) {
1681
+ var textContent;
1682
+ // Note(arv): IE9, Opera, and Safari 3 support innerText but they include
1683
+ // text nodes in script tags. So we revert to use a user agent test here.
1684
+ if (goog.dom.BrowserFeature.CAN_USE_INNER_TEXT && ('innerText' in node)) {
1685
+ textContent = goog.string.canonicalizeNewlines(node.innerText);
1686
+ // Unfortunately .innerText() returns text with &shy; symbols
1687
+ // We need to filter it out and then remove duplicate whitespaces
1688
+ } else {
1689
+ var buf = [];
1690
+ goog.dom.getTextContent_(node, buf, true);
1691
+ textContent = buf.join('');
1692
+ }
1693
+
1694
+ // Strip &shy; entities. goog.format.insertWordBreaks inserts them in Opera.
1695
+ textContent = textContent.replace(/ \xAD /g, ' ').replace(/\xAD/g, '');
1696
+ // Strip &#8203; entities. goog.format.insertWordBreaks inserts them in IE8.
1697
+ textContent = textContent.replace(/\u200B/g, '');
1698
+
1699
+ // Skip this replacement on old browsers with working innerText, which
1700
+ // automatically turns &nbsp; into ' ' and / +/ into ' ' when reading
1701
+ // innerText.
1702
+ if (!goog.dom.BrowserFeature.CAN_USE_INNER_TEXT) {
1703
+ textContent = textContent.replace(/ +/g, ' ');
1704
+ }
1705
+ if (textContent != ' ') {
1706
+ textContent = textContent.replace(/^\s*/, '');
1707
+ }
1708
+
1709
+ return textContent;
1710
+ };
1711
+
1712
+
1713
+ /**
1714
+ * Returns the text content of the current node, without markup.
1715
+ *
1716
+ * Unlike {@code getTextContent} this method does not collapse whitespaces
1717
+ * or normalize lines breaks.
1718
+ *
1719
+ * @param {Node} node The node from which we are getting content.
1720
+ * @return {string} The raw text content.
1721
+ */
1722
+ goog.dom.getRawTextContent = function(node) {
1723
+ var buf = [];
1724
+ goog.dom.getTextContent_(node, buf, false);
1725
+
1726
+ return buf.join('');
1727
+ };
1728
+
1729
+
1730
+ /**
1731
+ * Recursive support function for text content retrieval.
1732
+ *
1733
+ * @param {Node} node The node from which we are getting content.
1734
+ * @param {Array} buf string buffer.
1735
+ * @param {boolean} normalizeWhitespace Whether to normalize whitespace.
1736
+ * @private
1737
+ */
1738
+ goog.dom.getTextContent_ = function(node, buf, normalizeWhitespace) {
1739
+ if (node.nodeName in goog.dom.TAGS_TO_IGNORE_) {
1740
+ // ignore certain tags
1741
+ } else if (node.nodeType == goog.dom.NodeType.TEXT) {
1742
+ if (normalizeWhitespace) {
1743
+ buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
1744
+ } else {
1745
+ buf.push(node.nodeValue);
1746
+ }
1747
+ } else if (node.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) {
1748
+ buf.push(goog.dom.PREDEFINED_TAG_VALUES_[node.nodeName]);
1749
+ } else {
1750
+ var child = node.firstChild;
1751
+ while (child) {
1752
+ goog.dom.getTextContent_(child, buf, normalizeWhitespace);
1753
+ child = child.nextSibling;
1754
+ }
1755
+ }
1756
+ };
1757
+
1758
+
1759
+ /**
1760
+ * Returns the text length of the text contained in a node, without markup. This
1761
+ * is equivalent to the selection length if the node was selected, or the number
1762
+ * of cursor movements to traverse the node. Images & BRs take one space. New
1763
+ * lines are ignored.
1764
+ *
1765
+ * @param {Node} node The node whose text content length is being calculated.
1766
+ * @return {number} The length of {@code node}'s text content.
1767
+ */
1768
+ goog.dom.getNodeTextLength = function(node) {
1769
+ return goog.dom.getTextContent(node).length;
1770
+ };
1771
+
1772
+
1773
+ /**
1774
+ * Returns the text offset of a node relative to one of its ancestors. The text
1775
+ * length is the same as the length calculated by goog.dom.getNodeTextLength.
1776
+ *
1777
+ * @param {Node} node The node whose offset is being calculated.
1778
+ * @param {Node=} opt_offsetParent The node relative to which the offset will
1779
+ * be calculated. Defaults to the node's owner document's body.
1780
+ * @return {number} The text offset.
1781
+ */
1782
+ goog.dom.getNodeTextOffset = function(node, opt_offsetParent) {
1783
+ var root = opt_offsetParent || goog.dom.getOwnerDocument(node).body;
1784
+ var buf = [];
1785
+ while (node && node != root) {
1786
+ var cur = node;
1787
+ while ((cur = cur.previousSibling)) {
1788
+ buf.unshift(goog.dom.getTextContent(cur));
1789
+ }
1790
+ node = node.parentNode;
1791
+ }
1792
+ // Trim left to deal with FF cases when there might be line breaks and empty
1793
+ // nodes at the front of the text
1794
+ return goog.string.trimLeft(buf.join('')).replace(/ +/g, ' ').length;
1795
+ };
1796
+
1797
+
1798
+ /**
1799
+ * Returns the node at a given offset in a parent node. If an object is
1800
+ * provided for the optional third parameter, the node and the remainder of the
1801
+ * offset will stored as properties of this object.
1802
+ * @param {Node} parent The parent node.
1803
+ * @param {number} offset The offset into the parent node.
1804
+ * @param {Object=} opt_result Object to be used to store the return value. The
1805
+ * return value will be stored in the form {node: Node, remainder: number}
1806
+ * if this object is provided.
1807
+ * @return {Node} The node at the given offset.
1808
+ */
1809
+ goog.dom.getNodeAtOffset = function(parent, offset, opt_result) {
1810
+ var stack = [parent], pos = 0, cur;
1811
+ while (stack.length > 0 && pos < offset) {
1812
+ cur = stack.pop();
1813
+ if (cur.nodeName in goog.dom.TAGS_TO_IGNORE_) {
1814
+ // ignore certain tags
1815
+ } else if (cur.nodeType == goog.dom.NodeType.TEXT) {
1816
+ var text = cur.nodeValue.replace(/(\r\n|\r|\n)/g, '').replace(/ +/g, ' ');
1817
+ pos += text.length;
1818
+ } else if (cur.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) {
1819
+ pos += goog.dom.PREDEFINED_TAG_VALUES_[cur.nodeName].length;
1820
+ } else {
1821
+ for (var i = cur.childNodes.length - 1; i >= 0; i--) {
1822
+ stack.push(cur.childNodes[i]);
1823
+ }
1824
+ }
1825
+ }
1826
+ if (goog.isObject(opt_result)) {
1827
+ opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0;
1828
+ opt_result.node = cur;
1829
+ }
1830
+
1831
+ return cur;
1832
+ };
1833
+
1834
+
1835
+ /**
1836
+ * Returns true if the object is a {@code NodeList}. To qualify as a NodeList,
1837
+ * the object must have a numeric length property and an item function (which
1838
+ * has type 'string' on IE for some reason).
1839
+ * @param {Object} val Object to test.
1840
+ * @return {boolean} Whether the object is a NodeList.
1841
+ */
1842
+ goog.dom.isNodeList = function(val) {
1843
+ // TODO(attila): Now the isNodeList is part of goog.dom we can use
1844
+ // goog.userAgent to make this simpler.
1845
+ // A NodeList must have a length property of type 'number' on all platforms.
1846
+ if (val && typeof val.length == 'number') {
1847
+ // A NodeList is an object everywhere except Safari, where it's a function.
1848
+ if (goog.isObject(val)) {
1849
+ // A NodeList must have an item function (on non-IE platforms) or an item
1850
+ // property of type 'string' (on IE).
1851
+ return typeof val.item == 'function' || typeof val.item == 'string';
1852
+ } else if (goog.isFunction(val)) {
1853
+ // On Safari, a NodeList is a function with an item property that is also
1854
+ // a function.
1855
+ return typeof val.item == 'function';
1856
+ }
1857
+ }
1858
+
1859
+ // Not a NodeList.
1860
+ return false;
1861
+ };
1862
+
1863
+
1864
+ /**
1865
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
1866
+ * tag name and/or class name. If the passed element matches the specified
1867
+ * criteria, the element itself is returned.
1868
+ * @param {Node} element The DOM node to start with.
1869
+ * @param {?string=} opt_tag The tag name to match (or null/undefined to match
1870
+ * any node regardless of tag name). Must be uppercase (goog.dom.TagName).
1871
+ * @param {?string=} opt_class The class name to match (or null/undefined to
1872
+ * match any node regardless of class name).
1873
+ * @return {Node} The first ancestor that matches the passed criteria, or
1874
+ * null if none match.
1875
+ */
1876
+ goog.dom.getAncestorByTagNameAndClass = function(element, opt_tag, opt_class) {
1877
+ var tagName = opt_tag ? opt_tag.toUpperCase() : null;
1878
+ return goog.dom.getAncestor(element,
1879
+ function(node) {
1880
+ return (!tagName || node.nodeName == tagName) &&
1881
+ (!opt_class || goog.dom.classes.has(node, opt_class));
1882
+ }, true);
1883
+ };
1884
+
1885
+
1886
+ /**
1887
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
1888
+ * class name. If the passed element matches the specified criteria, the
1889
+ * element itself is returned.
1890
+ * @param {Node} element The DOM node to start with.
1891
+ * @param {?string=} opt_class The class name to match (or null/undefined to
1892
+ * match any node regardless of class name).
1893
+ * @return {Node} The first ancestor that matches the passed criteria, or
1894
+ * null if none match.
1895
+ */
1896
+ goog.dom.getAncestorByClass = function(element, opt_class) {
1897
+ return goog.dom.getAncestorByTagNameAndClass(element, null, opt_class);
1898
+ };
1899
+
1900
+
1901
+ /**
1902
+ * Walks up the DOM hierarchy returning the first ancestor that passes the
1903
+ * matcher function.
1904
+ * @param {Node} element The DOM node to start with.
1905
+ * @param {function(Node) : boolean} matcher A function that returns true if the
1906
+ * passed node matches the desired criteria.
1907
+ * @param {boolean=} opt_includeNode If true, the node itself is included in
1908
+ * the search (the first call to the matcher will pass startElement as
1909
+ * the node to test).
1910
+ * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
1911
+ * dom.
1912
+ * @return {Node} DOM node that matched the matcher, or null if there was
1913
+ * no match.
1914
+ */
1915
+ goog.dom.getAncestor = function(
1916
+ element, matcher, opt_includeNode, opt_maxSearchSteps) {
1917
+ if (!opt_includeNode) {
1918
+ element = element.parentNode;
1919
+ }
1920
+ var ignoreSearchSteps = opt_maxSearchSteps == null;
1921
+ var steps = 0;
1922
+ while (element && (ignoreSearchSteps || steps <= opt_maxSearchSteps)) {
1923
+ if (matcher(element)) {
1924
+ return element;
1925
+ }
1926
+ element = element.parentNode;
1927
+ steps++;
1928
+ }
1929
+ // Reached the root of the DOM without a match
1930
+ return null;
1931
+ };
1932
+
1933
+
1934
+ /**
1935
+ * Determines the active element in the given document.
1936
+ * @param {Document} doc The document to look in.
1937
+ * @return {Element} The active element.
1938
+ */
1939
+ goog.dom.getActiveElement = function(doc) {
1940
+ try {
1941
+ return doc && doc.activeElement;
1942
+ } catch (e) {
1943
+ // NOTE(nicksantos): Sometimes, evaluating document.activeElement in IE
1944
+ // throws an exception. I'm not 100% sure why, but I suspect it chokes
1945
+ // on document.activeElement if the activeElement has been recently
1946
+ // removed from the DOM by a JS operation.
1947
+ //
1948
+ // We assume that an exception here simply means
1949
+ // "there is no active element."
1950
+ }
1951
+
1952
+ return null;
1953
+ };
1954
+
1955
+
1956
+
1957
+ /**
1958
+ * Create an instance of a DOM helper with a new document object.
1959
+ * @param {Document=} opt_document Document object to associate with this
1960
+ * DOM helper.
1961
+ * @constructor
1962
+ */
1963
+ goog.dom.DomHelper = function(opt_document) {
1964
+ /**
1965
+ * Reference to the document object to use
1966
+ * @type {!Document}
1967
+ * @private
1968
+ */
1969
+ this.document_ = opt_document || goog.global.document || document;
1970
+ };
1971
+
1972
+
1973
+ /**
1974
+ * Gets the dom helper object for the document where the element resides.
1975
+ * @param {Node=} opt_node If present, gets the DomHelper for this node.
1976
+ * @return {!goog.dom.DomHelper} The DomHelper.
1977
+ */
1978
+ goog.dom.DomHelper.prototype.getDomHelper = goog.dom.getDomHelper;
1979
+
1980
+
1981
+ /**
1982
+ * Sets the document object.
1983
+ * @param {!Document} document Document object.
1984
+ */
1985
+ goog.dom.DomHelper.prototype.setDocument = function(document) {
1986
+ this.document_ = document;
1987
+ };
1988
+
1989
+
1990
+ /**
1991
+ * Gets the document object being used by the dom library.
1992
+ * @return {!Document} Document object.
1993
+ */
1994
+ goog.dom.DomHelper.prototype.getDocument = function() {
1995
+ return this.document_;
1996
+ };
1997
+
1998
+
1999
+ /**
2000
+ * Alias for {@code getElementById}. If a DOM node is passed in then we just
2001
+ * return that.
2002
+ * @param {string|Element} element Element ID or a DOM node.
2003
+ * @return {Element} The element with the given ID, or the node passed in.
2004
+ */
2005
+ goog.dom.DomHelper.prototype.getElement = function(element) {
2006
+ if (goog.isString(element)) {
2007
+ return this.document_.getElementById(element);
2008
+ } else {
2009
+ return element;
2010
+ }
2011
+ };
2012
+
2013
+
2014
+ /**
2015
+ * Alias for {@code getElement}.
2016
+ * @param {string|Element} element Element ID or a DOM node.
2017
+ * @return {Element} The element with the given ID, or the node passed in.
2018
+ * @deprecated Use {@link goog.dom.DomHelper.prototype.getElement} instead.
2019
+ */
2020
+ goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement;
2021
+
2022
+
2023
+ /**
2024
+ * Looks up elements by both tag and class name, using browser native functions
2025
+ * ({@code querySelectorAll}, {@code getElementsByTagName} or
2026
+ * {@code getElementsByClassName}) where possible. The returned array is a live
2027
+ * NodeList or a static list depending on the code path taken.
2028
+ *
2029
+ * @see goog.dom.query
2030
+ *
2031
+ * @param {?string=} opt_tag Element tag name or * for all tags.
2032
+ * @param {?string=} opt_class Optional class name.
2033
+ * @param {Document|Element=} opt_el Optional element to look in.
2034
+ * @return { {length: number} } Array-like list of elements (only a length
2035
+ * property and numerical indices are guaranteed to exist).
2036
+ */
2037
+ goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(opt_tag,
2038
+ opt_class,
2039
+ opt_el) {
2040
+ return goog.dom.getElementsByTagNameAndClass_(this.document_, opt_tag,
2041
+ opt_class, opt_el);
2042
+ };
2043
+
2044
+
2045
+ /**
2046
+ * Returns an array of all the elements with the provided className.
2047
+ * @see {goog.dom.query}
2048
+ * @param {string} className the name of the class to look for.
2049
+ * @param {Element|Document=} opt_el Optional element to look in.
2050
+ * @return { {length: number} } The items found with the class name provided.
2051
+ */
2052
+ goog.dom.DomHelper.prototype.getElementsByClass = function(className, opt_el) {
2053
+ var doc = opt_el || this.document_;
2054
+ return goog.dom.getElementsByClass(className, doc);
2055
+ };
2056
+
2057
+
2058
+ /**
2059
+ * Returns the first element we find matching the provided class name.
2060
+ * @see {goog.dom.query}
2061
+ * @param {string} className the name of the class to look for.
2062
+ * @param {Element|Document=} opt_el Optional element to look in.
2063
+ * @return {Element} The first item found with the class name provided.
2064
+ */
2065
+ goog.dom.DomHelper.prototype.getElementByClass = function(className, opt_el) {
2066
+ var doc = opt_el || this.document_;
2067
+ return goog.dom.getElementByClass(className, doc);
2068
+ };
2069
+
2070
+
2071
+ /**
2072
+ * Alias for {@code getElementsByTagNameAndClass}.
2073
+ * @deprecated Use DomHelper getElementsByTagNameAndClass.
2074
+ * @see goog.dom.query
2075
+ *
2076
+ * @param {?string=} opt_tag Element tag name.
2077
+ * @param {?string=} opt_class Optional class name.
2078
+ * @param {Element=} opt_el Optional element to look in.
2079
+ * @return { {length: number} } Array-like list of elements (only a length
2080
+ * property and numerical indices are guaranteed to exist).
2081
+ */
2082
+ goog.dom.DomHelper.prototype.$$ =
2083
+ goog.dom.DomHelper.prototype.getElementsByTagNameAndClass;
2084
+
2085
+
2086
+ /**
2087
+ * Sets a number of properties on a node.
2088
+ * @param {Element} element DOM node to set properties on.
2089
+ * @param {Object} properties Hash of property:value pairs.
2090
+ */
2091
+ goog.dom.DomHelper.prototype.setProperties = goog.dom.setProperties;
2092
+
2093
+
2094
+ /**
2095
+ * Gets the dimensions of the viewport.
2096
+ * @param {Window=} opt_window Optional window element to test. Defaults to
2097
+ * the window of the Dom Helper.
2098
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
2099
+ */
2100
+ goog.dom.DomHelper.prototype.getViewportSize = function(opt_window) {
2101
+ // TODO(arv): This should not take an argument. That breaks the rule of a
2102
+ // a DomHelper representing a single frame/window/document.
2103
+ return goog.dom.getViewportSize(opt_window || this.getWindow());
2104
+ };
2105
+
2106
+
2107
+ /**
2108
+ * Calculates the height of the document.
2109
+ *
2110
+ * @return {number} The height of the document.
2111
+ */
2112
+ goog.dom.DomHelper.prototype.getDocumentHeight = function() {
2113
+ return goog.dom.getDocumentHeight_(this.getWindow());
2114
+ };
2115
+
2116
+
2117
+ /**
2118
+ * Typedef for use with goog.dom.createDom and goog.dom.append.
2119
+ * @typedef {Object|string|Array|NodeList}
2120
+ */
2121
+ goog.dom.Appendable;
2122
+
2123
+
2124
+ /**
2125
+ * Returns a dom node with a set of attributes. This function accepts varargs
2126
+ * for subsequent nodes to be added. Subsequent nodes will be added to the
2127
+ * first node as childNodes.
2128
+ *
2129
+ * So:
2130
+ * <code>createDom('div', null, createDom('p'), createDom('p'));</code>
2131
+ * would return a div with two child paragraphs
2132
+ *
2133
+ * An easy way to move all child nodes of an existing element to a new parent
2134
+ * element is:
2135
+ * <code>createDom('div', null, oldElement.childNodes);</code>
2136
+ * which will remove all child nodes from the old element and add them as
2137
+ * child nodes of the new DIV.
2138
+ *
2139
+ * @param {string} tagName Tag to create.
2140
+ * @param {Object|string=} opt_attributes If object, then a map of name-value
2141
+ * pairs for attributes. If a string, then this is the className of the new
2142
+ * element.
2143
+ * @param {...goog.dom.Appendable} var_args Further DOM nodes or
2144
+ * strings for text nodes. If one of the var_args is an array or
2145
+ * NodeList, its elements will be added as childNodes instead.
2146
+ * @return {!Element} Reference to a DOM node.
2147
+ */
2148
+ goog.dom.DomHelper.prototype.createDom = function(tagName,
2149
+ opt_attributes,
2150
+ var_args) {
2151
+ return goog.dom.createDom_(this.document_, arguments);
2152
+ };
2153
+
2154
+
2155
+ /**
2156
+ * Alias for {@code createDom}.
2157
+ * @param {string} tagName Tag to create.
2158
+ * @param {Object|string=} opt_attributes If object, then a map of name-value
2159
+ * pairs for attributes. If a string, then this is the className of the new
2160
+ * element.
2161
+ * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for
2162
+ * text nodes. If one of the var_args is an array, its children will be
2163
+ * added as childNodes instead.
2164
+ * @return {!Element} Reference to a DOM node.
2165
+ * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead.
2166
+ */
2167
+ goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom;
2168
+
2169
+
2170
+ /**
2171
+ * Creates a new element.
2172
+ * @param {string} name Tag name.
2173
+ * @return {!Element} The new element.
2174
+ */
2175
+ goog.dom.DomHelper.prototype.createElement = function(name) {
2176
+ return this.document_.createElement(name);
2177
+ };
2178
+
2179
+
2180
+ /**
2181
+ * Creates a new text node.
2182
+ * @param {string} content Content.
2183
+ * @return {!Text} The new text node.
2184
+ */
2185
+ goog.dom.DomHelper.prototype.createTextNode = function(content) {
2186
+ return this.document_.createTextNode(content);
2187
+ };
2188
+
2189
+
2190
+ /**
2191
+ * Create a table.
2192
+ * @param {number} rows The number of rows in the table. Must be >= 1.
2193
+ * @param {number} columns The number of columns in the table. Must be >= 1.
2194
+ * @param {boolean=} opt_fillWithNbsp If true, fills table entries with nsbps.
2195
+ * @return {!Element} The created table.
2196
+ */
2197
+ goog.dom.DomHelper.prototype.createTable = function(rows, columns,
2198
+ opt_fillWithNbsp) {
2199
+ return goog.dom.createTable_(this.document_, rows, columns,
2200
+ !!opt_fillWithNbsp);
2201
+ };
2202
+
2203
+
2204
+ /**
2205
+ * Converts an HTML string into a node or a document fragment. A single Node
2206
+ * is used if the {@code htmlString} only generates a single node. If the
2207
+ * {@code htmlString} generates multiple nodes then these are put inside a
2208
+ * {@code DocumentFragment}.
2209
+ *
2210
+ * @param {string} htmlString The HTML string to convert.
2211
+ * @return {!Node} The resulting node.
2212
+ */
2213
+ goog.dom.DomHelper.prototype.htmlToDocumentFragment = function(htmlString) {
2214
+ return goog.dom.htmlToDocumentFragment_(this.document_, htmlString);
2215
+ };
2216
+
2217
+
2218
+ /**
2219
+ * Returns the compatMode of the document.
2220
+ * @return {string} The result is either CSS1Compat or BackCompat.
2221
+ * @deprecated use goog.dom.DomHelper.prototype.isCss1CompatMode instead.
2222
+ */
2223
+ goog.dom.DomHelper.prototype.getCompatMode = function() {
2224
+ return this.isCss1CompatMode() ? 'CSS1Compat' : 'BackCompat';
2225
+ };
2226
+
2227
+
2228
+ /**
2229
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
2230
+ * mode, false otherwise.
2231
+ * @return {boolean} True if in CSS1-compatible mode.
2232
+ */
2233
+ goog.dom.DomHelper.prototype.isCss1CompatMode = function() {
2234
+ return goog.dom.isCss1CompatMode_(this.document_);
2235
+ };
2236
+
2237
+
2238
+ /**
2239
+ * Gets the window object associated with the document.
2240
+ * @return {!Window} The window associated with the given document.
2241
+ */
2242
+ goog.dom.DomHelper.prototype.getWindow = function() {
2243
+ return goog.dom.getWindow_(this.document_);
2244
+ };
2245
+
2246
+
2247
+ /**
2248
+ * Gets the document scroll element.
2249
+ * @return {Element} Scrolling element.
2250
+ */
2251
+ goog.dom.DomHelper.prototype.getDocumentScrollElement = function() {
2252
+ return goog.dom.getDocumentScrollElement_(this.document_);
2253
+ };
2254
+
2255
+
2256
+ /**
2257
+ * Gets the document scroll distance as a coordinate object.
2258
+ * @return {!goog.math.Coordinate} Object with properties 'x' and 'y'.
2259
+ */
2260
+ goog.dom.DomHelper.prototype.getDocumentScroll = function() {
2261
+ return goog.dom.getDocumentScroll_(this.document_);
2262
+ };
2263
+
2264
+
2265
+ /**
2266
+ * Appends a child to a node.
2267
+ * @param {Node} parent Parent.
2268
+ * @param {Node} child Child.
2269
+ */
2270
+ goog.dom.DomHelper.prototype.appendChild = goog.dom.appendChild;
2271
+
2272
+
2273
+ /**
2274
+ * Appends a node with text or other nodes.
2275
+ * @param {!Node} parent The node to append nodes to.
2276
+ * @param {...goog.dom.Appendable} var_args The things to append to the node.
2277
+ * If this is a Node it is appended as is.
2278
+ * If this is a string then a text node is appended.
2279
+ * If this is an array like object then fields 0 to length - 1 are appended.
2280
+ */
2281
+ goog.dom.DomHelper.prototype.append = goog.dom.append;
2282
+
2283
+
2284
+ /**
2285
+ * Removes all the child nodes on a DOM node.
2286
+ * @param {Node} node Node to remove children from.
2287
+ */
2288
+ goog.dom.DomHelper.prototype.removeChildren = goog.dom.removeChildren;
2289
+
2290
+
2291
+ /**
2292
+ * Inserts a new node before an existing reference node (i.e., as the previous
2293
+ * sibling). If the reference node has no parent, then does nothing.
2294
+ * @param {Node} newNode Node to insert.
2295
+ * @param {Node} refNode Reference node to insert before.
2296
+ */
2297
+ goog.dom.DomHelper.prototype.insertSiblingBefore = goog.dom.insertSiblingBefore;
2298
+
2299
+
2300
+ /**
2301
+ * Inserts a new node after an existing reference node (i.e., as the next
2302
+ * sibling). If the reference node has no parent, then does nothing.
2303
+ * @param {Node} newNode Node to insert.
2304
+ * @param {Node} refNode Reference node to insert after.
2305
+ */
2306
+ goog.dom.DomHelper.prototype.insertSiblingAfter = goog.dom.insertSiblingAfter;
2307
+
2308
+
2309
+ /**
2310
+ * Removes a node from its parent.
2311
+ * @param {Node} node The node to remove.
2312
+ * @return {Node} The node removed if removed; else, null.
2313
+ */
2314
+ goog.dom.DomHelper.prototype.removeNode = goog.dom.removeNode;
2315
+
2316
+
2317
+ /**
2318
+ * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no
2319
+ * parent.
2320
+ * @param {Node} newNode Node to insert.
2321
+ * @param {Node} oldNode Node to replace.
2322
+ */
2323
+ goog.dom.DomHelper.prototype.replaceNode = goog.dom.replaceNode;
2324
+
2325
+
2326
+ /**
2327
+ * Flattens an element. That is, removes it and replace it with its children.
2328
+ * @param {Element} element The element to flatten.
2329
+ * @return {Element|undefined} The original element, detached from the document
2330
+ * tree, sans children, or undefined if the element was already not in the
2331
+ * document.
2332
+ */
2333
+ goog.dom.DomHelper.prototype.flattenElement = goog.dom.flattenElement;
2334
+
2335
+
2336
+ /**
2337
+ * Returns the first child node that is an element.
2338
+ * @param {Node} node The node to get the first child element of.
2339
+ * @return {Element} The first child node of {@code node} that is an element.
2340
+ */
2341
+ goog.dom.DomHelper.prototype.getFirstElementChild =
2342
+ goog.dom.getFirstElementChild;
2343
+
2344
+
2345
+ /**
2346
+ * Returns the last child node that is an element.
2347
+ * @param {Node} node The node to get the last child element of.
2348
+ * @return {Element} The last child node of {@code node} that is an element.
2349
+ */
2350
+ goog.dom.DomHelper.prototype.getLastElementChild = goog.dom.getLastElementChild;
2351
+
2352
+
2353
+ /**
2354
+ * Returns the first next sibling that is an element.
2355
+ * @param {Node} node The node to get the next sibling element of.
2356
+ * @return {Element} The next sibling of {@code node} that is an element.
2357
+ */
2358
+ goog.dom.DomHelper.prototype.getNextElementSibling =
2359
+ goog.dom.getNextElementSibling;
2360
+
2361
+
2362
+ /**
2363
+ * Returns the first previous sibling that is an element.
2364
+ * @param {Node} node The node to get the previous sibling element of.
2365
+ * @return {Element} The first previous sibling of {@code node} that is
2366
+ * an element.
2367
+ */
2368
+ goog.dom.DomHelper.prototype.getPreviousElementSibling =
2369
+ goog.dom.getPreviousElementSibling;
2370
+
2371
+
2372
+ /**
2373
+ * Returns the next node in source order from the given node.
2374
+ * @param {Node} node The node.
2375
+ * @return {Node} The next node in the DOM tree, or null if this was the last
2376
+ * node.
2377
+ */
2378
+ goog.dom.DomHelper.prototype.getNextNode =
2379
+ goog.dom.getNextNode;
2380
+
2381
+
2382
+ /**
2383
+ * Returns the previous node in source order from the given node.
2384
+ * @param {Node} node The node.
2385
+ * @return {Node} The previous node in the DOM tree, or null if this was the
2386
+ * first node.
2387
+ */
2388
+ goog.dom.DomHelper.prototype.getPreviousNode =
2389
+ goog.dom.getPreviousNode;
2390
+
2391
+
2392
+ /**
2393
+ * Whether the object looks like a DOM node.
2394
+ * @param {*} obj The object being tested for node likeness.
2395
+ * @return {boolean} Whether the object looks like a DOM node.
2396
+ */
2397
+ goog.dom.DomHelper.prototype.isNodeLike = goog.dom.isNodeLike;
2398
+
2399
+
2400
+ /**
2401
+ * Whether a node contains another node.
2402
+ * @param {Node} parent The node that should contain the other node.
2403
+ * @param {Node} descendant The node to test presence of.
2404
+ * @return {boolean} Whether the parent node contains the descendent node.
2405
+ */
2406
+ goog.dom.DomHelper.prototype.contains = goog.dom.contains;
2407
+
2408
+
2409
+ /**
2410
+ * Returns the owner document for a node.
2411
+ * @param {Node} node The node to get the document for.
2412
+ * @return {!Document} The document owning the node.
2413
+ */
2414
+ goog.dom.DomHelper.prototype.getOwnerDocument = goog.dom.getOwnerDocument;
2415
+
2416
+
2417
+ /**
2418
+ * Cross browser function for getting the document element of an iframe.
2419
+ * @param {HTMLIFrameElement|HTMLFrameElement} iframe Iframe element.
2420
+ * @return {!HTMLDocument} The frame content document.
2421
+ */
2422
+ goog.dom.DomHelper.prototype.getFrameContentDocument =
2423
+ goog.dom.getFrameContentDocument;
2424
+
2425
+
2426
+ /**
2427
+ * Cross browser function for getting the window of a frame or iframe.
2428
+ * @param {HTMLIFrameElement|HTMLFrameElement} frame Frame element.
2429
+ * @return {Window} The window associated with the given frame.
2430
+ */
2431
+ goog.dom.DomHelper.prototype.getFrameContentWindow =
2432
+ goog.dom.getFrameContentWindow;
2433
+
2434
+
2435
+ /**
2436
+ * Cross browser function for setting the text content of an element.
2437
+ * @param {Element} element The element to change the text content of.
2438
+ * @param {string} text The string that should replace the current element
2439
+ * content with.
2440
+ */
2441
+ goog.dom.DomHelper.prototype.setTextContent = goog.dom.setTextContent;
2442
+
2443
+
2444
+ /**
2445
+ * Finds the first descendant node that matches the filter function. This does
2446
+ * a depth first search.
2447
+ * @param {Node} root The root of the tree to search.
2448
+ * @param {function(Node) : boolean} p The filter function.
2449
+ * @return {(Node, undefined)} The found node or undefined if none is found.
2450
+ */
2451
+ goog.dom.DomHelper.prototype.findNode = goog.dom.findNode;
2452
+
2453
+
2454
+ /**
2455
+ * Finds all the descendant nodes that matches the filter function. This does a
2456
+ * depth first search.
2457
+ * @param {Node} root The root of the tree to search.
2458
+ * @param {function(Node) : boolean} p The filter function.
2459
+ * @return {Array.<Node>} The found nodes or an empty array if none are found.
2460
+ */
2461
+ goog.dom.DomHelper.prototype.findNodes = goog.dom.findNodes;
2462
+
2463
+
2464
+ /**
2465
+ * Returns the text contents of the current node, without markup. New lines are
2466
+ * stripped and whitespace is collapsed, such that each character would be
2467
+ * visible.
2468
+ *
2469
+ * In browsers that support it, innerText is used. Other browsers attempt to
2470
+ * simulate it via node traversal. Line breaks are canonicalized in IE.
2471
+ *
2472
+ * @param {Node} node The node from which we are getting content.
2473
+ * @return {string} The text content.
2474
+ */
2475
+ goog.dom.DomHelper.prototype.getTextContent = goog.dom.getTextContent;
2476
+
2477
+
2478
+ /**
2479
+ * Returns the text length of the text contained in a node, without markup. This
2480
+ * is equivalent to the selection length if the node was selected, or the number
2481
+ * of cursor movements to traverse the node. Images & BRs take one space. New
2482
+ * lines are ignored.
2483
+ *
2484
+ * @param {Node} node The node whose text content length is being calculated.
2485
+ * @return {number} The length of {@code node}'s text content.
2486
+ */
2487
+ goog.dom.DomHelper.prototype.getNodeTextLength = goog.dom.getNodeTextLength;
2488
+
2489
+
2490
+ /**
2491
+ * Returns the text offset of a node relative to one of its ancestors. The text
2492
+ * length is the same as the length calculated by
2493
+ * {@code goog.dom.getNodeTextLength}.
2494
+ *
2495
+ * @param {Node} node The node whose offset is being calculated.
2496
+ * @param {Node=} opt_offsetParent Defaults to the node's owner document's body.
2497
+ * @return {number} The text offset.
2498
+ */
2499
+ goog.dom.DomHelper.prototype.getNodeTextOffset = goog.dom.getNodeTextOffset;
2500
+
2501
+
2502
+ /**
2503
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
2504
+ * tag name and/or class name. If the passed element matches the specified
2505
+ * criteria, the element itself is returned.
2506
+ * @param {Node} element The DOM node to start with.
2507
+ * @param {?string=} opt_tag The tag name to match (or null/undefined to match
2508
+ * any node regardless of tag name). Must be uppercase (goog.dom.TagName).
2509
+ * @param {?string=} opt_class The class name to match (or null/undefined to
2510
+ * match any node regardless of class name).
2511
+ * @return {Node} The first ancestor that matches the passed criteria, or
2512
+ * null if none match.
2513
+ */
2514
+ goog.dom.DomHelper.prototype.getAncestorByTagNameAndClass =
2515
+ goog.dom.getAncestorByTagNameAndClass;
2516
+
2517
+
2518
+ /**
2519
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
2520
+ * class name. If the passed element matches the specified criteria, the
2521
+ * element itself is returned.
2522
+ * @param {Node} element The DOM node to start with.
2523
+ * @param {?string=} opt_class The class name to match (or null/undefined to
2524
+ * match any node regardless of class name).
2525
+ * @return {Node} The first ancestor that matches the passed criteria, or
2526
+ * null if none match.
2527
+ */
2528
+ goog.dom.DomHelper.prototype.getAncestorByClass =
2529
+ goog.dom.getAncestorByClass;
2530
+
2531
+
2532
+ /**
2533
+ * Walks up the DOM hierarchy returning the first ancestor that passes the
2534
+ * matcher function.
2535
+ * @param {Node} element The DOM node to start with.
2536
+ * @param {function(Node) : boolean} matcher A function that returns true if the
2537
+ * passed node matches the desired criteria.
2538
+ * @param {boolean=} opt_includeNode If true, the node itself is included in
2539
+ * the search (the first call to the matcher will pass startElement as
2540
+ * the node to test).
2541
+ * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
2542
+ * dom.
2543
+ * @return {Node} DOM node that matched the matcher, or null if there was
2544
+ * no match.
2545
+ */
2546
+ goog.dom.DomHelper.prototype.getAncestor = goog.dom.getAncestor;
2547
+ ;
2548
+ FI"asset_paths;
2549
+ F["�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-031d1d0f0e50/vendor/closure-library/closure/goog/dom/dom.jsI"dependency_paths;
2550
+ F[{I" path;
2551
+ F"�/Users/ali/.rvm/gems/ruby-1.9.3-p0/bundler/gems/closure-library-wrapper-031d1d0f0e50/vendor/closure-library/closure/goog/dom/dom.jsI"
2552
+ mtime;
2553
+ FIu: Time
2554
+ T: offsetiI"hexdigest;
2555
+ F"%727ecd3542acdd7f6cf9417a0cd1b810I"
2556
+ F"%46dde6621c301f4928e3b34efee9e3b5