kublog 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +177 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +102 -0
  6. data/Rakefile +39 -0
  7. data/app/assets/images/kublog/.gitkeep +0 -0
  8. data/app/assets/images/kublog/missing_image.png +0 -0
  9. data/app/assets/javascripts/kublog/application.js +13 -0
  10. data/app/assets/javascripts/kublog/categories.js.coffee +48 -0
  11. data/app/assets/javascripts/kublog/comments.js.coffee +30 -0
  12. data/app/assets/javascripts/kublog/email.js.coffee +32 -0
  13. data/app/assets/javascripts/kublog/images.js.coffee +77 -0
  14. data/app/assets/javascripts/kublog/posts.js.coffee +44 -0
  15. data/app/assets/javascripts/kublog/shared.js.coffee.erb +19 -0
  16. data/app/assets/javascripts/kublog/wysiwyg.controls.js.coffee +68 -0
  17. data/app/assets/plugins/kublog/ajaxyupload/images/ajax-loader.gif +0 -0
  18. data/app/assets/plugins/kublog/ajaxyupload/javascripts/jquery.ajaxyupload.js +126 -0
  19. data/app/assets/plugins/kublog/fancybox/images/blank.gif +0 -0
  20. data/app/assets/plugins/kublog/fancybox/images/fancy_close.png +0 -0
  21. data/app/assets/plugins/kublog/fancybox/images/fancy_loading.png +0 -0
  22. data/app/assets/plugins/kublog/fancybox/images/fancy_nav_left.png +0 -0
  23. data/app/assets/plugins/kublog/fancybox/images/fancy_nav_right.png +0 -0
  24. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_e.png +0 -0
  25. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_n.png +0 -0
  26. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_ne.png +0 -0
  27. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_nw.png +0 -0
  28. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_s.png +0 -0
  29. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_se.png +0 -0
  30. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_sw.png +0 -0
  31. data/app/assets/plugins/kublog/fancybox/images/fancy_shadow_w.png +0 -0
  32. data/app/assets/plugins/kublog/fancybox/images/fancy_title_left.png +0 -0
  33. data/app/assets/plugins/kublog/fancybox/images/fancy_title_main.png +0 -0
  34. data/app/assets/plugins/kublog/fancybox/images/fancy_title_over.png +0 -0
  35. data/app/assets/plugins/kublog/fancybox/images/fancy_title_right.png +0 -0
  36. data/app/assets/plugins/kublog/fancybox/images/fancybox-x.png +0 -0
  37. data/app/assets/plugins/kublog/fancybox/images/fancybox-y.png +0 -0
  38. data/app/assets/plugins/kublog/fancybox/images/fancybox.png +0 -0
  39. data/app/assets/plugins/kublog/fancybox/javascripts/fancybox-1.3.4.js +46 -0
  40. data/app/assets/plugins/kublog/fancybox/stylesheets/fancybox-1.3.4.css +359 -0
  41. data/app/assets/plugins/kublog/livequery/javascripts/jquery.livequery.js +250 -0
  42. data/app/assets/plugins/kublog/wysiwyg/images/ajax-loader.gif +0 -0
  43. data/app/assets/plugins/kublog/wysiwyg/images/jquery.wysiwyg.bg.png +0 -0
  44. data/app/assets/plugins/kublog/wysiwyg/images/jquery.wysiwyg.gif +0 -0
  45. data/app/assets/plugins/kublog/wysiwyg/images/jquery.wysiwyg.jpg +0 -0
  46. data/app/assets/plugins/kublog/wysiwyg/images/jquery.wysiwyg.no-alpha.gif +0 -0
  47. data/app/assets/plugins/kublog/wysiwyg/javascripts/jquery.wysiwyg.js +2377 -0
  48. data/app/assets/plugins/kublog/wysiwyg/javascripts/wysiwyg.image.js +284 -0
  49. data/app/assets/plugins/kublog/wysiwyg/javascripts/wysiwyg.link.js +249 -0
  50. data/app/assets/plugins/kublog/wysiwyg/stylesheets/jquery.wysiwyg.css +94 -0
  51. data/app/assets/stylesheets/kublog/application.css +9 -0
  52. data/app/assets/stylesheets/kublog/categories.css +4 -0
  53. data/app/assets/stylesheets/kublog/comments.css +4 -0
  54. data/app/assets/stylesheets/kublog/email.css +7 -0
  55. data/app/assets/stylesheets/kublog/images.css +41 -0
  56. data/app/assets/stylesheets/kublog/posts.css +39 -0
  57. data/app/controllers/kublog/application_controller.rb +12 -0
  58. data/app/controllers/kublog/categories_controller.rb +47 -0
  59. data/app/controllers/kublog/comments_controller.rb +37 -0
  60. data/app/controllers/kublog/images_controller.rb +44 -0
  61. data/app/controllers/kublog/posts_controller.rb +66 -0
  62. data/app/helpers/kublog/application_helper.rb +4 -0
  63. data/app/helpers/kublog/posts_helper.rb +38 -0
  64. data/app/mailers/kublog/post_mailer.rb +11 -0
  65. data/app/models/kublog/category.rb +26 -0
  66. data/app/models/kublog/comment.rb +46 -0
  67. data/app/models/kublog/image.rb +23 -0
  68. data/app/models/kublog/post.rb +51 -0
  69. data/app/presenters/kublog/post_presenter.rb +23 -0
  70. data/app/presenters/kublog/posts_presenter.rb +29 -0
  71. data/app/uploaders/kublog/file_uploader.rb +56 -0
  72. data/app/views/kublog/post_mailer/new_post.html.erb +1 -0
  73. data/app/views/kublog/post_mailer/new_post.liquid.html.erb +7 -0
  74. data/app/views/kublog/posts/_email_form.html.erb +13 -0
  75. data/app/views/kublog/posts/_form.html.erb +71 -0
  76. data/app/views/kublog/posts/_image_form.html.erb +26 -0
  77. data/app/views/kublog/posts/edit.html.erb +3 -0
  78. data/app/views/kublog/posts/index.atom.builder +15 -0
  79. data/app/views/kublog/posts/index.html.erb +36 -0
  80. data/app/views/kublog/posts/new.html.erb +3 -0
  81. data/app/views/kublog/posts/show.html.erb +46 -0
  82. data/app/views/layouts/kublog/application.html.erb +14 -0
  83. data/config/locales/kublog/en.yml +54 -0
  84. data/config/routes.rb +13 -0
  85. data/db/migrate/20110816211552_create_kublog_posts.rb +27 -0
  86. data/db/migrate/20110817215828_create_kublog_images.rb +11 -0
  87. data/db/migrate/20110818181434_create_kublog_categories.rb +11 -0
  88. data/db/migrate/20110822194341_create_kublog_comments.rb +14 -0
  89. data/kublog.gemspec +39 -0
  90. data/lib/kublog.rb +92 -0
  91. data/lib/kublog/author.rb +13 -0
  92. data/lib/kublog/engine.rb +5 -0
  93. data/lib/kublog/notifiable.rb +26 -0
  94. data/lib/kublog/notification/email.rb +86 -0
  95. data/lib/kublog/notification/email_job.rb +14 -0
  96. data/lib/kublog/notification/fb_post.rb +43 -0
  97. data/lib/kublog/notification/fb_post_job.rb +16 -0
  98. data/lib/kublog/notification/tweet.rb +68 -0
  99. data/lib/kublog/notification/tweet_job.rb +16 -0
  100. data/lib/kublog/user_integration/common.rb +31 -0
  101. data/lib/kublog/user_integration/devise.rb +23 -0
  102. data/lib/kublog/version.rb +3 -0
  103. data/lib/kublog/xhr_upload/file_helper.rb +36 -0
  104. data/lib/tasks/kublog_tasks.rake +4 -0
  105. data/script/rails +6 -0
  106. data/test/dummy/Rakefile +7 -0
  107. data/test/dummy/app/assets/javascripts/application.js +9 -0
  108. data/test/dummy/app/assets/javascripts/sessions.js +2 -0
  109. data/test/dummy/app/assets/javascripts/users.js +2 -0
  110. data/test/dummy/app/assets/stylesheets/application.css +157 -0
  111. data/test/dummy/app/assets/stylesheets/sessions.css +4 -0
  112. data/test/dummy/app/assets/stylesheets/users.css +4 -0
  113. data/test/dummy/app/controllers/application_controller.rb +19 -0
  114. data/test/dummy/app/controllers/sessions_controller.rb +22 -0
  115. data/test/dummy/app/controllers/users_controller.rb +17 -0
  116. data/test/dummy/app/helpers/application_helper.rb +2 -0
  117. data/test/dummy/app/helpers/error_messages_helper.rb +23 -0
  118. data/test/dummy/app/helpers/layout_helper.rb +22 -0
  119. data/test/dummy/app/helpers/sessions_helper.rb +2 -0
  120. data/test/dummy/app/helpers/users_helper.rb +2 -0
  121. data/test/dummy/app/mailers/.gitkeep +0 -0
  122. data/test/dummy/app/models/.gitkeep +0 -0
  123. data/test/dummy/app/models/ability.rb +2 -0
  124. data/test/dummy/app/models/user.rb +25 -0
  125. data/test/dummy/app/views/layouts/_account.html.erb +8 -0
  126. data/test/dummy/app/views/layouts/application.html.erb +29 -0
  127. data/test/dummy/app/views/layouts/kublog/application.html.erb +31 -0
  128. data/test/dummy/app/views/sessions/new.html.erb +15 -0
  129. data/test/dummy/app/views/users/new.html.erb +28 -0
  130. data/test/dummy/config.ru +4 -0
  131. data/test/dummy/config/application.rb +42 -0
  132. data/test/dummy/config/boot.rb +10 -0
  133. data/test/dummy/config/database.yml +25 -0
  134. data/test/dummy/config/environment.rb +5 -0
  135. data/test/dummy/config/environments/development.rb +38 -0
  136. data/test/dummy/config/environments/production.rb +51 -0
  137. data/test/dummy/config/environments/test.rb +39 -0
  138. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  139. data/test/dummy/config/initializers/inflections.rb +10 -0
  140. data/test/dummy/config/initializers/mime_types.rb +5 -0
  141. data/test/dummy/config/initializers/secret_token.rb +7 -0
  142. data/test/dummy/config/initializers/session_store.rb +8 -0
  143. data/test/dummy/config/initializers/wrap_parameters.rb +12 -0
  144. data/test/dummy/config/locales/en.yml +54 -0
  145. data/test/dummy/config/routes.rb +13 -0
  146. data/test/dummy/db/migrate/20110816225222_create_users.rb +11 -0
  147. data/test/dummy/db/migrate/20110819135547_create_delayed_jobs.rb +21 -0
  148. data/test/dummy/db/schema.rb +96 -0
  149. data/test/dummy/lib/assets/.gitkeep +0 -0
  150. data/test/dummy/log/.gitkeep +0 -0
  151. data/test/dummy/public/404.html +26 -0
  152. data/test/dummy/public/422.html +26 -0
  153. data/test/dummy/public/500.html +26 -0
  154. data/test/dummy/public/favicon.ico +0 -0
  155. data/test/dummy/script/delayed_job +5 -0
  156. data/test/dummy/script/rails +6 -0
  157. data/test/dummy/test/fixtures/users.yml +9 -0
  158. data/test/dummy/test/functional/sessions_controller_test.rb +7 -0
  159. data/test/dummy/test/functional/users_controller_test.rb +7 -0
  160. data/test/dummy/test/unit/helpers/sessions_helper_test.rb +4 -0
  161. data/test/dummy/test/unit/helpers/users_helper_test.rb +4 -0
  162. data/test/dummy/test/unit/user_test.rb +7 -0
  163. data/test/factories.rb +9 -0
  164. data/test/fixtures/kublog/categories.yml +7 -0
  165. data/test/fixtures/kublog/comments.yml +7 -0
  166. data/test/fixtures/kublog/images.yml +9 -0
  167. data/test/fixtures/kublog/posts.yml +9 -0
  168. data/test/functional/kublog/categories_controller_test.rb +9 -0
  169. data/test/functional/kublog/comments_controller_test.rb +9 -0
  170. data/test/functional/kublog/images_controller_test.rb +9 -0
  171. data/test/functional/kublog/post_mailer_test.rb +9 -0
  172. data/test/functional/kublog/posts_controller_test.rb +9 -0
  173. data/test/integration/navigation_test.rb +10 -0
  174. data/test/kublog_test.rb +7 -0
  175. data/test/test_helper.rb +12 -0
  176. data/test/unit/helpers/kublog/categories_helper_test.rb +6 -0
  177. data/test/unit/helpers/kublog/comments_helper_test.rb +6 -0
  178. data/test/unit/helpers/kublog/images_helper_test.rb +6 -0
  179. data/test/unit/helpers/kublog/posts_helper_test.rb +6 -0
  180. data/test/unit/kublog/category_test.rb +9 -0
  181. data/test/unit/kublog/comment_test.rb +9 -0
  182. data/test/unit/kublog/image_test.rb +9 -0
  183. data/test/unit/kublog/post_test.rb +19 -0
  184. metadata +439 -0
