wysihtml5_with_ps 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ module("wysihtml5.dom.renameElement", {
2
+ equal: function(actual, expected, message) {
3
+ return wysihtml5.assert.htmlEqual(actual, expected, message);
4
+ },
5
+
6
+ renameElement: function(html, newNodeName) {
7
+ var container = wysihtml5.dom.getAsDom(html);
8
+ wysihtml5.dom.renameElement(container.firstChild, newNodeName);
9
+ return container.innerHTML;
10
+ }
11
+ });
12
+
13
+ test("Basic tests", function() {
14
+ this.equal(
15
+ this.renameElement("<p>foo</p>", "div"),
16
+ "<div>foo</div>"
17
+ );
18
+
19
+ this.equal(
20
+ this.renameElement("<ul><li>foo</li></ul>", "ol"),
21
+ "<ol><li>foo</li></ol>"
22
+ );
23
+
24
+ this.equal(
25
+ this.renameElement('<p align="left" class="foo"></p>', "h2"),
26
+ '<h2 align="left" class="foo"></h2>'
27
+ );
28
+ });
@@ -0,0 +1,46 @@
1
+ module("wysihtml5.dom.resolveList", {
2
+ equal: function(actual, expected, message) {
3
+ return wysihtml5.assert.htmlEqual(actual, expected, message);
4
+ },
5
+
6
+ resolveList: function(html) {
7
+ var container = wysihtml5.dom.getAsDom(html);
8
+ document.body.appendChild(container);
9
+ wysihtml5.dom.resolveList(container.firstChild);
10
+ var innerHTML = container.innerHTML;
11
+ container.parentNode.removeChild(container);
12
+ return innerHTML;
13
+ }
14
+ });
15
+
16
+ test("Basic tests", function() {
17
+ this.equal(
18
+ this.resolveList("<ul><li>foo</li></ul>"),
19
+ "foo<br>"
20
+ );
21
+
22
+ this.equal(
23
+ this.resolveList("<ul><li>foo</li><li>bar</li></ul>"),
24
+ "foo<br>bar<br>"
25
+ );
26
+
27
+ this.equal(
28
+ this.resolveList("<ol><li>foo</li><li>bar</li></ol>"),
29
+ "foo<br>bar<br>"
30
+ );
31
+
32
+ this.equal(
33
+ this.resolveList("<ol><li></li><li>bar</li></ol>"),
34
+ "bar<br>"
35
+ );
36
+
37
+ this.equal(
38
+ this.resolveList("<ol><li>foo<br></li><li>bar</li></ol>"),
39
+ "foo<br>bar<br>"
40
+ );
41
+
42
+ this.equal(
43
+ this.resolveList("<ul><li><h1>foo</h1></li><li><div>bar</div></li><li>baz</li></ul>"),
44
+ "<h1>foo</h1><div>bar</div>baz<br>"
45
+ );
46
+ });
@@ -0,0 +1,184 @@
1
+ module("wysihtml5.dom.Sandbox", {
2
+ teardown: function() {
3
+ var iframe;
4
+ while (iframe = document.querySelector("iframe.wysihtml5-sandbox")) {
5
+ iframe.parentNode.removeChild(iframe);
6
+ }
7
+ },
8
+
9
+ getCharset: function(doc) {
10
+ var charset = doc.characterSet || doc.charset;
11
+ if (/unicode|utf-8/.test(charset)) {
12
+ return "utf-8";
13
+ }
14
+ return charset;
15
+ },
16
+
17
+ eval: function(iframeWindow, code) {
18
+ try {
19
+ return iframeWindow.execScript ? iframeWindow.execScript(code) : iframeWindow.eval(code);
20
+ } catch(e) {
21
+ return null;
22
+ }
23
+ },
24
+
25
+ isUnset: function(evalCode, iframeWindow) {
26
+ var value = this.eval(iframeWindow, evalCode);
27
+ return !value || value == wysihtml5.EMPTY_FUNCTION;
28
+ }
29
+ });
30
+
31
+
32
+ asyncTest("Basic Test", function() {
33
+ expect(8);
34
+
35
+ var sandbox = new wysihtml5.dom.Sandbox(function(param) {
36
+ equal(param, sandbox, "The parameter passed into the readyCallback is the sandbox instance");
37
+
38
+ var iframes = document.querySelectorAll("iframe.wysihtml5-sandbox");
39
+ equal(iframes.length, 1, "iFrame sandbox inserted into dom tree");
40
+
41
+ var iframe = iframes[iframes.length - 1],
42
+ isIframeInvisible = iframe.width == 0 && iframe.height == 0 && iframe.frameBorder == 0;
43
+ ok(isIframeInvisible, "iframe is not visible");
44
+
45
+ var isSandboxed = iframe.getAttribute("security") == "restricted";
46
+ ok(isSandboxed, "iFrame is sandboxed");
47
+
48
+ var isWindowObject = sandbox.getWindow().setInterval && sandbox.getWindow().clearInterval;
49
+ ok(isWindowObject, "wysihtml5.Sandbox.prototype.getWindow() works properly");
50
+
51
+ var isDocumentObject = sandbox.getDocument().appendChild && sandbox.getDocument().body;
52
+ ok(isDocumentObject, "wysihtml5.Sandbox.prototype.getDocument() works properly");
53
+
54
+ equal(sandbox.getIframe(), iframe, "wysihtml5.Sandbox.prototype.getIframe() returns the iframe correctly");
55
+ equal(typeof(sandbox.getWindow().onerror), "function", "window.onerror is set");
56
+
57
+ start();
58
+ });
59
+
60
+ sandbox.insertInto(document.body);
61
+ });
62
+
63
+
64
+ asyncTest("Security test #1", function() {
65
+ expect(14);
66
+
67
+ var that = this;
68
+
69
+ var sandbox = new wysihtml5.dom.Sandbox(function() {
70
+ var iframeWindow = sandbox.getWindow();
71
+
72
+ var isSafari = wysihtml5.browser.USER_AGENT.indexOf("Safari") !== -1 && wysihtml5.browser.USER_AGENT.indexOf("Chrome") === 1;
73
+
74
+ if (isSafari) {
75
+ // This test fails in Safari 5, as it's impossible to unset a cookie there
76
+ ok(true, "Cookie is NOT unset (but that's expected in Safari)");
77
+ } else {
78
+ ok(that.isUnset("document.cookie", iframeWindow), "Cookie is unset");
79
+ }
80
+
81
+ ok(that.isUnset("document.open", iframeWindow), "document.open is unset");
82
+ ok(that.isUnset("document.write", iframeWindow), "document.write is unset");
83
+ ok(that.isUnset("window.parent", iframeWindow), "window.parent is unset");
84
+ ok(that.isUnset("window.opener", iframeWindow), "window.opener is unset");
85
+ ok(that.isUnset("window.localStorage", iframeWindow), "localStorage is unset");
86
+ ok(that.isUnset("window.globalStorage", iframeWindow), "globalStorage is unset");
87
+ ok(that.isUnset("window.XMLHttpRequest", iframeWindow), "XMLHttpRequest is an empty function");
88
+ ok(that.isUnset("window.XDomainRequest", iframeWindow), "XDomainRequest is an empty function");
89
+ ok(that.isUnset("window.alert", iframeWindow), "alert is an empty function");
90
+ ok(that.isUnset("window.prompt", iframeWindow), "prompt is an empty function");
91
+ ok(that.isUnset("window.openDatabase", iframeWindow), "window.openDatabase is unset");
92
+ ok(that.isUnset("window.indexedDB", iframeWindow), "window.indexedDB is unset");
93
+ ok(that.isUnset("window.postMessage", iframeWindow), "window.openDatabase is unset");
94
+
95
+ start();
96
+ });
97
+
98
+ sandbox.insertInto(document.body);
99
+ });
100
+
101
+
102
+ asyncTest("Security test #2", function() {
103
+ expect(2);
104
+
105
+ var sandbox = new wysihtml5.dom.Sandbox(function() {
106
+ var html = '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" onerror="#{script}" onload="try { window.parent._hackedCookie=document.cookie; } catch(e){}; try { window.parent._hackedVariable=1; } catch(e) {}">';
107
+ sandbox.getDocument().body.innerHTML = html;
108
+
109
+ setTimeout(function() {
110
+ equal(window._hackedCookie || "", "", "Cookie can't be easily stolen");
111
+ equal(window._hackedVariable || 0, 0, "iFrame has no access to parent");
112
+
113
+ start();
114
+ }, 2000);
115
+ });
116
+
117
+ sandbox.insertInto(document.body);
118
+ });
119
+
120
+
121
+ asyncTest("Check charset & doctype", function() {
122
+ expect(3);
123
+
124
+ var that = this;
125
+
126
+ var sandbox = new wysihtml5.dom.Sandbox(function() {
127
+ var iframeDocument = sandbox.getDocument(),
128
+ isQuirksMode = iframeDocument.compatMode == "BackCompat";
129
+
130
+ ok(!isQuirksMode, "iFrame isn't in quirks mode");
131
+ equal(that.getCharset(iframeDocument), that.getCharset(document), "Charset correctly inherited by iframe");
132
+
133
+ iframeDocument.body.innerHTML = '<meta charset="iso-8859-1">&uuml;';
134
+
135
+ setTimeout(function() {
136
+ equal(that.getCharset(iframeDocument), that.getCharset(document), "Charset isn't overwritten");
137
+ start();
138
+ }, 500);
139
+ });
140
+
141
+ sandbox.insertInto(document.body);
142
+ });
143
+
144
+
145
+ asyncTest("Check insertion of single stylesheet", function() {
146
+ expect(1);
147
+
148
+ new wysihtml5.dom.Sandbox(function(sandbox) {
149
+ var doc = sandbox.getDocument();
150
+ equal(doc.getElementsByTagName("link").length, 1, "Correct amount of stylesheets inserted into the dom tree");
151
+ start();
152
+ }, {
153
+ stylesheets: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/blitzer/jquery-ui.css"
154
+ }).insertInto(document.body);
155
+ });
156
+
157
+
158
+ asyncTest("Check insertion of multiple stylesheets", function() {
159
+ expect(1);
160
+
161
+ new wysihtml5.dom.Sandbox(function(sandbox) {
162
+ var doc = sandbox.getDocument();
163
+ equal(doc.getElementsByTagName("link").length, 2, "Correct amount of stylesheets inserted into the dom tree");
164
+ start();
165
+ }, {
166
+ stylesheets: [
167
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/blitzer/jquery-ui.css",
168
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/excite-bike/jquery-ui.css"
169
+ ]
170
+ }).insertInto(document.body);
171
+ });
172
+
173
+
174
+ asyncTest("Check X-UA-Compatible", function() {
175
+ expect(1);
176
+
177
+ new wysihtml5.dom.Sandbox(function(sandbox) {
178
+ var doc = sandbox.getDocument(),
179
+ docMode = doc.documentMode;
180
+
181
+ ok(doc.documentMode === document.documentMode, "iFrame is in in the same document mode as the parent site");
182
+ start();
183
+ }).insertInto(document.body);
184
+ });
@@ -0,0 +1,15 @@
1
+ module("wysihtml5.dom.setAttributes", {
2
+ setup: function() {
3
+ this.element = document.createElement("div");
4
+ }
5
+ });
6
+
7
+ test("Basic test", function() {
8
+ wysihtml5.dom.setAttributes({
9
+ id: "foo",
10
+ "class": "bar"
11
+ }).on(this.element);
12
+
13
+ equal(this.element.id, "foo");
14
+ equal(this.element.className, "bar");
15
+ });
@@ -0,0 +1,19 @@
1
+ module("wysihtml5.dom.setStyles", {
2
+ setup: function() {
3
+ this.element = document.createElement("div");
4
+ document.body.appendChild(this.element);
5
+ },
6
+
7
+ teardown: function() {
8
+ this.element.parentNode.removeChild(this.element);
9
+ }
10
+ });
11
+
12
+ test("Basic test", function() {
13
+ wysihtml5.dom.setStyles("text-align: right; float: left").on(this.element);
14
+ equal(wysihtml5.dom.getStyle("text-align").from(this.element), "right");
15
+ equal(wysihtml5.dom.getStyle("float").from(this.element), "left");
16
+
17
+ wysihtml5.dom.setStyles({ "float": "right" }).on(this.element);
18
+ equal(wysihtml5.dom.getStyle("float").from(this.element), "right");
19
+ });
@@ -0,0 +1,547 @@
1
+ if (wysihtml5.browser.supported()) {
2
+ module("wysihtml5.Editor", {
3
+ setup: function() {
4
+ wysihtml5.dom.insertCSS([
5
+ "#wysihtml5-test-textarea { width: 50%; height: 100px; margin-top: 5px; font-style: italic; border: 2px solid red; border-radius: 2px; }",
6
+ "#wysihtml5-test-textarea:focus { margin-top: 10px; }",
7
+ "#wysihtml5-test-textarea:disabled { margin-top: 20px; }"
8
+ ]).into(document);
9
+
10
+ this.textareaElement = document.createElement("textarea");
11
+ this.textareaElement.id = "wysihtml5-test-textarea";
12
+ this.textareaElement.title = "Please enter your foo";
13
+ this.textareaElement.value = "hey tiff, what's up?";
14
+
15
+ this.form = document.createElement("form");
16
+ this.form.onsubmit = function() { return false; };
17
+ this.form.appendChild(this.textareaElement);
18
+
19
+ this.originalBodyClassName = document.body.className;
20
+
21
+ document.body.appendChild(this.form);
22
+ },
23
+
24
+ teardown: function() {
25
+ var leftover;
26
+ while (leftover = document.querySelector("iframe.wysihtml5-sandbox, input[name='_wysihtml5_mode']")) {
27
+ leftover.parentNode.removeChild(leftover);
28
+ }
29
+ this.form.parentNode.removeChild(this.form);
30
+ document.body.className = this.originalBodyClassName;
31
+ },
32
+
33
+ getComposerElement: function() {
34
+ return this.getIframeElement().contentWindow.document.body;
35
+ },
36
+
37
+ getIframeElement: function() {
38
+ var iframes = document.querySelectorAll("iframe.wysihtml5-sandbox");
39
+ return iframes[iframes.length - 1];
40
+ }
41
+ });
42
+
43
+ asyncTest("Basic test", function() {
44
+ expect(18);
45
+
46
+ var that = this;
47
+
48
+ var editor = new wysihtml5.Editor(this.textareaElement);
49
+ editor.observe("load", function() {
50
+ var iframeElement = that.getIframeElement(),
51
+ composerElement = that.getComposerElement(),
52
+ textareaElement = that.textareaElement;
53
+ ok(true, "Load callback triggered");
54
+ ok(wysihtml5.dom.hasClass(document.body, "wysihtml5-supported"), "<body> received correct class name");
55
+ equal(textareaElement.style.display, "none", "Textarea not visible");
56
+ ok(iframeElement.style.display, "", "Editor iFrame is visible");
57
+ equal(editor.currentView.name, "composer", "Current view is 'composer'");
58
+
59
+ // Make textarea visible for a short amount of time, in order to calculate dimensions properly
60
+ textareaElement.style.display = "block";
61
+ deepEqual(
62
+ [iframeElement.offsetHeight, iframeElement.offsetWidth],
63
+ [textareaElement.offsetHeight, textareaElement.offsetWidth],
64
+ "Editor has the same dimensions as the original textarea"
65
+ );
66
+ textareaElement.style.display = "none";
67
+
68
+ var hiddenField = textareaElement.nextSibling;
69
+ equal(hiddenField.name, "_wysihtml5_mode", "Hidden field has correct name");
70
+ equal(hiddenField.value, "1", "Hidden field has correct value");
71
+ equal(hiddenField.type, "hidden", "Hidden field is actually hidden");
72
+ equal(textareaElement.nextSibling.nextSibling, iframeElement, "Editor iframe is inserted after the textarea");
73
+ equal(composerElement.getAttribute("contentEditable"), "true", "Body element in iframe is editable");
74
+ equal(editor.textarea.element, textareaElement, "Textarea correctly available on editor instance");
75
+ equal(editor.composer.element, composerElement, "contentEditable element available on editor instance");
76
+ equal(wysihtml5.dom.getStyle("font-style").from(composerElement), "italic", "Correct font-style applied to editor element");
77
+ equal(wysihtml5.dom.getStyle("width").from(iframeElement), "50%", "Correct width applied to iframe")
78
+ equal(wysihtml5.dom.getStyle("height").from(iframeElement), "100px", "Correct height applied to iframe")
79
+
80
+ if ("borderRadius" in document.createElement("div").style) {
81
+ expect(19);
82
+ ok(wysihtml5.dom.getStyle("border-top-right-radius").from(iframeElement).indexOf("2px") !== -1, "border-radius correctly copied");
83
+ }
84
+
85
+ equal(composerElement.innerHTML.toLowerCase(), "hey tiff, what's up?", "Copied the initial textarea value to the editor");
86
+ ok(wysihtml5.dom.hasClass(composerElement, "wysihtml5-editor"), "Editor element has correct class name");
87
+
88
+ start();
89
+ });
90
+ });
91
+
92
+
93
+ asyncTest("Check setting of name as class name on iframe and iframe's body", function() {
94
+ expect(4);
95
+
96
+ this.textareaElement.className = "death-star";
97
+
98
+ var that = this,
99
+ name = "star-wars-input",
100
+ editor = new wysihtml5.Editor(this.textareaElement, { name: "star-wars-input" });
101
+
102
+ editor.observe("load", function() {
103
+ var iframeElement = that.getIframeElement(),
104
+ composerElement = that.getComposerElement(),
105
+ textareaElement = that.textareaElement;
106
+ ok(wysihtml5.dom.hasClass(iframeElement, name), "iFrame has adopted name as className");
107
+ ok(wysihtml5.dom.hasClass(composerElement, name), "iFrame's body has adopted name as className");
108
+ ok(wysihtml5.dom.hasClass(composerElement, "death-star"), "iFrame's body has adopted the textarea className");
109
+ ok(!wysihtml5.dom.hasClass(textareaElement, name), "Textarea has not adopted name as className");
110
+ start();
111
+ });
112
+ });
113
+
114
+
115
+ asyncTest("Check textarea with box-sizing: border-box;", function() {
116
+ expect(1);
117
+
118
+ var that = this;
119
+
120
+ wysihtml5.dom.setStyles({
121
+ MozBoxSizing: "border-box",
122
+ WebkitBoxSizing: "border-box",
123
+ MsBoxSizing: "border-box",
124
+ boxSizing: "border-box"
125
+ }).on(this.textareaElement);
126
+
127
+ var editor = new wysihtml5.Editor(this.textareaElement);
128
+ editor.observe("load", function() {
129
+ // Make textarea visible for a short amount of time, in order to calculate dimensions properly
130
+ that.textareaElement.style.display = "block";
131
+ deepEqual(
132
+ [that.getIframeElement().offsetWidth, that.getIframeElement().offsetHeight],
133
+ [that.textareaElement.offsetWidth, that.textareaElement.offsetHeight],
134
+ "Editor has the same dimensions as the original textarea"
135
+ );
136
+ that.textareaElement.style.display = "none";
137
+
138
+ start();
139
+ });
140
+ });
141
+
142
+
143
+ asyncTest("Check whether attributes are copied", function() {
144
+ expect(1);
145
+
146
+ var that = this;
147
+
148
+ var editor = new wysihtml5.Editor(this.textareaElement);
149
+ editor.observe("load", function() {
150
+ equal(that.getComposerElement().title, that.textareaElement.title, "Editor got attributes copied over from textarea");
151
+ start();
152
+ });
153
+ });
154
+
155
+
156
+ asyncTest("Check events", function() {
157
+ expect(8);
158
+
159
+ var that = this;
160
+
161
+ var editor = new wysihtml5.Editor(this.textareaElement);
162
+
163
+ editor.observe("beforeload", function() {
164
+ ok(true, "'beforeload' event correctly fired");
165
+ });
166
+
167
+ editor.observe("load", function() {
168
+ var composerElement = that.getComposerElement(),
169
+ iframeElement = that.getIframeElement();
170
+
171
+ editor.observe("focus", function() {
172
+ ok(true, "'focus' event correctly fired");
173
+ });
174
+
175
+ editor.observe("blur", function() {
176
+ ok(true, "'blur' event correctly fired");
177
+ });
178
+
179
+ editor.observe("change", function() {
180
+ ok(true, "'change' event correctly fired");
181
+ });
182
+
183
+ editor.observe("paste", function() {
184
+ ok(true, "'paste' event correctly fired");
185
+ });
186
+
187
+ editor.observe("drop", function() {
188
+ ok(true, "'drop' event correctly fired");
189
+ });
190
+
191
+ editor.observe("custom_event", function() {
192
+ ok(true, "'custom_event' correctly fired");
193
+ });
194
+
195
+ QUnit.triggerEvent(composerElement, "focus");
196
+ editor.stopObserving("focus");
197
+
198
+ // Modify innerHTML in order to force 'change' event to trigger onblur
199
+ composerElement.innerHTML = "foobar";
200
+ QUnit.triggerEvent(composerElement, "blur");
201
+ QUnit.triggerEvent(composerElement, "focusout");
202
+ equal(wysihtml5.dom.getStyle("margin-top").from(iframeElement), "5px", ":focus styles are correctly unset");
203
+ QUnit.triggerEvent(composerElement, "paste");
204
+ QUnit.triggerEvent(composerElement, "drop");
205
+
206
+ editor.fire("custom_event");
207
+
208
+ // Delay teardown in order to avoid unwanted js errors caused by a too early removed sandbox iframe
209
+ // which then causes js errors in Safari 5
210
+ setTimeout(function() { start(); }, 100);
211
+ });
212
+ });
213
+
214
+
215
+ asyncTest("Check sync (basic)", function() {
216
+ expect(1);
217
+
218
+ var that = this;
219
+
220
+ var editor = new wysihtml5.Editor(this.textareaElement);
221
+ editor.observe("load", function() {
222
+ var html = "<p>hello foobar, what up?</p>";
223
+ that.getComposerElement().innerHTML = html;
224
+
225
+ setTimeout(function() {
226
+ equal(that.textareaElement.value.toLowerCase(), html.toLowerCase(), "Editor content got correctly copied over to original textarea");
227
+ start();
228
+ }, 500);
229
+ });
230
+ });
231
+
232
+
233
+ asyncTest("Check sync (advanced)", function() {
234
+ expect(5);
235
+
236
+ var that = this;
237
+
238
+ var editor = new wysihtml5.Editor(this.textareaElement, {
239
+ parserRules: { tags: { "strong": true } }
240
+ });
241
+
242
+ editor.observe("load", function() {
243
+ var html = "<strong>timmay!</strong>",
244
+ composerElement = that.getComposerElement();
245
+ composerElement.innerHTML = html;
246
+
247
+ setTimeout(function() {
248
+ equal(that.textareaElement.value.toLowerCase(), html.toLowerCase(), "Editor content got correctly copied over to original textarea");
249
+
250
+ composerElement.innerHTML = "<font color=\"red\">hey </font><strong>helen!</strong>";
251
+ editor.fire("change_view", "textarea");
252
+ equal(that.textareaElement.value.toLowerCase(), "hey <strong>helen!</strong>", "Editor got immediately copied over to textarea after switching the view");
253
+
254
+ that.textareaElement.value = "<i>hey </i><strong>richard!</strong>";
255
+ editor.fire("change_view", "composer");
256
+ equal(composerElement.innerHTML.toLowerCase(), "hey <strong>richard!</strong>", "Textarea sanitized and copied over it's value to the editor after switch");
257
+
258
+ composerElement.innerHTML = "<i>hey </i><strong>timmay!</strong>";
259
+ QUnit.triggerEvent(that.form, "submit");
260
+ equal(that.textareaElement.value.toLowerCase(), "hey <strong>timmay!</strong>", "Textarea gets the sanitized content of the editor onsubmit");
261
+
262
+ setTimeout(function() {
263
+ that.form.reset();
264
+
265
+ // Timeout needed since reset() isn't executed synchronously
266
+ setTimeout(function() {
267
+ equal(wysihtml5.dom.getTextContent(composerElement), "", "Editor is empty after reset");
268
+ start();
269
+ }, 100);
270
+
271
+ }, 500);
272
+
273
+ }, 500);
274
+
275
+ });
276
+ });
277
+
278
+
279
+ asyncTest("Check placeholder", function() {
280
+ expect(13);
281
+
282
+ var that = this;
283
+
284
+ var placeholderText = "enter text ...";
285
+ this.textareaElement.value = "";
286
+ this.textareaElement.setAttribute("placeholder", "enter text ...");
287
+
288
+ var editor = new wysihtml5.Editor(this.textareaElement);
289
+ editor.observe("load", function() {
290
+ var composerElement = that.getComposerElement();
291
+ equal(wysihtml5.dom.getTextContent(composerElement), placeholderText, "Placeholder text correctly copied into textarea");
292
+ ok(wysihtml5.dom.hasClass(composerElement, "placeholder"), "Editor got 'placeholder' css class");
293
+ ok(editor.hasPlaceholderSet(), "'hasPlaceholderSet' returns correct value when placeholder is actually set");
294
+ editor.fire("focus:composer");
295
+ equal(wysihtml5.dom.getTextContent(composerElement), "", "Editor is empty after focus");
296
+ ok(!wysihtml5.dom.hasClass(composerElement, "placeholder"), "Editor hasn't got 'placeholder' css class");
297
+ ok(!editor.hasPlaceholderSet(), "'hasPlaceholderSet' returns correct value when placeholder isn't actually set");
298
+ editor.fire("blur:composer");
299
+ equal(wysihtml5.dom.getTextContent(composerElement), placeholderText, "Editor restored placeholder text after unfocus");
300
+ editor.fire("focus:composer");
301
+ equal(wysihtml5.dom.getTextContent(composerElement), "");
302
+ composerElement.innerHTML = "some content";
303
+ editor.fire("blur:composer");
304
+ equal(wysihtml5.dom.getTextContent(composerElement), "some content");
305
+ ok(!wysihtml5.dom.hasClass(composerElement, "placeholder"), "Editor hasn't got 'placeholder' css class");
306
+ editor.fire("focus:composer");
307
+ // Following html causes innerText and textContent to report an empty string
308
+ var html = '<img>';
309
+ composerElement.innerHTML = html;
310
+ editor.fire("blur:composer");
311
+ equal(composerElement.innerHTML.toLowerCase(), html, "HTML hasn't been cleared even though the innerText and textContent properties indicate empty content.");
312
+ ok(!wysihtml5.dom.hasClass(composerElement, "placeholder"), "Editor hasn't got 'placeholder' css class");
313
+
314
+ setTimeout(function() {
315
+ that.form.reset();
316
+
317
+ // Timeout needed since reset() isn't executed synchronously
318
+ setTimeout(function() {
319
+ equal(wysihtml5.dom.getTextContent(composerElement), placeholderText, "After form reset the editor has the placeholder as content");
320
+ start();
321
+ }, 100);
322
+
323
+ }, 500);
324
+ });
325
+ });
326
+
327
+
328
+ asyncTest("Check public api", function() {
329
+ expect(13);
330
+
331
+ var that = this;
332
+
333
+ var editor = new wysihtml5.Editor(this.textareaElement, {
334
+ parserRules: { tags: { p: { rename_tag: "div" } } },
335
+ bodyClassName: "editor-is-supported",
336
+ composerClassName: "editor"
337
+ });
338
+
339
+ editor.observe("load", function() {
340
+ ok(editor.isCompatible(), "isCompatible() returns correct value");
341
+ ok(wysihtml5.dom.hasClass(document.body, "editor-is-supported"), "<body> received correct class name");
342
+
343
+ var composerElement = that.getComposerElement();
344
+ editor.clear();
345
+ equal(wysihtml5.dom.getTextContent(composerElement), "", "Editor empty after calling 'clear'");
346
+ ok(wysihtml5.dom.hasClass(composerElement, "editor"), "Composer element has correct class name");
347
+
348
+ var html = "hello <strong>foo</strong>!";
349
+ editor.setValue(html);
350
+ equal(composerElement.innerHTML.toLowerCase(), html, "Editor content correctly set after calling 'setValue'");
351
+ ok(!editor.isEmpty(), "'isEmpty' returns correct value when the composer element isn't actually empty");
352
+
353
+ var value = editor.getValue();
354
+ equal(value.toLowerCase(), html, "Editor content correctly returned after calling 'getValue'");
355
+
356
+ editor.clear();
357
+ value = editor.getValue();
358
+ equal(value, "");
359
+ ok(editor.isEmpty(), "'isEmpty' returns correct value when the composer element is actually empty");
360
+
361
+ equal(editor.parse("<p>foo</p>").toLowerCase(), "<div>foo</div>", "'parse' returns correct value");
362
+
363
+ // Check disable/enable
364
+ editor.disable();
365
+ ok(!composerElement.getAttribute("contentEditable"), "When disabled the composer hasn't the contentEditable attribute");
366
+
367
+ editor.enable();
368
+ equal(composerElement.getAttribute("contentEditable"), "true", "After enabling the editor the contentEditable property is true");
369
+ ok(!composerElement.getAttribute("disabled"), "After enabling the disabled attribute is unset");
370
+
371
+ start();
372
+ });
373
+ });
374
+
375
+
376
+ asyncTest("Parser (default parser method with parserRules as object", function() {
377
+ expect(2);
378
+
379
+ var parserRules = {
380
+ tags: {
381
+ div: true,
382
+ p: { rename_tag: "div" },
383
+ span: true,
384
+ script: undefined
385
+ }
386
+ };
387
+
388
+ var input = "<p>foobar</p>",
389
+ output = "<div>foobar</div>";
390
+
391
+ var editor = new wysihtml5.Editor(this.textareaElement, {
392
+ parserRules: parserRules
393
+ });
394
+
395
+ editor.observe("load", function() {
396
+ equal(editor.config.parserRules, parserRules, "Parser rules correctly set on config object");
397
+ // Invoke parsing via second parameter of setValue()
398
+ editor.setValue(input, true);
399
+ equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
400
+ start();
401
+ });
402
+ });
403
+
404
+
405
+ asyncTest("Parser (custom parser method with parserRules as object", function() {
406
+ expect(7);
407
+
408
+ var that = this,
409
+ parserRules = { script: undefined },
410
+ input = this.textareaElement.value,
411
+ output = input;
412
+
413
+ var editor = new wysihtml5.Editor(this.textareaElement, {
414
+ parserRules: parserRules,
415
+ parser: function(html, rules, context) {
416
+ equal(html.toLowerCase(), input, "HTML passed into parser is equal to the one which just got inserted");
417
+ equal(rules, parserRules, "Rules passed into parser are equal to those given to the editor");
418
+ equal(context, that.getIframeElement().contentWindow.document, "Context passed into parser is equal the document object of the editor's iframe");
419
+ return html.replace(/\<script\>.*?\<\/script\>/gi, "");
420
+ }
421
+ });
422
+
423
+ editor.observe("load", function() {
424
+ input = "<p>foobar</p><script>alert(1);</script>";
425
+ output = "<p>foobar</p>";
426
+
427
+ // Invoke parsing via second parameter of setValue()
428
+ editor.setValue(input, true);
429
+ equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
430
+
431
+ start();
432
+ });
433
+ });
434
+
435
+
436
+ asyncTest("Inserting an element which causes the textContent/innerText of the contentEditable element to be empty works correctly", function() {
437
+ expect(2);
438
+
439
+ var that = this;
440
+
441
+ var editor = new wysihtml5.Editor(this.textareaElement);
442
+ editor.observe("load", function() {
443
+ var html = '<img>',
444
+ composerElement = that.getComposerElement(),
445
+ textareaElement = that.textareaElement;
446
+ composerElement.innerHTML = html;
447
+
448
+ // Fire events that could cause a change in the composer
449
+ QUnit.triggerEvent(composerElement, "keypress");
450
+ QUnit.triggerEvent(composerElement, "keyup");
451
+ QUnit.triggerEvent(composerElement, "cut");
452
+ QUnit.triggerEvent(composerElement, "blur");
453
+
454
+ setTimeout(function() {
455
+ equal(composerElement.innerHTML.toLowerCase(), html, "Composer still has correct content");
456
+ equal(textareaElement.value.toLowerCase(), html, "Textarea got correct value");
457
+ start();
458
+ }, 500);
459
+ });
460
+ });
461
+
462
+
463
+ asyncTest("Check for stylesheets", function() {
464
+ expect(5);
465
+
466
+ var that = this;
467
+
468
+ var stylesheetUrls = [
469
+ "http://yui.yahooapis.com/2.8.2r1/build/reset/reset-min.css",
470
+ "http://yui.yahooapis.com/2.8.0/build/reset/reset-min.css"
471
+ ];
472
+
473
+ var editor = new wysihtml5.Editor(this.textareaElement, {
474
+ stylesheets: stylesheetUrls
475
+ });
476
+
477
+ editor.observe("load", function() {
478
+ var iframeElement = that.getIframeElement(),
479
+ iframeDoc = iframeElement.contentWindow.document,
480
+ linkElements = iframeDoc.getElementsByTagName("link");
481
+ equal(linkElements.length, 2, "Correct amount of stylesheets inserted into the dom tree");
482
+ equal(linkElements[0].getAttribute("href"), stylesheetUrls[0]);
483
+ equal(linkElements[0].getAttribute("rel"), "stylesheet");
484
+ equal(linkElements[1].getAttribute("href"), stylesheetUrls[1]);
485
+ equal(linkElements[1].getAttribute("rel"), "stylesheet");
486
+ start();
487
+ });
488
+ });
489
+
490
+
491
+ asyncTest("Check config.supportTouchDevices = false", function() {
492
+ expect(2);
493
+
494
+ var that = this;
495
+
496
+ var originalIsTouchDevice = wysihtml5.browser.isTouchDevice;
497
+ wysihtml5.browser.isTouchDevice = function() { return true; };
498
+
499
+ var editor = new wysihtml5.Editor(this.textareaElement, {
500
+ supportTouchDevices: false
501
+ });
502
+
503
+ editor.observe("load", function() {
504
+ ok(!that.getIframeElement(), "No editor iframe has been inserted");
505
+ equal(that.textareaElement.style.display, "", "Textarea is visible");
506
+
507
+ wysihtml5.browser.isTouchDevice = originalIsTouchDevice;
508
+
509
+ start();
510
+ });
511
+ });
512
+
513
+ asyncTest("Check whether everything works when the textarea is not within a form", function() {
514
+ expect(3);
515
+
516
+ var textareaElement = document.createElement("textarea");
517
+ document.body.appendChild(textareaElement);
518
+ var editor = new wysihtml5.Editor(textareaElement);
519
+
520
+ var that = this;
521
+ editor.observe("load", function() {
522
+ ok(!document.querySelector("input[name='_wysihtml5_mode']"), "No hidden _wysihtml5_mode input has been created");
523
+ ok(that.getIframeElement(), "Editor's iframe has been created");
524
+ equal(textareaElement.style.display, "none", "Textarea is not visible");
525
+ textareaElement.parentNode.removeChild(textareaElement);
526
+
527
+ start();
528
+ });
529
+ });
530
+
531
+ asyncTest("Test disabled textarea", function() {
532
+ expect(2);
533
+
534
+ this.textareaElement.disabled = true;
535
+ var that = this;
536
+
537
+ var editor = new wysihtml5.Editor(this.textareaElement);
538
+
539
+ editor.on("load", function() {
540
+ var iframeElement = that.getIframeElement(),
541
+ composerElement = that.getComposerElement();
542
+ equal(wysihtml5.dom.getStyle("margin-top").from(iframeElement), "20px", "Correct :disabled styles applied");
543
+ ok(!composerElement.hasAttribute("contentEditable"), "Editor is unfocusable");
544
+ start();
545
+ });
546
+ });
547
+ }