aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/testing/editor/testhelper.js
blob: 10f6f18970619e019a2b6e0042d0e7b8626cc90a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Class that allows for simple text editing tests.
 *
 * @author robbyw@google.com (Robby Walker)
 */

goog.provide('goog.testing.editor.TestHelper');

goog.require('goog.Disposable');
goog.require('goog.dom');
goog.require('goog.dom.Range');
goog.require('goog.editor.BrowserFeature');
goog.require('goog.editor.node');
goog.require('goog.testing.dom');


/**
 * Create a new test controller.
 * @param {Element} root The root editable element.
 * @constructor
 * @extends {goog.Disposable}
 */
goog.testing.editor.TestHelper = function(root) {
  if (!root) {
    throw Error('Null root');
  }
  goog.Disposable.call(this);

  /**
   * Convenience variable for root DOM element.
   * @type {!Element}
   * @private
   */
  this.root_ = root;

  /**
   * The starting HTML of the editable element.
   * @type {string}
   * @private
   */
  this.savedHtml_ = '';
};
goog.inherits(goog.testing.editor.TestHelper, goog.Disposable);


/**
 * Selects a new root element.
 * @param {Element} root The root editable element.
 */
goog.testing.editor.TestHelper.prototype.setRoot = function(root) {
  if (!root) {
    throw Error('Null root');
  }
  this.root_ = root;
};


/**
 * Make the root element editable.  Alse saves its HTML to be restored
 * in tearDown.
 */
goog.testing.editor.TestHelper.prototype.setUpEditableElement = function() {
  this.savedHtml_ = this.root_.innerHTML;
  if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
    this.root_.contentEditable = true;
  } else {
    this.root_.ownerDocument.designMode = 'on';
  }
  this.root_.setAttribute('g_editable', 'true');
};


/**
 * Reset the element previously initialized, restoring its HTML and making it
 * non editable.
 */
goog.testing.editor.TestHelper.prototype.tearDownEditableElement = function() {
  if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
    this.root_.contentEditable = false;
  } else {
    this.root_.ownerDocument.designMode = 'off';
  }
  goog.dom.removeChildren(this.root_);
  this.root_.innerHTML = this.savedHtml_;
  this.root_.removeAttribute('g_editable');

  if (goog.editor.plugins && goog.editor.plugins.AbstractBubblePlugin) {
    // Remove old bubbles.
    for (var key in goog.editor.plugins.AbstractBubblePlugin.bubbleMap_) {
      goog.editor.plugins.AbstractBubblePlugin.bubbleMap_[key].dispose();
    }
    // Ensure we get a new bubble for each test.
    goog.editor.plugins.AbstractBubblePlugin.bubbleMap_ = {};
  }
};


/**
 * Assert that the html in 'root' is substantially similar to htmlPattern.
 * This method tests for the same set of styles, and for the same order of
 * nodes.  Breaking whitespace nodes are ignored.  Elements can be annotated
 * with classnames corresponding to keys in goog.userAgent and will be
 * expected to show up in that user agent and expected not to show up in
 * others.
 * @param {string} htmlPattern The pattern to match.
 */
goog.testing.editor.TestHelper.prototype.assertHtmlMatches = function(
    htmlPattern) {
  goog.testing.dom.assertHtmlContentsMatch(htmlPattern, this.root_);
};


/**
 * Finds the first text node descendant of root with the given content.
 * @param {string|RegExp} textOrRegexp The text to find, or a regular
 *     expression to find a match of.
 * @return {Node} The first text node that matches, or null if none is found.
 */
goog.testing.editor.TestHelper.prototype.findTextNode = function(textOrRegexp) {
  return goog.testing.dom.findTextNode(textOrRegexp, this.root_);
};


/**
 * Select from the given from offset in the given from node to the given
 * to offset in the optionally given to node. If nodes are passed in, uses them,
 * otherwise uses findTextNode to find the nodes to select. Selects a caret
 * if opt_to and opt_toOffset are not given.
 * @param {Node|string} from Node or text of the node to start the selection at.
 * @param {number} fromOffset Offset within the above node to start the
 *     selection at.
 * @param {Node|string=} opt_to Node or text of the node to end the selection
 *     at.
 * @param {number=} opt_toOffset Offset within the above node to end the
 *     selection at.
 */
goog.testing.editor.TestHelper.prototype.select = function(from, fromOffset,
    opt_to, opt_toOffset) {
  var end;
  var start = end = goog.isString(from) ? this.findTextNode(from) : from;
  var endOffset;
  var startOffset = endOffset = fromOffset;

  if (opt_to && goog.isNumber(opt_toOffset)) {
    end = goog.isString(opt_to) ? this.findTextNode(opt_to) : opt_to;
    endOffset = opt_toOffset;
  }

  goog.dom.Range.createFromNodes(start, startOffset, end, endOffset).select();
};


/** @override */
goog.testing.editor.TestHelper.prototype.disposeInternal = function() {
  if (goog.editor.node.isEditableContainer(this.root_)) {
    this.tearDownEditableElement();
  }
  delete this.root_;
  goog.base(this, 'disposeInternal');
};