@@ -0,0 +1,2377 @@
1
+ /**
2
+ * WYSIWYG - jQuery plugin 0.97
3
+ * (0.97.2 - From infinity)
4
+ *
5
+ * Copyright (c) 2008-2009 Juan M Martinez, 2010-2011 Akzhan Abdulin and all contributors
6
+ * https://github.com/akzhan/jwysiwyg
7
+ *
8
+ * Dual licensed under the MIT and GPL licenses:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ * http://www.gnu.org/licenses/gpl.html
11
+ *
12
+ */
13
+
14
+ /*jslint browser: true, forin: true */
15
+
16
+ (function ($) {
17
+ "use strict";
18
+ /* Wysiwyg namespace: private properties and methods */
19
+
20
+ var console = window.console ? window.console : {
21
+ log: $.noop,
22
+ error: function (msg) {
23
+ $.error(msg);
24
+ }
25
+ };
26
+ var supportsProp = (('prop' in $.fn) && ('removeProp' in $.fn));
27
+
28
+ function Wysiwyg() {
29
+ this.controls = {
30
+ bold: {
31
+ groupIndex: 0,
32
+ visible: true,
33
+ tags: ["b", "strong"],
34
+ css: {
35
+ fontWeight: "bold"
36
+ },
37
+ tooltip: "Bold",
38
+ hotkey: {"ctrl": 1, "key": 66}
39
+ },
40
+
41
+ copy: {
42
+ groupIndex: 8,
43
+ visible: false,
44
+ tooltip: "Copy"
45
+ },
46
+
47
+ createLink: {
48
+ groupIndex: 6,
49
+ visible: true,
50
+ exec: function () {
51
+ var self = this;
52
+ if ($.wysiwyg.controls && $.wysiwyg.controls.link) {
53
+ $.wysiwyg.controls.link.init(this);
54
+ } else if ($.wysiwyg.autoload) {
55
+ $.wysiwyg.autoload.control("wysiwyg.link.js", function () {
56
+ self.controls.createLink.exec.apply(self);
57
+ });
58
+ } else {
59
+ console.error("$.wysiwyg.controls.link not defined. You need to include wysiwyg.link.js file");
60
+ }
61
+ },
62
+ tags: ["a"],
63
+ tooltip: "Create link"
64
+ },
65
+
66
+ cut: {
67
+ groupIndex: 8,
68
+ visible: false,
69
+ tooltip: "Cut"
70
+ },
71
+
72
+ decreaseFontSize: {
73
+ groupIndex: 9,
74
+ visible: false,
75
+ tags: ["small"],
76
+ tooltip: "Decrease font size",
77
+ exec: function () {
78
+ this.decreaseFontSize();
79
+ }
80
+ },
81
+
82
+ h1: {
83
+ groupIndex: 7,
84
+ visible: true,
85
+ className: "h1",
86
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
87
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h1>" : "h1",
88
+ tags: ["h1"],
89
+ tooltip: "Header 1"
90
+ },
91
+
92
+ h2: {
93
+ groupIndex: 7,
94
+ visible: true,
95
+ className: "h2",
96
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
97
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h2>" : "h2",
98
+ tags: ["h2"],
99
+ tooltip: "Header 2"
100
+ },
101
+
102
+ h3: {
103
+ groupIndex: 7,
104
+ visible: true,
105
+ className: "h3",
106
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
107
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h3>" : "h3",
108
+ tags: ["h3"],
109
+ tooltip: "Header 3"
110
+ },
111
+
112
+ highlight: {
113
+ tooltip: "Highlight",
114
+ className: "highlight",
115
+ groupIndex: 1,
116
+ visible: false,
117
+ css: {
118
+ backgroundColor: "rgb(255, 255, 102)"
119
+ },
120
+ exec: function () {
121
+ var command, node, selection, args;
122
+
123
+ if ($.browser.msie || $.browser.safari) {
124
+ command = "backcolor";
125
+ } else {
126
+ command = "hilitecolor";
127
+ }
128
+
129
+ if ($.browser.msie) {
130
+ node = this.getInternalRange().parentElement();
131
+ } else {
132
+ selection = this.getInternalSelection();
133
+ node = selection.extentNode || selection.focusNode;
134
+
135
+ while (node.style === undefined) {
136
+ node = node.parentNode;
137
+ if (node.tagName && node.tagName.toLowerCase() === "body") {
138
+ return;
139
+ }
140
+ }
141
+ }
142
+
143
+ if (node.style.backgroundColor === "rgb(255, 255, 102)" ||
144
+ node.style.backgroundColor === "#ffff66") {
145
+ args = "#ffffff";
146
+ } else {
147
+ args = "#ffff66";
148
+ }
149
+
150
+ this.editorDoc.execCommand(command, false, args);
151
+ }
152
+ },
153
+
154
+ html: {
155
+ groupIndex: 10,
156
+ visible: false,
157
+ exec: function () {
158
+ var elementHeight;
159
+
160
+ if (this.options.resizeOptions && $.fn.resizable) {
161
+ elementHeight = this.element.height();
162
+ }
163
+
164
+ if (this.viewHTML) {
165
+ this.setContent(this.original.value);
166
+
167
+ $(this.original).hide();
168
+ this.editor.show();
169
+
170
+ if (this.options.resizeOptions && $.fn.resizable) {
171
+ // if element.height still the same after frame was shown
172
+ if (elementHeight === this.element.height()) {
173
+ this.element.height(elementHeight + this.editor.height());
174
+ }
175
+
176
+ this.element.resizable($.extend(true, {
177
+ alsoResize: this.editor
178
+ }, this.options.resizeOptions));
179
+ }
180
+
181
+ this.ui.toolbar.find("li").each(function () {
182
+ var li = $(this);
183
+
184
+ if (li.hasClass("html")) {
185
+ li.removeClass("active");
186
+ } else {
187
+ li.removeClass('disabled');
188
+ }
189
+ });
190
+ } else {
191
+ this.saveContent();
192
+
193
+ $(this.original).css({
194
+ width: this.element.outerWidth() - 6,
195
+ height: this.element.height() - this.ui.toolbar.height() - 6,
196
+ resize: "none"
197
+ }).show();
198
+ this.editor.hide();
199
+
200
+ if (this.options.resizeOptions && $.fn.resizable) {
201
+ // if element.height still the same after frame was hidden
202
+ if (elementHeight === this.element.height()) {
203
+ this.element.height(this.ui.toolbar.height());
204
+ }
205
+
206
+ this.element.resizable("destroy");
207
+ }
208
+
209
+ this.ui.toolbar.find("li").each(function () {
210
+ var li = $(this);
211
+
212
+ if (li.hasClass("html")) {
213
+ li.addClass("active");
214
+ } else {
215
+ if (false === li.hasClass("fullscreen")) {
216
+ li.removeClass("active").addClass('disabled');
217
+ }
218
+ }
219
+ });
220
+ }
221
+
222
+ this.viewHTML = !(this.viewHTML);
223
+ },
224
+ tooltip: "View source code"
225
+ },
226
+
227
+ increaseFontSize: {
228
+ groupIndex: 9,
229
+ visible: false,
230
+ tags: ["big"],
231
+ tooltip: "Increase font size",
232
+ exec: function () {
233
+ this.increaseFontSize();
234
+ }
235
+ },
236
+
237
+ indent: {
238
+ groupIndex: 2,
239
+ visible: true,
240
+ tooltip: "Indent"
241
+ },
242
+
243
+ insertHorizontalRule: {
244
+ groupIndex: 6,
245
+ visible: true,
246
+ tags: ["hr"],
247
+ tooltip: "Insert Horizontal Rule"
248
+ },
249
+
250
+ insertImage: {
251
+ groupIndex: 6,
252
+ visible: true,
253
+ exec: function () {
254
+ var self = this;
255
+
256
+ if ($.wysiwyg.controls && $.wysiwyg.controls.image) {
257
+ $.wysiwyg.controls.image.init(this);
258
+ } else if ($.wysiwyg.autoload) {
259
+ $.wysiwyg.autoload.control("wysiwyg.image.js", function () {
260
+ self.controls.insertImage.exec.apply(self);
261
+ });
262
+ } else {
263
+ console.error("$.wysiwyg.controls.image not defined. You need to include wysiwyg.image.js file");
264
+ }
265
+ },
266
+ tags: ["img"],
267
+ tooltip: "Insert image"
268
+ },
269
+
270
+ insertOrderedList: {
271
+ groupIndex: 5,
272
+ visible: true,
273
+ tags: ["ol"],
274
+ tooltip: "Insert Ordered List"
275
+ },
276
+
277
+ insertTable: {
278
+ groupIndex: 6,
279
+ visible: false,
280
+ exec: function () {
281
+ var self = this;
282
+
283
+ if ($.wysiwyg.controls && $.wysiwyg.controls.table) {
284
+ $.wysiwyg.controls.table(this);
285
+ } else if ($.wysiwyg.autoload) {
286
+ $.wysiwyg.autoload.control("wysiwyg.table.js", function () {
287
+ self.controls.insertTable.exec.apply(self);
288
+ });
289
+ } else {
290
+ console.error("$.wysiwyg.controls.table not defined. You need to include wysiwyg.table.js file");
291
+ }
292
+ },
293
+ tags: ["table"],
294
+ tooltip: "Insert table"
295
+ },
296
+
297
+ insertUnorderedList: {
298
+ groupIndex: 5,
299
+ visible: true,
300
+ tags: ["ul"],
301
+ tooltip: "Insert Unordered List"
302
+ },
303
+
304
+ italic: {
305
+ groupIndex: 0,
306
+ visible: true,
307
+ tags: ["i", "em"],
308
+ css: {
309
+ fontStyle: "italic"
310
+ },
311
+ tooltip: "Italic",
312
+ hotkey: {"ctrl": 1, "key": 73}
313
+ },
314
+
315
+ justifyCenter: {
316
+ groupIndex: 1,
317
+ visible: true,
318
+ tags: ["center"],
319
+ css: {
320
+ textAlign: "center"
321
+ },
322
+ tooltip: "Justify Center"
323
+ },
324
+
325
+ justifyFull: {
326
+ groupIndex: 1,
327
+ visible: true,
328
+ css: {
329
+ textAlign: "justify"
330
+ },
331
+ tooltip: "Justify Full"
332
+ },
333
+
334
+ justifyLeft: {
335
+ visible: true,
336
+ groupIndex: 1,
337
+ css: {
338
+ textAlign: "left"
339
+ },
340
+ tooltip: "Justify Left"
341
+ },
342
+
343
+ justifyRight: {
344
+ groupIndex: 1,
345
+ visible: true,
346
+ css: {
347
+ textAlign: "right"
348
+ },
349
+ tooltip: "Justify Right"
350
+ },
351
+
352
+ ltr: {
353
+ groupIndex: 10,
354
+ visible: false,
355
+ exec: function () {
356
+ var p = this.dom.getElement("p");
357
+
358
+ if (!p) {
359
+ return false;
360
+ }
361
+
362
+ $(p).attr("dir", "ltr");
363
+ return true;
364
+ },
365
+ tooltip : "Left to Right"
366
+ },
367
+
368
+ outdent: {
369
+ groupIndex: 2,
370
+ visible: true,
371
+ tooltip: "Outdent"
372
+ },
373
+
374
+ paragraph: {
375
+ groupIndex: 7,
376
+ visible: false,
377
+ className: "paragraph",
378
+ command: "FormatBlock",
379
+ "arguments": ($.browser.msie || $.browser.safari) ? "<p>" : "p",
380
+ tags: ["p"],
381
+ tooltip: "Paragraph"
382
+ },
383
+
384
+ paste: {
385
+ groupIndex: 8,
386
+ visible: false,
387
+ tooltip: "Paste"
388
+ },
389
+
390
+ redo: {
391
+ groupIndex: 4,
392
+ visible: true,
393
+ tooltip: "Redo"
394
+ },
395
+
396
+ removeFormat: {
397
+ groupIndex: 10,
398
+ visible: false,
399
+ exec: function () {
400
+ this.removeFormat();
401
+ },
402
+ tooltip: "Remove formatting"
403
+ },
404
+
405
+ rtl: {
406
+ groupIndex: 10,
407
+ visible: false,
408
+ exec: function () {
409
+ var p = this.dom.getElement("p");
410
+
411
+ if (!p) {
412
+ return false;
413
+ }
414
+
415
+ $(p).attr("dir", "rtl");
416
+ return true;
417
+ },
418
+ tooltip : "Right to Left"
419
+ },
420
+
421
+ strikeThrough: {
422
+ groupIndex: 0,
423
+ visible: true,
424
+ tags: ["s", "strike"],
425
+ css: {
426
+ textDecoration: "line-through"
427
+ },
428
+ tooltip: "Strike-through"
429
+ },
430
+
431
+ subscript: {
432
+ groupIndex: 3,
433
+ visible: true,
434
+ tags: ["sub"],
435
+ tooltip: "Subscript"
436
+ },
437
+
438
+ superscript: {
439
+ groupIndex: 3,
440
+ visible: true,
441
+ tags: ["sup"],
442
+ tooltip: "Superscript"
443
+ },
444
+
445
+ underline: {
446
+ groupIndex: 0,
447
+ visible: true,
448
+ tags: ["u"],
449
+ css: {
450
+ textDecoration: "underline"
451
+ },
452
+ tooltip: "Underline",
453
+ hotkey: {"ctrl": 1, "key": 85}
454
+ },
455
+
456
+ undo: {
457
+ groupIndex: 4,
458
+ visible: true,
459
+ tooltip: "Undo"
460
+ },
461
+
462
+ code: {
463
+ visible : false,
464
+ groupIndex: 6,
465
+ tooltip: "Code snippet",
466
+ exec: function () {
467
+ var range = this.getInternalRange(),
468
+ common = $(range.commonAncestorContainer),
469
+ $nodeName = range.commonAncestorContainer.nodeName.toLowerCase();
470
+ if (common.parent("code").length) {
471
+ common.unwrap();
472
+ } else {
473
+ if ($nodeName !== "body") {
474
+ common.wrap("<code/>");
475
+ }
476
+ }
477
+ }
478
+ },
479
+
480
+ cssWrap: {
481
+ visible : false,
482
+ groupIndex: 6,
483
+ tooltip: "CSS Wrapper",
484
+ exec: function () {
485
+ $.wysiwyg.controls.cssWrap.init(this);
486
+ }
487
+ }
488
+
489
+ };
490
+
491
+ this.defaults = {
492
+ html: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" style="margin:0"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body style="margin:15px;">INITIAL_CONTENT</body></html>',
493
+ debug: false,
494
+ controls: {},
495
+ css: {},
496
+ events: {},
497
+ autoGrow: false,
498
+ autoSave: true,
499
+ brIE: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=15
500
+ formHeight: 270,
501
+ formWidth: 440,
502
+ iFrameClass: null,
503
+ initialContent: "<p>&nbsp;</p>",
504
+ maxHeight: 10000, // see autoGrow
505
+ maxLength: 0,
506
+ messages: {
507
+ nonSelection: "Select the text you wish to link"
508
+ },
509
+ toolbarHtml: '<ul role="menu" class="toolbar"></ul>',
510
+ removeHeadings: false,
511
+ replaceDivWithP: false,
512
+ resizeOptions: false,
513
+ rmUnusedControls: false, // https://github.com/akzhan/jwysiwyg/issues/52
514
+ rmUnwantedBr: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=11
515
+ tableFiller: "Lorem ipsum",
516
+ initialMinHeight: null,
517
+
518
+ controlImage: {
519
+ forceRelativeUrls: false
520
+ },
521
+
522
+ controlLink: {
523
+ forceRelativeUrls: false
524
+ },
525
+
526
+ plugins: { // placeholder for plugins settings
527
+ autoload: false,
528
+ i18n: false,
529
+ rmFormat: {
530
+ rmMsWordMarkup: false
531
+ }
532
+ },
533
+
534
+ dialog : "default"
535
+ };
536
+
537
+ this.availableControlProperties = [
538
+ "arguments",
539
+ "callback",
540
+ "className",
541
+ "command",
542
+ "css",
543
+ "custom",
544
+ "exec",
545
+ "groupIndex",
546
+ "hotkey",
547
+ "icon",
548
+ "tags",
549
+ "tooltip",
550
+ "visible"
551
+ ];
552
+
553
+ this.editor = null;
554
+ this.editorDoc = null;
555
+ this.element = null;
556
+ this.options = {};
557
+ this.original = null;
558
+ this.savedRange = null;
559
+ this.timers = [];
560
+ this.validKeyCodes = [8, 9, 13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46];
561
+
562
+ this.isDestroyed = false;
563
+
564
+ this.dom = { // DOM related properties and methods
565
+ ie: {
566
+ parent: null // link to dom
567
+ },
568
+ w3c: {
569
+ parent: null // link to dom
570
+ }
571
+ };
572
+ this.dom.parent = this;
573
+ this.dom.ie.parent = this.dom;
574
+ this.dom.w3c.parent = this.dom;
575
+
576
+ this.ui = {}; // UI related properties and methods
577
+ this.ui.self = this;
578
+ this.ui.toolbar = null;
579
+ this.ui.initialHeight = null; // ui.grow
580
+
581
+ this.dom.getAncestor = function (element, filterTagName) {
582
+ filterTagName = filterTagName.toLowerCase();
583
+
584
+ while (element && typeof element.tagName != "undefined" && "body" !== element.tagName.toLowerCase()) {
585
+ if (filterTagName === element.tagName.toLowerCase()) {
586
+ return element;
587
+ }
588
+
589
+ element = element.parentNode;
590
+ }
591
+ if(!element.tagName && (element.previousSibling || element.nextSibling)) {
592
+ if(element.previousSibling) {
593
+ if(element.previousSibling.tagName.toLowerCase() == filterTagName) {
594
+ return element.previousSibling;
595
+ }
596
+ }
597
+ if(element.nextSibling) {
598
+ if(element.nextSibling.tagName.toLowerCase() == filterTagName) {
599
+ return element.nextSibling;
600
+ }
601
+ }
602
+ }
603
+
604
+ return null;
605
+ };
606
+
607
+ this.dom.getElement = function (filterTagName) {
608
+ var dom = this;
609
+
610
+ filterTagName = filterTagName.toLowerCase();
611
+
612
+ if (window.getSelection) {
613
+ return dom.w3c.getElement(filterTagName);
614
+ } else {
615
+ return dom.ie.getElement(filterTagName);
616
+ }
617
+ };
618
+
619
+ this.dom.ie.getElement = function (filterTagName) {
620
+ var dom = this.parent,
621
+ selection = dom.parent.getInternalSelection(),
622
+ range = selection.createRange(),
623
+ element;
624
+
625
+ if ("Control" === selection.type) {
626
+ // control selection
627
+ if (1 === range.length) {
628
+ element = range.item(0);
629
+ } else {
630
+ // multiple control selection
631
+ return null;
632
+ }
633
+ } else {
634
+ element = range.parentElement();
635
+ }
636
+
637
+ return dom.getAncestor(element, filterTagName);
638
+ };
639
+
640
+ this.dom.w3c.getElement = function (filterTagName) {
641
+ var dom = this.parent,
642
+ range = dom.parent.getInternalRange(),
643
+ element;
644
+
645
+ if (!range) {
646
+ return null;
647
+ }
648
+
649
+ element = range.commonAncestorContainer;
650
+
651
+ if (3 === element.nodeType) {
652
+ element = element.parentNode;
653
+ }
654
+
655
+ // if startContainer not Text, Comment, or CDATASection element then
656
+ // startOffset is the number of child nodes between the start of the
657
+ // startContainer and the boundary point of the Range
658
+ if (element === range.startContainer) {
659
+ element = element.childNodes[range.startOffset];
660
+ }
661
+
662
+ if(!element.tagName && (element.previousSibiling || element.nextSibling)) {
663
+ if(element.previousSibiling) {
664
+ if(element.previousSibiling.tagName.toLowerCase() == filterTagName) {
665
+ return element.previousSibiling;
666
+ }
667
+ }
668
+ if(element.nextSibling) {
669
+ if(element.nextSibling.tagName.toLowerCase() == filterTagName) {
670
+ return element.nextSibling;
671
+ }
672
+ }
673
+ }
674
+
675
+ return dom.getAncestor(element, filterTagName);
676
+ };
677
+
678
+ this.ui.addHoverClass = function () {
679
+ $(this).addClass("wysiwyg-button-hover");
680
+ };
681
+
682
+ this.ui.appendControls = function () {
683
+ var ui = this,
684
+ self = this.self,
685
+ controls = self.parseControls(),
686
+ hasVisibleControls = true, // to prevent separator before first item
687
+ groups = [],
688
+ controlsByGroup = {},
689
+ i,
690
+ currentGroupIndex, // jslint wants all vars at top of function
691
+ iterateGroup = function (controlName, control) {
692
+ if (control.groupIndex && currentGroupIndex !== control.groupIndex) {
693
+ currentGroupIndex = control.groupIndex;
694
+ hasVisibleControls = false;
695
+ }
696
+
697
+ if (!control.visible) {
698
+ return;
699
+ }
700
+
701
+ if (!hasVisibleControls) {
702
+ ui.appendItemSeparator();
703
+ hasVisibleControls = true;
704
+ }
705
+
706
+ if (control.custom) {
707
+ ui.appendItemCustom(controlName, control);
708
+ } else {
709
+ ui.appendItem(controlName, control);
710
+ }
711
+ };
712
+
713
+ $.each(controls, function (name, c) {
714
+ var index = "empty";
715
+
716
+ if (undefined !== c.groupIndex) {
717
+ if ("" === c.groupIndex) {
718
+ index = "empty";
719
+ } else {
720
+ index = c.groupIndex;
721
+ }
722
+ }
723
+
724
+ if (undefined === controlsByGroup[index]) {
725
+ groups.push(index);
726
+ controlsByGroup[index] = {};
727
+ }
728
+ controlsByGroup[index][name] = c;
729
+ });
730
+
731
+ groups.sort(function (a, b) {
732
+ if ("number" === typeof (a) && typeof (a) === typeof (b)) {
733
+ return (a - b);
734
+ } else {
735
+ a = a.toString();
736
+ b = b.toString();
737
+
738
+ if (a > b) {
739
+ return 1;
740
+ }
741
+
742
+ if (a === b) {
743
+ return 0;
744
+ }
745
+
746
+ return -1;
747
+ }
748
+ });
749
+
750
+ if (0 < groups.length) {
751
+ // set to first index in groups to proper placement of separator
752
+ currentGroupIndex = groups[0];
753
+ }
754
+
755
+ for (i = 0; i < groups.length; i += 1) {
756
+ $.each(controlsByGroup[groups[i]], iterateGroup);
757
+ }
758
+ };
759
+
760
+ this.ui.appendItem = function (name, control) {
761
+ var self = this.self,
762
+ className = control.className || control.command || name || "empty",
763
+ tooltip = control.tooltip || control.command || name || "";
764
+
765
+ return $('<li role="menuitem" unselectable="on">' + (className) + "</li>")
766
+ .addClass(className)
767
+ .attr("title", tooltip)
768
+ .hover(this.addHoverClass, this.removeHoverClass)
769
+ .click(function () {
770
+ if ($(this).hasClass("disabled")) {
771
+ return false;
772
+ }
773
+
774
+ self.triggerControl.apply(self, [name, control]);
775
+
776
+ this.blur();
777
+ self.ui.returnRange();
778
+ self.ui.focus();
779
+ return true;
780
+ })
781
+ .appendTo(self.ui.toolbar);
782
+ };
783
+
784
+ this.ui.appendItemCustom = function (name, control) {
785
+ var self = this.self,
786
+ tooltip = control.tooltip || control.command || name || "";
787
+
788
+ if (control.callback) {
789
+ $(window).bind("trigger-" + name + ".wysiwyg", control.callback);
790
+ }
791
+
792
+ return $('<li role="menuitem" unselectable="on" style="background: url(\'' + control.icon + '\') no-repeat;"></li>')
793
+ .addClass("custom-command-" + name)
794
+ .addClass("wysiwyg-custom-command")
795
+ .addClass(name)
796
+ .attr("title", tooltip)
797
+ .hover(this.addHoverClass, this.removeHoverClass)
798
+ .click(function () {
799
+ if ($(this).hasClass("disabled")) {
800
+ return false;
801
+ }
802
+
803
+ self.triggerControl.apply(self, [name, control]);
804
+
805
+ this.blur();
806
+ self.ui.returnRange();
807
+ self.ui.focus();
808
+
809
+ self.triggerControlCallback(name);
810
+ return true;
811
+ })
812
+ .appendTo(self.ui.toolbar);
813
+ };
814
+
815
+ this.ui.appendItemSeparator = function () {
816
+ var self = this.self;
817
+ return $('<li role="separator" class="separator"></li>').appendTo(self.ui.toolbar);
818
+ };
819
+
820
+ this.autoSaveFunction = function () {
821
+ this.saveContent();
822
+ };
823
+
824
+ this.ui.checkTargets = function (element) {
825
+ var self = this.self;
826
+
827
+ $.each(self.options.controls, function (name, control) {
828
+ var className = control.className || control.command || name || "empty",
829
+ tags,
830
+ elm,
831
+ css,
832
+ el,
833
+ checkActiveStatus = function (cssProperty, cssValue) {
834
+ var handler;
835
+
836
+ if ("function" === typeof (cssValue)) {
837
+ handler = cssValue;
838
+ if (handler(el.css(cssProperty).toString().toLowerCase(), self)) {
839
+ self.ui.toolbar.find("." + className).addClass("active");
840
+ }
841
+ } else {
842
+ if (el.css(cssProperty).toString().toLowerCase() === cssValue) {
843
+ self.ui.toolbar.find("." + className).addClass("active");
844
+ }
845
+ }
846
+ };
847
+
848
+ if ("fullscreen" !== className) {
849
+ self.ui.toolbar.find("." + className).removeClass("active");
850
+ }
851
+
852
+ if (control.tags || (control.options && control.options.tags)) {
853
+ tags = control.tags || (control.options && control.options.tags);
854
+
855
+ elm = element;
856
+ while (elm) {
857
+ if (elm.nodeType !== 1) {
858
+ break;
859
+ }
860
+
861
+ if ($.inArray(elm.tagName.toLowerCase(), tags) !== -1) {
862
+ self.ui.toolbar.find("." + className).addClass("active");
863
+ }
864
+
865
+ elm = elm.parentNode;
866
+ }
867
+ }
868
+
869
+ if (control.css || (control.options && control.options.css)) {
870
+ css = control.css || (control.options && control.options.css);
871
+ el = $(element);
872
+
873
+ while (el) {
874
+ if (el[0].nodeType !== 1) {
875
+ break;
876
+ }
877
+ $.each(css, checkActiveStatus);
878
+
879
+ el = el.parent();
880
+ }
881
+ }
882
+ });
883
+ };
884
+
885
+ this.ui.designMode = function () {
886
+ var attempts = 3,
887
+ self = this.self,
888
+ runner;
889
+ runner = function (attempts) {
890
+ if ("on" === self.editorDoc.designMode) {
891
+ if (self.timers.designMode) {
892
+ window.clearTimeout(self.timers.designMode);
893
+ }
894
+
895
+ // IE needs to reget the document element (this.editorDoc) after designMode was set
896
+ if (self.innerDocument() !== self.editorDoc) {
897
+ self.ui.initFrame();
898
+ }
899
+
900
+ return;
901
+ }
902
+
903
+ try {
904
+ self.editorDoc.designMode = "on";
905
+ } catch (e) {
906
+ }
907
+
908
+ attempts -= 1;
909
+ if (attempts > 0) {
910
+ self.timers.designMode = window.setTimeout(function () { runner(attempts); }, 100);
911
+ }
912
+ };
913
+
914
+ runner(attempts);
915
+ };
916
+
917
+ this.destroy = function () {
918
+ this.isDestroyed = true;
919
+
920
+ var i, $form = this.element.closest("form");
921
+
922
+ for (i = 0; i < this.timers.length; i += 1) {
923
+ window.clearTimeout(this.timers[i]);
924
+ }
925
+
926
+ // Remove bindings
927
+ $form.unbind(".wysiwyg");
928
+ this.element.remove();
929
+ $.removeData(this.original, "wysiwyg");
930
+ $(this.original).show();
931
+ return this;
932
+ };
933
+
934
+ this.getRangeText = function () {
935
+ var r = this.getInternalRange();
936
+
937
+ if (r.toString) {
938
+ r = r.toString();
939
+ } else if (r.text) { // IE
940
+ r = r.text;
941
+ }
942
+
943
+ return r;
944
+ };
945
+ //not used?
946
+ this.execute = function (command, arg) {
947
+ if (typeof (arg) === "undefined") {
948
+ arg = null;
949
+ }
950
+ this.editorDoc.execCommand(command, false, arg);
951
+ };
952
+
953
+ this.extendOptions = function (options) {
954
+ var controls = {};
955
+
956
+ /**
957
+ * If the user set custom controls, we catch it, and merge with the
958
+ * defaults controls later.
959
+ */
960
+ if ("object" === typeof options.controls) {
961
+ controls = options.controls;
962
+ delete options.controls;
963
+ }
964
+
965
+ options = $.extend(true, {}, this.defaults, options);
966
+ options.controls = $.extend(true, {}, controls, this.controls, controls);
967
+
968
+ if (options.rmUnusedControls) {
969
+ $.each(options.controls, function (controlName) {
970
+ if (!controls[controlName]) {
971
+ delete options.controls[controlName];
972
+ }
973
+ });
974
+ }
975
+
976
+ return options;
977
+ };
978
+
979
+ this.ui.focus = function () {
980
+ var self = this.self;
981
+
982
+ self.editor.get(0).contentWindow.focus();
983
+ return self;
984
+ };
985
+
986
+ this.ui.returnRange = function () {
987
+ var self = this.self, sel;
988
+
989
+ if (self.savedRange !== null) {
990
+ if (window.getSelection) { //non IE and there is already a selection
991
+ sel = window.getSelection();
992
+ if (sel.rangeCount > 0) {
993
+ sel.removeAllRanges();
994
+ }
995
+ try {
996
+ sel.addRange(self.savedRange);
997
+ } catch (e) {
998
+ console.error(e);
999
+ }
1000
+ } else if (window.document.createRange) { // non IE and no selection
1001
+ window.getSelection().addRange(self.savedRange);
1002
+ } else if (window.document.selection) { //IE
1003
+ self.savedRange.select();
1004
+ }
1005
+
1006
+ self.savedRange = null;
1007
+ }
1008
+ };
1009
+
1010
+ this.increaseFontSize = function () {
1011
+ if ($.browser.mozilla || $.browser.opera) {
1012
+ this.editorDoc.execCommand("increaseFontSize", false, null);
1013
+ } else if ($.browser.safari) {
1014
+ var Range = this.getInternalRange(),
1015
+ Selection = this.getInternalSelection(),
1016
+ newNode = this.editorDoc.createElement("big");
1017
+
1018
+ // If cursor placed on text node
1019
+ if (true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType) {
1020
+ var text = Range.commonAncestorContainer.nodeValue.toString(),
1021
+ start = text.lastIndexOf(" ", Range.startOffset) + 1,
1022
+ end = (-1 === text.indexOf(" ", Range.startOffset)) ? text : text.indexOf(" ", Range.startOffset);
1023
+
1024
+ Range.setStart(Range.commonAncestorContainer, start);
1025
+ Range.setEnd(Range.commonAncestorContainer, end);
1026
+
1027
+ Range.surroundContents(newNode);
1028
+ Selection.addRange(Range);
1029
+ } else {
1030
+ Range.surroundContents(newNode);
1031
+ Selection.removeAllRanges();
1032
+ Selection.addRange(Range);
1033
+ }
1034
+ } else {
1035
+ console.error("Internet Explorer?");
1036
+ }
1037
+ };
1038
+
1039
+ this.decreaseFontSize = function () {
1040
+ if ($.browser.mozilla || $.browser.opera) {
1041
+ this.editorDoc.execCommand("decreaseFontSize", false, null);
1042
+ } else if ($.browser.safari) {
1043
+ var Range = this.getInternalRange(),
1044
+ Selection = this.getInternalSelection(),
1045
+ newNode = this.editorDoc.createElement("small");
1046
+
1047
+ // If cursor placed on text node
1048
+ if (true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType) {
1049
+ var text = Range.commonAncestorContainer.nodeValue.toString(),
1050
+ start = text.lastIndexOf(" ", Range.startOffset) + 1,
1051
+ end = (-1 === text.indexOf(" ", Range.startOffset)) ? text : text.indexOf(" ", Range.startOffset);
1052
+
1053
+ Range.setStart(Range.commonAncestorContainer, start);
1054
+ Range.setEnd(Range.commonAncestorContainer, end);
1055
+
1056
+ Range.surroundContents(newNode);
1057
+ Selection.addRange(Range);
1058
+ } else {
1059
+ Range.surroundContents(newNode);
1060
+ Selection.removeAllRanges();
1061
+ Selection.addRange(Range);
1062
+ }
1063
+ } else {
1064
+ console.error("Internet Explorer?");
1065
+ }
1066
+ };
1067
+
1068
+ this.getContent = function () {
1069
+ if (this.viewHTML) {
1070
+ this.setContent(this.original.value);
1071
+ }
1072
+ return this.events.filter('getContent', this.editorDoc.body.innerHTML);
1073
+ };
1074
+
1075
+ /**
1076
+ * A jWysiwyg specific event system.
1077
+ *
1078
+ * Example:
1079
+ *
1080
+ * $("#editor").getWysiwyg().events.bind("getContent", function (orig) {
1081
+ * return "<div id='content'>"+orgi+"</div>";
1082
+ * });
1083
+ *
1084
+ * This makes it so that when ever getContent is called, it is wrapped in a div#content.
1085
+ */
1086
+ this.events = {
1087
+ _events : {},
1088
+
1089
+ /**
1090
+ * Similar to jQuery's bind, but for jWysiwyg only.
1091
+ */
1092
+ bind : function (eventName, callback) {
1093
+ if (typeof (this._events.eventName) !== "object") {
1094
+ this._events[eventName] = [];
1095
+ }
1096
+ this._events[eventName].push(callback);
1097
+ },
1098
+
1099
+ /**
1100
+ * Similar to jQuery's trigger, but for jWysiwyg only.
1101
+ */
1102
+ trigger : function (eventName, args) {
1103
+ if (typeof (this._events.eventName) === "object") {
1104
+ var editor = this.editor;
1105
+ $.each(this._events[eventName], function (k, v) {
1106
+ if (typeof (v) === "function") {
1107
+ v.apply(editor, args);
1108
+ }
1109
+ });
1110
+ }
1111
+ },
1112
+
1113
+ /**
1114
+ * This "filters" `originalText` by passing it as the first argument to every callback
1115
+ * with the name `eventName` and taking the return value and passing it to the next function.
1116
+ *
1117
+ * This function returns the result after all the callbacks have been applied to `originalText`.
1118
+ */
1119
+ filter : function (eventName, originalText) {
1120
+ if (typeof (this._events[eventName]) === "object") {
1121
+ var editor = this.editor,
1122
+ args = Array.prototype.slice.call(arguments, 1);
1123
+
1124
+ $.each(this._events[eventName], function (k, v) {
1125
+ if (typeof (v) === "function") {
1126
+ originalText = v.apply(editor, args);
1127
+ }
1128
+ });
1129
+ }
1130
+ return originalText;
1131
+ }
1132
+ };
1133
+
1134
+ this.getElementByAttributeValue = function (tagName, attributeName, attributeValue) {
1135
+ var i, value, elements = this.editorDoc.getElementsByTagName(tagName);
1136
+
1137
+ for (i = 0; i < elements.length; i += 1) {
1138
+ value = elements[i].getAttribute(attributeName);
1139
+
1140
+ if ($.browser.msie) {
1141
+ /** IE add full path, so I check by the last chars. */
1142
+ value = value.substr(value.length - attributeValue.length);
1143
+ }
1144
+
1145
+ if (value === attributeValue) {
1146
+ return elements[i];
1147
+ }
1148
+ }
1149
+
1150
+ return false;
1151
+ };
1152
+
1153
+ this.getInternalRange = function () {
1154
+ var selection = this.getInternalSelection();
1155
+
1156
+ if (!selection) {
1157
+ return null;
1158
+ }
1159
+
1160
+ if (selection.rangeCount && selection.rangeCount > 0) { // w3c
1161
+ return selection.getRangeAt(0);
1162
+ } else if (selection.createRange) { // ie
1163
+ return selection.createRange();
1164
+ }
1165
+
1166
+ return null;
1167
+ };
1168
+
1169
+ this.getInternalSelection = function () {
1170
+ // firefox: document.getSelection is deprecated
1171
+ if (this.editor.get(0).contentWindow) {
1172
+ if (this.editor.get(0).contentWindow.getSelection) {
1173
+ return this.editor.get(0).contentWindow.getSelection();
1174
+ }
1175
+ if (this.editor.get(0).contentWindow.selection) {
1176
+ return this.editor.get(0).contentWindow.selection;
1177
+ }
1178
+ }
1179
+ if (this.editorDoc.getSelection) {
1180
+ return this.editorDoc.getSelection();
1181
+ }
1182
+ if (this.editorDoc.selection) {
1183
+ return this.editorDoc.selection;
1184
+ }
1185
+
1186
+ return null;
1187
+ };
1188
+
1189
+ this.getRange = function () {
1190
+ var selection = this.getSelection();
1191
+
1192
+ if (!selection) {
1193
+ return null;
1194
+ }
1195
+
1196
+ if (selection.rangeCount && selection.rangeCount > 0) { // w3c
1197
+ selection.getRangeAt(0);
1198
+ } else if (selection.createRange) { // ie
1199
+ return selection.createRange();
1200
+ }
1201
+
1202
+ return null;
1203
+ };
1204
+
1205
+ this.getSelection = function () {
1206
+ return (window.getSelection) ? window.getSelection() : window.document.selection;
1207
+ };
1208
+
1209
+ // :TODO: you can type long string and letters will be hidden because of overflow
1210
+ this.ui.grow = function () {
1211
+ var self = this.self,
1212
+ innerBody = $(self.editorDoc.body),
1213
+ innerHeight = $.browser.msie ? innerBody[0].scrollHeight : innerBody.height() + 2 + 20, // 2 - borders, 20 - to prevent content jumping on grow
1214
+ minHeight = self.ui.initialHeight,
1215
+ height = Math.max(innerHeight, minHeight);
1216
+
1217
+ height = Math.min(height, self.options.maxHeight);
1218
+
1219
+ self.editor.attr("scrolling", height < self.options.maxHeight ? "no" : "auto"); // hide scrollbar firefox
1220
+ innerBody.css("overflow", height < self.options.maxHeight ? "hidden" : ""); // hide scrollbar chrome
1221
+
1222
+ self.editor.get(0).height = height;
1223
+
1224
+ return self;
1225
+ };
1226
+
1227
+ this.init = function (element, options) {
1228
+ var self = this,
1229
+ $form = $(element).closest("form"),
1230
+ newX = element.width || element.clientWidth || 0,
1231
+ newY = element.height || element.clientHeight || 0
1232
+ ;
1233
+
1234
+ this.options = this.extendOptions(options);
1235
+ this.original = element;
1236
+ this.ui.toolbar = $(this.options.toolbarHtml);
1237
+
1238
+ if ($.browser.msie && parseInt($.browser.version, 10) < 8) {
1239
+ this.options.autoGrow = false;
1240
+ }
1241
+
1242
+ if (newX === 0 && element.cols) {
1243
+ newX = (element.cols * 8) + 21;
1244
+ }
1245
+ if (newY === 0 && element.rows) {
1246
+ newY = (element.rows * 16) + 16;
1247
+ }
1248
+
1249
+ this.editor = $(window.location.protocol === "https:" ? '<iframe src="javascript:false;"></iframe>' : "<iframe></iframe>").attr("frameborder", "0");
1250
+
1251
+ if (this.options.iFrameClass) {
1252
+ this.editor.addClass(this.options.iFrameClass);
1253
+ } else {
1254
+ this.editor.css({
1255
+ minHeight: (newY - 6).toString() + "px",
1256
+ // fix for issue 12 ( http://github.com/akzhan/jwysiwyg/issues/issue/12 )
1257
+ width: (newX > 50) ? (newX - 8).toString() + "px" : ""
1258
+ });
1259
+ if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
1260
+ this.editor.css("height", newY.toString() + "px");
1261
+ }
1262
+ }
1263
+ /**
1264
+ * http://code.google.com/p/jwysiwyg/issues/detail?id=96
1265
+ */
1266
+ this.editor.attr("tabindex", $(element).attr("tabindex"));
1267
+
1268
+ this.element = $("<div/>").addClass("wysiwyg");
1269
+
1270
+ if (!this.options.iFrameClass) {
1271
+ this.element.css({
1272
+ width: (newX > 0) ? newX.toString() + "px" : "100%"
1273
+ });
1274
+ }
1275
+
1276
+ $(element).hide().before(this.element);
1277
+
1278
+ this.viewHTML = false;
1279
+
1280
+ /**
1281
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
1282
+ */
1283
+ this.initialContent = $(element).val();
1284
+ this.ui.initFrame();
1285
+
1286
+ if (this.options.resizeOptions && $.fn.resizable) {
1287
+ this.element.resizable($.extend(true, {
1288
+ alsoResize: this.editor
1289
+ }, this.options.resizeOptions));
1290
+ }
1291
+
1292
+ if (this.options.autoSave) {
1293
+ $form.bind("submit.wysiwyg", function () { self.autoSaveFunction(); });
1294
+ }
1295
+
1296
+ $form.bind("reset.wysiwyg", function () { self.resetFunction(); });
1297
+ };
1298
+
1299
+ this.ui.initFrame = function () {
1300
+ var self = this.self,
1301
+ stylesheet,
1302
+ growHandler,
1303
+ saveHandler;
1304
+
1305
+ self.ui.appendControls();
1306
+ self.element.append(self.ui.toolbar)
1307
+ .append($("<div><!-- --></div>")
1308
+ .css({
1309
+ clear: "both"
1310
+ }))
1311
+ .append(self.editor);
1312
+
1313
+ self.editorDoc = self.innerDocument();
1314
+
1315
+ if (self.isDestroyed) {
1316
+ return null;
1317
+ }
1318
+
1319
+ self.ui.designMode();
1320
+ self.editorDoc.open();
1321
+ self.editorDoc.write(
1322
+ self.options.html
1323
+ /**
1324
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=144
1325
+ */
1326
+ .replace(/INITIAL_CONTENT/, function () { return self.wrapInitialContent(); })
1327
+ );
1328
+ self.editorDoc.close();
1329
+
1330
+ $.wysiwyg.plugin.bind(self);
1331
+
1332
+ $(self.editorDoc).trigger("initFrame.wysiwyg");
1333
+
1334
+ $(self.editorDoc).bind("click.wysiwyg", function (event) {
1335
+ self.ui.checkTargets(event.target ? event.target : event.srcElement);
1336
+ });
1337
+
1338
+ /**
1339
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
1340
+ */
1341
+ $(self.original).focus(function () {
1342
+ if ($(this).filter(":visible").length === 0) {
1343
+ return;
1344
+ }
1345
+ self.ui.focus();
1346
+ });
1347
+
1348
+ $(self.editorDoc).keydown(function (event) {
1349
+ var emptyContentRegex;
1350
+ if (event.keyCode === 8) { // backspace
1351
+ emptyContentRegex = /^<([\w]+)[^>]*>(<br\/?>)?<\/\1>$/;
1352
+ if (emptyContentRegex.test(self.getContent())) { // if content is empty
1353
+ event.stopPropagation(); // prevent remove single empty tag
1354
+ return false;
1355
+ }
1356
+ }
1357
+ return true;
1358
+ });
1359
+
1360
+ if (!$.browser.msie) {
1361
+ $(self.editorDoc).keydown(function (event) {
1362
+ var controlName;
1363
+
1364
+ /* Meta for Macs. tom@punkave.com */
1365
+ if (event.ctrlKey || event.metaKey) {
1366
+ for (controlName in self.controls) {
1367
+ if (self.controls[controlName].hotkey && self.controls[controlName].hotkey.ctrl) {
1368
+ if (event.keyCode === self.controls[controlName].hotkey.key) {
1369
+ self.triggerControl.apply(self, [controlName, self.controls[controlName]]);
1370
+
1371
+ return false;
1372
+ }
1373
+ }
1374
+ }
1375
+ }
1376
+
1377
+ return true;
1378
+ });
1379
+ } else if (self.options.brIE) {
1380
+ $(self.editorDoc).keydown(function (event) {
1381
+ if (event.keyCode === 13) {
1382
+ var rng = self.getRange();
1383
+ rng.pasteHTML("<br/>");
1384
+ rng.collapse(false);
1385
+ rng.select();
1386
+
1387
+ return false;
1388
+ }
1389
+
1390
+ return true;
1391
+ });
1392
+ }
1393
+
1394
+ if (self.options.plugins.rmFormat.rmMsWordMarkup) {
1395
+ $(self.editorDoc).bind("keyup.wysiwyg", function (event) {
1396
+ if (event.ctrlKey || event.metaKey) {
1397
+ // CTRL + V (paste)
1398
+ if (86 === event.keyCode) {
1399
+ if ($.wysiwyg.rmFormat) {
1400
+ if ("object" === typeof (self.options.plugins.rmFormat.rmMsWordMarkup)) {
1401
+ $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: self.options.plugins.rmFormat.rmMsWordMarkup }});
1402
+ } else {
1403
+ $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: { enabled: true }}});
1404
+ }
1405
+ }
1406
+ }
1407
+ }
1408
+ });
1409
+ }
1410
+
1411
+ if (self.options.autoSave) {
1412
+ $(self.editorDoc).keydown(function () { self.autoSaveFunction(); })
1413
+ .keyup(function () { self.autoSaveFunction(); })
1414
+ .mousedown(function () { self.autoSaveFunction(); })
1415
+ .bind($.support.noCloneEvent ? "input.wysiwyg" : "paste.wysiwyg", function () { self.autoSaveFunction(); });
1416
+ }
1417
+
1418
+ if (self.options.autoGrow) {
1419
+ if (self.options.initialMinHeight !== null) {
1420
+ self.ui.initialHeight = self.options.initialMinHeight;
1421
+ } else {
1422
+ self.ui.initialHeight = $(self.editorDoc).height();
1423
+ }
1424
+ $(self.editorDoc.body).css("border", "1px solid white"); // cancel margin collapsing
1425
+
1426
+ growHandler = function () {
1427
+ self.ui.grow();
1428
+ };
1429
+
1430
+ $(self.editorDoc).keyup(growHandler);
1431
+ $(self.editorDoc).bind("editorRefresh.wysiwyg", growHandler);
1432
+
1433
+ // fix when content height > textarea height
1434
+ self.ui.grow();
1435
+ }
1436
+
1437
+ if (self.options.css) {
1438
+ if (String === self.options.css.constructor) {
1439
+ if ($.browser.msie) {
1440
+ stylesheet = self.editorDoc.createStyleSheet(self.options.css);
1441
+ $(stylesheet).attr({
1442
+ "media": "all"
1443
+ });
1444
+ } else {
1445
+ stylesheet = $("<link/>").attr({
1446
+ "href": self.options.css,
1447
+ "media": "all",
1448
+ "rel": "stylesheet",
1449
+ "type": "text/css"
1450
+ });
1451
+
1452
+ $(self.editorDoc).find("head").append(stylesheet);
1453
+ }
1454
+ } else {
1455
+ self.timers.initFrame_Css = window.setTimeout(function () {
1456
+ $(self.editorDoc.body).css(self.options.css);
1457
+ }, 0);
1458
+ }
1459
+ }
1460
+
1461
+ if (self.initialContent.length === 0) {
1462
+ if ("function" === typeof (self.options.initialContent)) {
1463
+ self.setContent(self.options.initialContent());
1464
+ } else {
1465
+ self.setContent(self.options.initialContent);
1466
+ }
1467
+ }
1468
+
1469
+ if (self.options.maxLength > 0) {
1470
+ $(self.editorDoc).keydown(function (event) {
1471
+ if ($(self.editorDoc).text().length >= self.options.maxLength && $.inArray(event.which, self.validKeyCodes) === -1) {
1472
+ event.preventDefault();
1473
+ }
1474
+ });
1475
+ }
1476
+
1477
+ // Support event callbacks
1478
+ $.each(self.options.events, function (key, handler) {
1479
+ $(self.editorDoc).bind(key + ".wysiwyg", function (event) {
1480
+ // Trigger event handler, providing the event and api to
1481
+ // support additional functionality.
1482
+ handler.apply(self.editorDoc, [event, self]);
1483
+ });
1484
+ });
1485
+
1486
+ // restores selection properly on focus
1487
+ if ($.browser.msie) {
1488
+ // Event chain: beforedeactivate => focusout => blur.
1489
+ // Focusout & blur fired too late to handle internalRange() in dialogs.
1490
+ // When clicked on input boxes both got range = null
1491
+ $(self.editorDoc).bind("beforedeactivate.wysiwyg", function () {
1492
+ self.savedRange = self.getInternalRange();
1493
+ });
1494
+ } else {
1495
+ $(self.editorDoc).bind("blur.wysiwyg", function () {
1496
+ self.savedRange = self.getInternalRange();
1497
+ });
1498
+ }
1499
+
1500
+ $(self.editorDoc.body).addClass("wysiwyg");
1501
+ if (self.options.events && self.options.events.save) {
1502
+ saveHandler = self.options.events.save;
1503
+
1504
+ $(self.editorDoc).bind("keyup.wysiwyg", saveHandler);
1505
+ $(self.editorDoc).bind("change.wysiwyg", saveHandler);
1506
+
1507
+ if ($.support.noCloneEvent) {
1508
+ $(self.editorDoc).bind("input.wysiwyg", saveHandler);
1509
+ } else {
1510
+ $(self.editorDoc).bind("paste.wysiwyg", saveHandler);
1511
+ $(self.editorDoc).bind("cut.wysiwyg", saveHandler);
1512
+ }
1513
+ }
1514
+
1515
+ /**
1516
+ * XHTML5 {@link https://github.com/akzhan/jwysiwyg/issues/152}
1517
+ */
1518
+ if (self.options.xhtml5 && self.options.unicode) {
1519
+ var replacements = {ne:8800,le:8804,para:182,xi:958,darr:8595,nu:957,oacute:243,Uacute:218,omega:969,prime:8242,pound:163,igrave:236,thorn:254,forall:8704,emsp:8195,lowast:8727,brvbar:166,alefsym:8501,nbsp:160,delta:948,clubs:9827,lArr:8656,Omega:937,Auml:196,cedil:184,and:8743,plusmn:177,ge:8805,raquo:187,uml:168,equiv:8801,laquo:171,rdquo:8221,Epsilon:917,divide:247,fnof:402,chi:967,Dagger:8225,iacute:237,rceil:8969,sigma:963,Oslash:216,acute:180,frac34:190,lrm:8206,upsih:978,Scaron:352,part:8706,exist:8707,nabla:8711,image:8465,prop:8733,zwj:8205,omicron:959,aacute:225,Yuml:376,Yacute:221,weierp:8472,rsquo:8217,otimes:8855,kappa:954,thetasym:977,harr:8596,Ouml:214,Iota:921,ograve:242,sdot:8901,copy:169,oplus:8853,acirc:226,sup:8835,zeta:950,Iacute:205,Oacute:211,crarr:8629,Nu:925,bdquo:8222,lsquo:8216,apos:39,Beta:914,eacute:233,egrave:232,lceil:8968,Kappa:922,piv:982,Ccedil:199,ldquo:8220,Xi:926,cent:162,uarr:8593,hellip:8230,Aacute:193,ensp:8194,sect:167,Ugrave:217,aelig:230,ordf:170,curren:164,sbquo:8218,macr:175,Phi:934,Eta:919,rho:961,Omicron:927,sup2:178,euro:8364,aring:229,Theta:920,mdash:8212,uuml:252,otilde:245,eta:951,uacute:250,rArr:8658,nsub:8836,agrave:224,notin:8713,ndash:8211,Psi:936,Ocirc:212,sube:8838,szlig:223,micro:181,not:172,sup1:185,middot:183,iota:953,ecirc:234,lsaquo:8249,thinsp:8201,sum:8721,ntilde:241,scaron:353,cap:8745,atilde:227,lang:10216,__replacement:65533,isin:8712,gamma:947,Euml:203,ang:8736,upsilon:965,Ntilde:209,hearts:9829,Alpha:913,Tau:932,spades:9824,dagger:8224,THORN:222,"int":8747,lambda:955,Eacute:201,Uuml:220,infin:8734,rlm:8207,Aring:197,ugrave:249,Egrave:200,Acirc:194,rsaquo:8250,ETH:208,oslash:248,alpha:945,Ograve:210,Prime:8243,mu:956,ni:8715,real:8476,bull:8226,beta:946,icirc:238,eth:240,prod:8719,larr:8592,ordm:186,perp:8869,Gamma:915,reg:174,ucirc:251,Pi:928,psi:968,tilde:732,asymp:8776,zwnj:8204,Agrave:192,deg:176,AElig:198,times:215,Delta:916,sim:8764,Otilde:213,Mu:924,uArr:8657,circ:710,theta:952,Rho:929,sup3:179,diams:9830,tau:964,Chi:935,frac14:188,oelig:339,shy:173,or:8744,dArr:8659,phi:966,iuml:239,Lambda:923,rfloor:8971,iexcl:161,cong:8773,ccedil:231,Icirc:206,frac12:189,loz:9674,rarr:8594,cup:8746,radic:8730,frasl:8260,euml:235,OElig:338,hArr:8660,Atilde:195,Upsilon:933,there4:8756,ouml:246,oline:8254,Ecirc:202,yacute:253,auml:228,permil:8240,sigmaf:962,iquest:191,empty:8709,pi:960,Ucirc:219,supe:8839,Igrave:204,yen:165,rang:10217,trade:8482,lfloor:8970,minus:8722,Zeta:918,sub:8834,epsilon:949,yuml:255,Sigma:931,Iuml:207,ocirc:244};
1520
+ self.events.bind("getContent", function (text) {
1521
+ return text.replace(/&(?:amp;)?(?!amp|lt|gt|quot)([a-z][a-z0-9]*);/gi, function (str, p1) {
1522
+ if (!replacements[p1]) {
1523
+ p1 = p1.toLowerCase();
1524
+ if (!replacements[p1]) {
1525
+ p1 = "__replacement";
1526
+ }
1527
+ }
1528
+
1529
+ var num = replacements[p1];
1530
+ /* Numeric return if ever wanted: return replacements[p1] ? "&#"+num+";" : ""; */
1531
+ return String.fromCharCode(num);
1532
+ });
1533
+ });
1534
+ }
1535
+ $(self.original).trigger('ready.jwysiwyg', [self.editorDoc, self]);
1536
+ };
1537
+
1538
+ this.innerDocument = function () {
1539
+ var element = this.editor.get(0);
1540
+
1541
+ if (element.nodeName.toLowerCase() === "iframe") {
1542
+ if (element.contentDocument) { // Gecko
1543
+ return element.contentDocument;
1544
+ } else if (element.contentWindow) { // IE
1545
+ return element.contentWindow.document;
1546
+ }
1547
+
1548
+ if (this.isDestroyed) {
1549
+ return null;
1550
+ }
1551
+
1552
+ console.error("Unexpected error in innerDocument");
1553
+
1554
+ /*
1555
+ return ( $.browser.msie )
1556
+ ? document.frames[element.id].document
1557
+ : element.contentWindow.document // contentDocument;
1558
+ */
1559
+ }
1560
+
1561
+ return element;
1562
+ };
1563
+
1564
+ this.insertHtml = function (szHTML) {
1565
+ var img, range;
1566
+
1567
+ if (!szHTML || szHTML.length === 0) {
1568
+ return this;
1569
+ }
1570
+
1571
+ if ($.browser.msie) {
1572
+ this.ui.focus();
1573
+ this.editorDoc.execCommand("insertImage", false, "#jwysiwyg#");
1574
+ img = this.getElementByAttributeValue("img", "src", "#jwysiwyg#");
1575
+ if (img) {
1576
+ $(img).replaceWith(szHTML);
1577
+ }
1578
+ } else {
1579
+ if ($.browser.mozilla) { // @link https://github.com/akzhan/jwysiwyg/issues/50
1580
+ if (1 === $(szHTML).length) {
1581
+ range = this.getInternalRange();
1582
+ range.deleteContents();
1583
+ range.insertNode($(szHTML).get(0));
1584
+ } else {
1585
+ this.editorDoc.execCommand("insertHTML", false, szHTML);
1586
+ }
1587
+ } else {
1588
+ if (!this.editorDoc.execCommand("insertHTML", false, szHTML)) {
1589
+ this.editor.focus();
1590
+ /* :TODO: place caret at the end
1591
+ if (window.getSelection) {
1592
+ } else {
1593
+ }
1594
+ this.editor.focus();
1595
+ */
1596
+ this.editorDoc.execCommand("insertHTML", false, szHTML);
1597
+ }
1598
+ }
1599
+ }
1600
+
1601
+ this.saveContent();
1602
+
1603
+ return this;
1604
+ };
1605
+
1606
+ this.parseControls = function () {
1607
+ var self = this;
1608
+
1609
+ $.each(this.options.controls, function (controlName, control) {
1610
+ $.each(control, function (propertyName) {
1611
+ if (-1 === $.inArray(propertyName, self.availableControlProperties)) {
1612
+ throw controlName + '["' + propertyName + '"]: property "' + propertyName + '" not exists in Wysiwyg.availableControlProperties';
1613
+ }
1614
+ });
1615
+ });
1616
+
1617
+ if (this.options.parseControls) {
1618
+ return this.options.parseControls.call(this);
1619
+ }
1620
+
1621
+ return this.options.controls;
1622
+ };
1623
+
1624
+ this.removeFormat = function () {
1625
+ if ($.browser.msie) {
1626
+ this.ui.focus();
1627
+ }
1628
+
1629
+ if (this.options.removeHeadings) {
1630
+ this.editorDoc.execCommand("formatBlock", false, "<p>"); // remove headings
1631
+ }
1632
+
1633
+ this.editorDoc.execCommand("removeFormat", false, null);
1634
+ this.editorDoc.execCommand("unlink", false, null);
1635
+
1636
+ if ($.wysiwyg.rmFormat && $.wysiwyg.rmFormat.enabled) {
1637
+ if ("object" === typeof (this.options.plugins.rmFormat.rmMsWordMarkup)) {
1638
+ $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: this.options.plugins.rmFormat.rmMsWordMarkup }});
1639
+ } else {
1640
+ $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: { enabled: true }}});
1641
+ }
1642
+ }
1643
+
1644
+ return this;
1645
+ };
1646
+
1647
+ this.ui.removeHoverClass = function () {
1648
+ $(this).removeClass("wysiwyg-button-hover");
1649
+ };
1650
+
1651
+ this.resetFunction = function () {
1652
+ this.setContent(this.initialContent);
1653
+ };
1654
+
1655
+ this.saveContent = function () {
1656
+ if (this.viewHTML)
1657
+ {
1658
+ return; // no need
1659
+ }
1660
+ if (this.original) {
1661
+ var content, newContent;
1662
+
1663
+ content = this.getContent();
1664
+
1665
+ if (this.options.rmUnwantedBr) {
1666
+ content = content.replace(/<br\/?>$/, "");
1667
+ }
1668
+
1669
+ if (this.options.replaceDivWithP) {
1670
+ newContent = $("<div/>").addClass("temp").append(content);
1671
+
1672
+ newContent.children("div").each(function () {
1673
+ var element = $(this), p = element.find("p"), i;
1674
+
1675
+ if (0 === p.length) {
1676
+ p = $("<p></p>");
1677
+
1678
+ if (this.attributes.length > 0) {
1679
+ for (i = 0; i < this.attributes.length; i += 1) {
1680
+ p.attr(this.attributes[i].name, element.attr(this.attributes[i].name));
1681
+ }
1682
+ }
1683
+
1684
+ p.append(element.html());
1685
+
1686
+ element.replaceWith(p);
1687
+ }
1688
+ });
1689
+
1690
+ content = newContent.html();
1691
+ }
1692
+
1693
+ $(this.original).val(content);
1694
+
1695
+ if (this.options.events && this.options.events.save) {
1696
+ this.options.events.save.call(this);
1697
+ }
1698
+ }
1699
+
1700
+ return this;
1701
+ };
1702
+
1703
+ this.setContent = function (newContent) {
1704
+ this.editorDoc.body.innerHTML = newContent;
1705
+ this.saveContent();
1706
+
1707
+ return this;
1708
+ };
1709
+
1710
+ this.triggerControl = function (name, control) {
1711
+ var cmd = control.command || name,
1712
+ args = control["arguments"] || [];
1713
+
1714
+ if (control.exec) {
1715
+ control.exec.apply(this);
1716
+ } else {
1717
+ this.ui.focus();
1718
+ this.ui.withoutCss();
1719
+ // when click <Cut>, <Copy> or <Paste> got "Access to XPConnect service denied" code: "1011"
1720
+ // in Firefox untrusted JavaScript is not allowed to access the clipboard
1721
+ try {
1722
+ this.editorDoc.execCommand(cmd, false, args);
1723
+ } catch (e) {
1724
+ console.error(e);
1725
+ }
1726
+ }
1727
+
1728
+ if (this.options.autoSave) {
1729
+ this.autoSaveFunction();
1730
+ }
1731
+ };
1732
+
1733
+ this.triggerControlCallback = function (name) {
1734
+ $(window).trigger("trigger-" + name + ".wysiwyg", [this]);
1735
+ };
1736
+
1737
+ this.ui.withoutCss = function () {
1738
+ var self = this.self;
1739
+
1740
+ if ($.browser.mozilla) {
1741
+ try {
1742
+ self.editorDoc.execCommand("styleWithCSS", false, false);
1743
+ } catch (e) {
1744
+ try {
1745
+ self.editorDoc.execCommand("useCSS", false, true);
1746
+ } catch (e2) {
1747
+ }
1748
+ }
1749
+ }
1750
+
1751
+ return self;
1752
+ };
1753
+
1754
+ this.wrapInitialContent = function () {
1755
+ var content = this.initialContent,
1756
+ found = content.match(/<\/?p>/gi);
1757
+
1758
+ if (!found) {
1759
+ return "<p>" + content + "</p>";
1760
+ } else {
1761
+ // :TODO: checking/replacing
1762
+ }
1763
+
1764
+ return content;
1765
+ };
1766
+ }
1767
+
1768
+ /*
1769
+ * Wysiwyg namespace: public properties and methods
1770
+ */
1771
+ $.wysiwyg = {
1772
+ messages: {
1773
+ noObject: "Something goes wrong, check object"
1774
+ },
1775
+
1776
+ /**
1777
+ * Custom control support by Alec Gorge ( http://github.com/alecgorge )
1778
+ */
1779
+ addControl: function (object, name, settings) {
1780
+ return object.each(function () {
1781
+ var oWysiwyg = $(this).data("wysiwyg"),
1782
+ customControl = {},
1783
+ toolbar;
1784
+
1785
+ if (!oWysiwyg) {
1786
+ return this;
1787
+ }
1788
+
1789
+ customControl[name] = $.extend(true, {visible: true, custom: true}, settings);
1790
+ $.extend(true, oWysiwyg.options.controls, customControl);
1791
+
1792
+ // render new toolbar
1793
+ toolbar = $(oWysiwyg.options.toolbarHtml);
1794
+ oWysiwyg.ui.toolbar.replaceWith(toolbar);
1795
+ oWysiwyg.ui.toolbar = toolbar;
1796
+ oWysiwyg.ui.appendControls();
1797
+ });
1798
+ },
1799
+
1800
+ clear: function (object) {
1801
+ return object.each(function () {
1802
+ var oWysiwyg = $(this).data("wysiwyg");
1803
+
1804
+ if (!oWysiwyg) {
1805
+ return this;
1806
+ }
1807
+
1808
+ oWysiwyg.setContent("");
1809
+ });
1810
+ },
1811
+
1812
+ console: console, // let our console be available for extensions
1813
+
1814
+ destroy: function (object) {
1815
+ return object.each(function () {
1816
+ var oWysiwyg = $(this).data("wysiwyg");
1817
+
1818
+ if (!oWysiwyg) {
1819
+ return this;
1820
+ }
1821
+
1822
+ oWysiwyg.destroy();
1823
+ });
1824
+ },
1825
+
1826
+ "document": function (object) {
1827
+ // no chains because of return
1828
+ var oWysiwyg = object.data("wysiwyg");
1829
+
1830
+ if (!oWysiwyg) {
1831
+ return undefined;
1832
+ }
1833
+
1834
+ return $(oWysiwyg.editorDoc);
1835
+ },
1836
+
1837
+ getContent: function (object) {
1838
+ // no chains because of return
1839
+ var oWysiwyg = object.data("wysiwyg");
1840
+
1841
+ if (!oWysiwyg) {
1842
+ return undefined;
1843
+ }
1844
+
1845
+ return oWysiwyg.getContent();
1846
+ },
1847
+
1848
+ init: function (object, options) {
1849
+ return object.each(function () {
1850
+ var opts = $.extend(true, {}, options),
1851
+ obj;
1852
+
1853
+ // :4fun:
1854
+ // remove this textarea validation and change line in this.saveContent function
1855
+ // $(this.original).val(content); to $(this.original).html(content);
1856
+ // now you can make WYSIWYG editor on h1, p, and many more tags
1857
+ if (("textarea" !== this.nodeName.toLowerCase()) || $(this).data("wysiwyg")) {
1858
+ return;
1859
+ }
1860
+
1861
+ obj = new Wysiwyg();
1862
+ obj.init(this, opts);
1863
+ $.data(this, "wysiwyg", obj);
1864
+
1865
+ $(obj.editorDoc).trigger("afterInit.wysiwyg");
1866
+ });
1867
+ },
1868
+
1869
+ insertHtml: function (object, szHTML) {
1870
+ return object.each(function () {
1871
+ var oWysiwyg = $(this).data("wysiwyg");
1872
+
1873
+ if (!oWysiwyg) {
1874
+ return this;
1875
+ }
1876
+
1877
+ oWysiwyg.insertHtml(szHTML);
1878
+ });
1879
+ },
1880
+
1881
+ plugin: {
1882
+ listeners: {},
1883
+
1884
+ bind: function (Wysiwyg) {
1885
+ var self = this;
1886
+
1887
+ $.each(this.listeners, function (action, handlers) {
1888
+ var i, plugin;
1889
+
1890
+ for (i = 0; i < handlers.length; i += 1) {
1891
+ plugin = self.parseName(handlers[i]);
1892
+
1893
+ $(Wysiwyg.editorDoc).bind(action + ".wysiwyg", {plugin: plugin}, function (event) {
1894
+ $.wysiwyg[event.data.plugin.name][event.data.plugin.method].apply($.wysiwyg[event.data.plugin.name], [Wysiwyg]);
1895
+ });
1896
+ }
1897
+ });
1898
+ },
1899
+
1900
+ exists: function (name) {
1901
+ var plugin;
1902
+
1903
+ if ("string" !== typeof (name)) {
1904
+ return false;
1905
+ }
1906
+
1907
+ plugin = this.parseName(name);
1908
+
1909
+ if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) {
1910
+ return false;
1911
+ }
1912
+
1913
+ return true;
1914
+ },
1915
+
1916
+ listen: function (action, handler) {
1917
+ var plugin;
1918
+
1919
+ plugin = this.parseName(handler);
1920
+
1921
+ if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) {
1922
+ return false;
1923
+ }
1924
+
1925
+ if (!this.listeners[action]) {
1926
+ this.listeners[action] = [];
1927
+ }
1928
+
1929
+ this.listeners[action].push(handler);
1930
+
1931
+ return true;
1932
+ },
1933
+
1934
+ parseName: function (name) {
1935
+ var elements;
1936
+
1937
+ if ("string" !== typeof (name)) {
1938
+ return false;
1939
+ }
1940
+
1941
+ elements = name.split(".");
1942
+
1943
+ if (2 > elements.length) {
1944
+ return false;
1945
+ }
1946
+
1947
+ return {name: elements[0], method: elements[1]};
1948
+ },
1949
+
1950
+ register: function (data) {
1951
+ if (!data.name) {
1952
+ console.error("Plugin name missing");
1953
+ }
1954
+
1955
+ $.each($.wysiwyg, function (pluginName) {
1956
+ if (pluginName === data.name) {
1957
+ console.error("Plugin with name '" + data.name + "' was already registered");
1958
+ }
1959
+ });
1960
+
1961
+ $.wysiwyg[data.name] = data;
1962
+
1963
+ return true;
1964
+ }
1965
+ },
1966
+
1967
+ removeFormat: function (object) {
1968
+ return object.each(function () {
1969
+ var oWysiwyg = $(this).data("wysiwyg");
1970
+
1971
+ if (!oWysiwyg) {
1972
+ return this;
1973
+ }
1974
+
1975
+ oWysiwyg.removeFormat();
1976
+ });
1977
+ },
1978
+
1979
+ save: function (object) {
1980
+ return object.each(function () {
1981
+ var oWysiwyg = $(this).data("wysiwyg");
1982
+
1983
+ if (!oWysiwyg) {
1984
+ return this;
1985
+ }
1986
+
1987
+ oWysiwyg.saveContent();
1988
+ });
1989
+ },
1990
+
1991
+ selectAll: function (object) {
1992
+ var oWysiwyg = object.data("wysiwyg"), oBody, oRange, selection;
1993
+
1994
+ if (!oWysiwyg) {
1995
+ return this;
1996
+ }
1997
+
1998
+ oBody = oWysiwyg.editorDoc.body;
1999
+ if (window.getSelection) {
2000
+ selection = oWysiwyg.getInternalSelection();
2001
+ selection.selectAllChildren(oBody);
2002
+ } else {
2003
+ oRange = oBody.createTextRange();
2004
+ oRange.moveToElementText(oBody);
2005
+ oRange.select();
2006
+ }
2007
+ },
2008
+
2009
+ setContent: function (object, newContent) {
2010
+ return object.each(function () {
2011
+ var oWysiwyg = $(this).data("wysiwyg");
2012
+
2013
+ if (!oWysiwyg) {
2014
+ return this;
2015
+ }
2016
+
2017
+ oWysiwyg.setContent(newContent);
2018
+ });
2019
+ },
2020
+
2021
+ triggerControl: function (object, controlName) {
2022
+ return object.each(function () {
2023
+ var oWysiwyg = $(this).data("wysiwyg");
2024
+
2025
+ if (!oWysiwyg) {
2026
+ return this;
2027
+ }
2028
+
2029
+ if (!oWysiwyg.controls[controlName]) {
2030
+ console.error("Control '" + controlName + "' not exists");
2031
+ }
2032
+
2033
+ oWysiwyg.triggerControl.apply(oWysiwyg, [controlName, oWysiwyg.controls[controlName]]);
2034
+ });
2035
+ },
2036
+
2037
+ support: {
2038
+ prop: supportsProp
2039
+ },
2040
+
2041
+ utils: {
2042
+ extraSafeEntities: [["<", ">", "'", '"', " "], [32]],
2043
+
2044
+ encodeEntities: function (str) {
2045
+ var self = this, aStr, aRet = [];
2046
+
2047
+ if (this.extraSafeEntities[1].length === 0) {
2048
+ $.each(this.extraSafeEntities[0], function (i, ch) {
2049
+ self.extraSafeEntities[1].push(ch.charCodeAt(0));
2050
+ });
2051
+ }
2052
+ aStr = str.split("");
2053
+ $.each(aStr, function (i) {
2054
+ var iC = aStr[i].charCodeAt(0);
2055
+ if ($.inArray(iC, self.extraSafeEntities[1]) && (iC < 65 || iC > 127 || (iC > 90 && iC < 97))) {
2056
+ aRet.push('&#' + iC + ';');
2057
+ } else {
2058
+ aRet.push(aStr[i]);
2059
+ }
2060
+ });
2061
+
2062
+ return aRet.join('');
2063
+ }
2064
+ }
2065
+ };
2066
+
2067
+ /**
2068
+ * Unifies dialog methods to allow custom implementations
2069
+ *
2070
+ * Events:
2071
+ * * afterOpen
2072
+ * * beforeShow
2073
+ * * afterShow
2074
+ * * beforeHide
2075
+ * * afterHide
2076
+ * * beforeClose
2077
+ * * afterClose
2078
+ *
2079
+ * Example:
2080
+ * var dialog = new ($.wysiwyg.dialog)($('#idToTextArea').data('wysiwyg'), {"title": "Test", "content": "form data, etc."});
2081
+ *
2082
+ * dialog.bind("afterOpen", function () { alert('you should see a dialog behind this one!'); });
2083
+ *
2084
+ * dialog.open();
2085
+ *
2086
+ *
2087
+ */
2088
+ $.wysiwyg.dialog = function (jWysiwyg, opts) {
2089
+
2090
+ var theme = (jWysiwyg && jWysiwyg.options && jWysiwyg.options.dialog) ? jWysiwyg.options.dialog : (opts.theme ? opts.theme : "default"),
2091
+ obj = new $.wysiwyg.dialog.createDialog(theme),
2092
+ that = this,
2093
+ $that = $(that);
2094
+
2095
+ this.options = {
2096
+ "modal": true,
2097
+ "draggable": true,
2098
+ "title": "Title",
2099
+ "content": "Content",
2100
+ "width":"auto",
2101
+ "height":"auto",
2102
+ "open": false,
2103
+ "close": false
2104
+ };
2105
+
2106
+ this.isOpen = false;
2107
+
2108
+ $.extend(this.options, opts);
2109
+
2110
+ this.object = obj;
2111
+
2112
+ // Opens a dialog with the specified content
2113
+ this.open = function () {
2114
+ this.isOpen = true;
2115
+
2116
+ obj.init.apply(that, []);
2117
+ var $dialog = obj.show.apply(that, []);
2118
+
2119
+ $that.trigger("afterOpen", [$dialog]);
2120
+
2121
+ };
2122
+
2123
+ this.show = function () {
2124
+ this.isOpen = true;
2125
+
2126
+ $that.trigger("beforeShow");
2127
+
2128
+ var $dialog = obj.show.apply(that, []);
2129
+
2130
+ $that.trigger("afterShow");
2131
+ };
2132
+
2133
+ this.hide = function () {
2134
+ this.isOpen = false;
2135
+
2136
+ $that.trigger("beforeHide");
2137
+
2138
+ var $dialog = obj.hide.apply(that, []);
2139
+
2140
+ $that.trigger("afterHide", [$dialog]);
2141
+ };
2142
+
2143
+ // Closes the dialog window.
2144
+ this.close = function () {
2145
+ this.isOpen = false;
2146
+
2147
+ var $dialog = obj.hide.apply(that, []);
2148
+
2149
+ $that.trigger("beforeClose", [$dialog]);
2150
+
2151
+ obj.destroy.apply(that, []);
2152
+
2153
+ $that.trigger("afterClose", [$dialog]);
2154
+
2155
+ };
2156
+
2157
+ if (this.options.open) {
2158
+ $that.bind("afterOpen", this.options.open);
2159
+ }
2160
+ if (this.options.close) {
2161
+ $that.bind("afterClose", this.options.close);
2162
+ }
2163
+
2164
+ return this;
2165
+ };
2166
+
2167
+ // "Static" Dialog methods.
2168
+ $.extend(true, $.wysiwyg.dialog, {
2169
+ _themes : {}, // sample {"Theme Name": object}
2170
+ _theme : "", // the current theme
2171
+
2172
+ register : function(name, obj) {
2173
+ $.wysiwyg.dialog._themes[name] = obj;
2174
+ },
2175
+
2176
+ deregister : function (name) {
2177
+ delete $.wysiwyg.dialog._themes[name];
2178
+ },
2179
+
2180
+ createDialog : function (name) {
2181
+ return new ($.wysiwyg.dialog._themes[name]);
2182
+ }
2183
+ });
2184
+
2185
+ $(function () { // need access to jQuery UI stuff.
2186
+ if (jQuery.ui) {
2187
+ $.wysiwyg.dialog.register("jqueryui", function () {
2188
+ var that = this;
2189
+
2190
+ this._$dialog = null;
2191
+
2192
+ this.init = function() {
2193
+ var abstractDialog = this,
2194
+ content = this.options.content;
2195
+
2196
+ if (typeof content === 'object') {
2197
+ if (typeof content.html === 'function') {
2198
+ content = content.html();
2199
+ } else if(typeof content.toString === 'function') {
2200
+ content = content.toString();
2201
+ }
2202
+ }
2203
+
2204
+ that._$dialog = $('<div></div>').attr('title', this.options.title).html(content);
2205
+
2206
+ var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height,
2207
+ dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
2208
+
2209
+ // console.log(that._$dialog);
2210
+
2211
+ that._$dialog.dialog({
2212
+ modal: this.options.modal,
2213
+ draggable: this.options.draggable,
2214
+ height: dialogHeight,
2215
+ width: dialogWidth
2216
+ });
2217
+
2218
+ return that._$dialog;
2219
+ };
2220
+
2221
+ this.show = function () {
2222
+ that._$dialog.dialog("open");
2223
+ return that._$dialog;
2224
+ };
2225
+
2226
+ this.hide = function () {
2227
+ that._$dialog.dialog("close");
2228
+ return that._$dialog;
2229
+ };
2230
+
2231
+ this.destroy = function() {
2232
+ that._$dialog.dialog("destroy");
2233
+ return that._$dialog;
2234
+ };
2235
+ });
2236
+ }
2237
+
2238
+ $.wysiwyg.dialog.register("default", function () {
2239
+ var that = this;
2240
+
2241
+ this._$dialog = null;
2242
+
2243
+ this.init = function() {
2244
+ var abstractDialog = this,
2245
+ content = this.options.content;
2246
+
2247
+ if (typeof content === 'object') {
2248
+ if(typeof content.html === 'function') {
2249
+ content = content.html();
2250
+ }
2251
+ else if(typeof content.toString === 'function') {
2252
+ content = content.toString();
2253
+ }
2254
+ }
2255
+
2256
+ that._$dialog = $('<div class="wysiwyg-dialog"></div>');
2257
+
2258
+ var $topbar = $('<div class="wysiwyg-dialog-topbar"><div class="wysiwyg-dialog-close-wrapper"></div><div class="wysiwyg-dialog-title">'+this.options.title+'</div></div>');
2259
+ var $link = $('<a href="#" class="wysiwyg-dialog-close-button">X</a>');
2260
+
2261
+ $link.click(function () {
2262
+ abstractDialog.close(); // this is important it makes sure that is close from the abstract $.wysiwyg.dialog instace, not just locally
2263
+ });
2264
+
2265
+ $topbar.find('.wysiwyg-dialog-close-wrapper').prepend($link);
2266
+
2267
+ var $dcontent = $('<div class="wysiwyg-dialog-content">'+content+'</div>');
2268
+
2269
+ that._$dialog.append($topbar).append($dcontent);
2270
+
2271
+ // Set dialog's height & width, and position it correctly:
2272
+ var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height,
2273
+ dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
2274
+ that._$dialog.hide().css({
2275
+ "width": dialogWidth,
2276
+ "height": dialogHeight,
2277
+ "left": (($(window).width() - dialogWidth) / 2),
2278
+ "top": (($(window).height() - dialogHeight) / 3)
2279
+ });
2280
+
2281
+ $("body").append(that._$dialog);
2282
+
2283
+ return that._$dialog;
2284
+ };
2285
+
2286
+ this.show = function () {
2287
+
2288
+ // Modal feature:
2289
+ if (this.options.modal) {
2290
+ that._$dialog.wrap('<div class="wysiwyg-dialog-modal-div"></div>');
2291
+ }
2292
+
2293
+ // Draggable feature:
2294
+ if (this.options.draggable) {
2295
+
2296
+ var mouseDown = false;
2297
+
2298
+ that._$dialog.find("div.wysiwyg-dialog-topbar").bind("mousedown", function (e) {
2299
+ e.preventDefault();
2300
+ $(this).css({ "cursor": "move" });
2301
+ var $topbar = $(this),
2302
+ _dialog = $(this).parents(".wysiwyg-dialog"),
2303
+ offsetX = (e.pageX - parseInt(_dialog.css("left"), 10)),
2304
+ offsetY = (e.pageY - parseInt(_dialog.css("top"), 10));
2305
+ mouseDown = true;
2306
+ $(this).css({ "cursor": "move" });
2307
+
2308
+ $(document).bind("mousemove", function (e) {
2309
+ e.preventDefault();
2310
+ if (mouseDown) {
2311
+ _dialog.css({
2312
+ "top": (e.pageY - offsetY),
2313
+ "left": (e.pageX - offsetX)
2314
+ });
2315
+ }
2316
+ }).bind("mouseup", function (e) {
2317
+ e.preventDefault();
2318
+ mouseDown = false;
2319
+ $topbar.css({ "cursor": "auto" });
2320
+ $(document).unbind("mousemove").unbind("mouseup");
2321
+ });
2322
+
2323
+ });
2324
+ }
2325
+
2326
+ that._$dialog.show();
2327
+ return that._$dialog;
2328
+
2329
+ };
2330
+
2331
+ this.hide = function () {
2332
+ that._$dialog.hide();
2333
+ return that._$dialog;
2334
+ };
2335
+
2336
+ this.destroy = function() {
2337
+
2338
+ // Modal feature:
2339
+ if (this.options.modal) {
2340
+ that._$dialog.unwrap();
2341
+ }
2342
+
2343
+ // Draggable feature:
2344
+ if (this.options.draggable) {
2345
+ that._$dialog.find("div.wysiwyg-dialog-topbar").unbind("mousedown");
2346
+ }
2347
+
2348
+ that._$dialog.remove();
2349
+ return that._$dialog;
2350
+ };
2351
+ });
2352
+ });
2353
+ // end Dialog
2354
+
2355
+ $.fn.wysiwyg = function (method) {
2356
+ var args = arguments, plugin;
2357
+
2358
+ if ("undefined" !== typeof $.wysiwyg[method]) {
2359
+ // set argument object to undefined
2360
+ args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1));
2361
+ return $.wysiwyg[method].apply($.wysiwyg, Array.prototype.slice.call(args, 1));
2362
+ } else if ("object" === typeof method || !method) {
2363
+ Array.prototype.unshift.call(args, this);
2364
+ return $.wysiwyg.init.apply($.wysiwyg, args);
2365
+ } else if ($.wysiwyg.plugin.exists(method)) {
2366
+ plugin = $.wysiwyg.plugin.parseName(method);
2367
+ args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1));
2368
+ return $.wysiwyg[plugin.name][plugin.method].apply($.wysiwyg[plugin.name], Array.prototype.slice.call(args, 1));
2369
+ } else {
2370
+ console.error("Method '" + method + "' does not exist on jQuery.wysiwyg.\nTry to include some extra controls or plugins");
2371
+ }
2372
+ };
2373
+
2374
+ $.fn.getWysiwyg = function () {
2375
+ return $.data(this, "wysiwyg");
2376
+ };
2377
+ })(jQuery);