rails-redactorjs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +53 -0
  5. data/Rakefile +2 -0
  6. data/lib/rails-redactorjs.rb +14 -0
  7. data/lib/rails-redactorjs/configuration.rb +54 -0
  8. data/lib/rails-redactorjs/engine.rb +11 -0
  9. data/lib/rails-redactorjs/helper.rb +15 -0
  10. data/lib/rails-redactorjs/version.rb +5 -0
  11. data/rails-redactorjs.gemspec +17 -0
  12. data/vendor/assets/javascripts/rails-redactorjs/css/docstyle.css +123 -0
  13. data/vendor/assets/javascripts/rails-redactorjs/css/style.css +119 -0
  14. data/vendor/assets/javascripts/rails-redactorjs/css/wym.css +136 -0
  15. data/vendor/assets/javascripts/rails-redactorjs/index.js +1 -0
  16. data/vendor/assets/javascripts/rails-redactorjs/langs/by.js +72 -0
  17. data/vendor/assets/javascripts/rails-redactorjs/langs/de.js +75 -0
  18. data/vendor/assets/javascripts/rails-redactorjs/langs/en.js +76 -0
  19. data/vendor/assets/javascripts/rails-redactorjs/langs/es.js +76 -0
  20. data/vendor/assets/javascripts/rails-redactorjs/langs/fr.js +74 -0
  21. data/vendor/assets/javascripts/rails-redactorjs/langs/hu.js +76 -0
  22. data/vendor/assets/javascripts/rails-redactorjs/langs/it.js +76 -0
  23. data/vendor/assets/javascripts/rails-redactorjs/langs/ja.js +76 -0
  24. data/vendor/assets/javascripts/rails-redactorjs/langs/lv.js +74 -0
  25. data/vendor/assets/javascripts/rails-redactorjs/langs/nl.js +76 -0
  26. data/vendor/assets/javascripts/rails-redactorjs/langs/pl.js +75 -0
  27. data/vendor/assets/javascripts/rails-redactorjs/langs/pt_br.js +81 -0
  28. data/vendor/assets/javascripts/rails-redactorjs/langs/ru.js +75 -0
  29. data/vendor/assets/javascripts/rails-redactorjs/langs/sq.js +76 -0
  30. data/vendor/assets/javascripts/rails-redactorjs/langs/tr.js +76 -0
  31. data/vendor/assets/javascripts/rails-redactorjs/langs/ua.js +75 -0
  32. data/vendor/assets/javascripts/rails-redactorjs/langs/zh_cn.js +77 -0
  33. data/vendor/assets/javascripts/rails-redactorjs/langs/zh_tw.js +76 -0
  34. data/vendor/assets/javascripts/rails-redactorjs/plugins/file.html +3 -0
  35. data/vendor/assets/javascripts/rails-redactorjs/plugins/image.html +39 -0
  36. data/vendor/assets/javascripts/rails-redactorjs/plugins/image_edit.html +35 -0
  37. data/vendor/assets/javascripts/rails-redactorjs/plugins/link.html +74 -0
  38. data/vendor/assets/javascripts/rails-redactorjs/plugins/table.html +25 -0
  39. data/vendor/assets/javascripts/rails-redactorjs/plugins/video.html +15 -0
  40. data/vendor/assets/javascripts/rails-redactorjs/redactor.js +2259 -0
  41. data/vendor/assets/javascripts/rails-redactorjs/redactor.min.js +1 -0
  42. data/vendor/assets/javascripts/rails-redactorjs/toolbars/default.js +214 -0
  43. data/vendor/assets/javascripts/rails-redactorjs/toolbars/mini.js +103 -0
  44. data/vendor/assets/stylesheets/rails-redactorjs/css/redactor.css +368 -0
  45. data/vendor/assets/stylesheets/rails-redactorjs/img/icons.png +0 -0
  46. data/vendor/assets/stylesheets/rails-redactorjs/index.css +1 -0
  47. metadata +95 -0
@@ -0,0 +1,76 @@
1
+ var RLANG = {
2
+ html: '原始碼',
3
+ video: '影片',
4
+ image: '圖片',
5
+ table: '表格',
6
+ link: '超連結',
7
+ link_insert: '插入超連結',
8
+ unlink: '取消超連結',
9
+ styles: '樣式',
10
+ paragraph: '段落',
11
+ quote: '引用',
12
+ code: '程式碼',
13
+ header1: '標題 1',
14
+ header2: '標題 2',
15
+ header3: '標題 3',
16
+ header4: '標題 4',
17
+ format: '格式',
18
+ bold: '粗體',
19
+ italic: '斜體',
20
+ superscript: '上標',
21
+ strikethrough: '刪除線',
22
+ fontcolor: '字體顏色',
23
+ backcolor: '背景顏色',
24
+ removeformat: '取消格式',
25
+ cleanstyles: '清除樣式',
26
+ lists: '列表',
27
+ unorderedlist: '項號編號',
28
+ orderedlist: '數字編號',
29
+ outdent: '減少縮排',
30
+ indent: '增加縮排',
31
+ redo: '取消復原',
32
+ undo: '復原',
33
+ cut: '剪下',
34
+ cancel: '取消',
35
+ insert: '貼上',
36
+ save: '儲存',
37
+ _delete: '刪除',
38
+ insert_table: '插入表格',
39
+ insert_row_above: '從上方插入',
40
+ insert_row_below: '從下方插入',
41
+ insert_column_left: '從左側插入',
42
+ insert_column_right: '從右側插入',
43
+ delete_column: '刪除整列',
44
+ delete_row: '刪除整行',
45
+ delete_table: '刪除表格',
46
+ Rows: '行',
47
+ Columns: '列',
48
+ add_head: '新增標題',
49
+ delete_head: '刪除標題',
50
+ title: '標題',
51
+ image_view: '圖片內容',
52
+ image_position: '位置',
53
+ none: '無',
54
+ left: '左',
55
+ right: '右',
56
+ image_web_link: '圖片路徑',
57
+ text: '文字',
58
+ mailto: '電子郵件信箱',
59
+ web: '網址',
60
+ video_html_code: '影片嵌入程式碼',
61
+ file: '檔案',
62
+ upload: '上傳',
63
+ download: '下載',
64
+ choose: '選擇',
65
+ or_choose: '或選擇',
66
+ drop_file_here: '把檔案拖曳到這邊',
67
+ align_left: '靠左對齊',
68
+ align_center: '文字置中',
69
+ align_right: '靠右對齊',
70
+ align_justify: '左右對齊',
71
+ horizontalrule: '水平線',
72
+ fullscreen: '全螢幕',
73
+ deleted: '刪除線',
74
+ none: '無',
75
+ anchor: '錨點'
76
+ };
@@ -0,0 +1,3 @@
1
+ <form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">
2
+ <input type="file" id="redactor_file" name="file" />
3
+ </form>
@@ -0,0 +1,39 @@
1
+ <div id="redactor_tabs">
2
+ <a href="javascript:void(null);" class="redactor_tabs_act">%RLANG.upload%</a>
3
+ <a href="javascript:void(null);">%RLANG.choose%</a>
4
+ <a href="javascript:void(null);">%RLANG.link%</a>
5
+ </div>
6
+
7
+
8
+ <form id="redactorInsertImageForm" method="post" action="" enctype="multipart/form-data">
9
+ <div id="redactor_tab1" class="redactor_tab">
10
+ <input type="file" id="redactor_file" name="file" />
11
+ </div>
12
+ <div id="redactor_tab2" class="redactor_tab" style="display: none;">
13
+ <div id="redactor_image_box"></div>
14
+ </div>
15
+ </form>
16
+
17
+
18
+ <div id="redactor_tab3" class="redactor_tab" style="display: none;">
19
+ <table class="redactor_ruler" width="100%">
20
+ <tr>
21
+ <td nowrap>%RLANG.image_web_link%</td>
22
+ <td width="100%"><input name="redactor_file_link" id="redactor_file_link" style="width: 99%" /></td>
23
+ </tr>
24
+ <tr>
25
+ <td></td>
26
+ <td>
27
+
28
+ <span class="redactor_btns_box">
29
+ <input type="button" name="upload" id="redactor_upload_btn" value="%RLANG.insert%" />&nbsp;&nbsp;
30
+ <a href="javascript:void(null);" style="color: #777; font-size: 12px;" id="redactor_btn_modal_close">%RLANG.cancel%</a>
31
+ </span>
32
+ <div style="clear: both;"></div>
33
+
34
+ </td>
35
+ </tr>
36
+
37
+ </table>
38
+ </div>
39
+
@@ -0,0 +1,35 @@
1
+
2
+ <table class="redactor_ruler">
3
+ <tr>
4
+ <td nowrap>%RLANG.title%</td>
5
+ <td><input id="redactor_file_alt" style="width: 99%;" /></td>
6
+ </tr>
7
+ <tr>
8
+ <td nowrap>%RLANG.link%</td>
9
+ <td><input id="redactor_file_link" style="width: 99%;" /></td>
10
+ </tr>
11
+ <tr>
12
+ <td nowrap class="small">%RLANG.image_position%</td>
13
+ <td width="100%">
14
+ <select id="redactor_form_image_align">
15
+ <option value="none">%RLANG.none%</option>
16
+ <option value="left">%RLANG.left%</option>
17
+ <option value="right">%RLANG.right%</option>
18
+ </select>
19
+ </td>
20
+ </tr>
21
+ <tr>
22
+ <td><a href="javascript:void(null);" id="redactor_image_delete_btn" style="color: #000;">%RLANG._delete%</a></td>
23
+ <td>
24
+
25
+ <span class="redactor_btns_box">
26
+ <input type="button" name="save" id="redactorSaveBtn" value="%RLANG.save%" />&nbsp;&nbsp;
27
+ <a href="javascript:void(null);" style="color: #777; font-size: 12px;" id="redactor_btn_modal_close">%RLANG.cancel%</a>
28
+ </span>
29
+ <div style="clear: both;"></div>
30
+
31
+ </td>
32
+ </tr>
33
+ </table>
34
+
35
+
@@ -0,0 +1,74 @@
1
+ <form id="redactorInsertLinkForm" method="post" action="" enctype="multipart/form-data">
2
+
3
+
4
+ <div id="redactor_tabs">
5
+ <a href="javascript:void(null);" class="redactor_tabs_act">URL</a>
6
+ <a href="javascript:void(null);">Email</a>
7
+ <a href="javascript:void(null);">%RLANG.anchor%</a>
8
+ <a href="javascript:void(null);">%RLANG.file%</a>
9
+ </div>
10
+
11
+ <input type="hidden" id="redactor_tab_selected" value="1" />
12
+
13
+ <div class="redactor_tab" id="redactor_tab1">
14
+ <table class="redactor_ruler">
15
+ <tr>
16
+ <td nowrap>URL</td>
17
+ <td width="100%"><input id="redactor_link_url" style="width: 99%; font-size: 16px;" /></td>
18
+ </tr>
19
+ <tr>
20
+ <td>%RLANG.text%</td>
21
+ <td><input class="redactor_link_text" id="redactor_link_url_text" style="width: 99%; font-size: 16px;" /></td>
22
+ </tr>
23
+ </table>
24
+ </div>
25
+ <div class="redactor_tab" id="redactor_tab2" style="display: none;">
26
+ <table class="redactor_ruler">
27
+ <tr>
28
+ <td nowrap>Email</td>
29
+ <td width="100%"><input id="redactor_link_mailto" style="width: 99%; font-size: 16px;" /></td>
30
+ </tr>
31
+ <tr>
32
+ <td>%RLANG.text%</td>
33
+ <td><input class="redactor_link_text" id="redactor_link_mailto_text" style="width: 99%; font-size: 16px;" /></td>
34
+ </tr>
35
+ </table>
36
+ </div>
37
+ <div class="redactor_tab" id="redactor_tab3" style="display: none;">
38
+ <table class="redactor_ruler">
39
+ <tr>
40
+ <td nowrap>%RLANG.anchor%</td>
41
+ <td width="100%"><input id="redactor_link_anchor" style="width: 99%; font-size: 16px;" /></td>
42
+ </tr>
43
+ <tr>
44
+ <td>%RLANG.text%</td>
45
+ <td><input class="redactor_link_text" id="redactor_link_anchor_text" style="width: 99%; font-size: 16px;" /></td>
46
+ </tr>
47
+ </table>
48
+ </div>
49
+ <div class="redactor_tab" id="redactor_tab4" style="display: none;">
50
+ <table class="redactor_ruler">
51
+ <tr>
52
+ <td>%RLANG.text%</td>
53
+ <td><input class="redactor_link_text" id="redactor_link_file_text" style="width: 99%; font-size: 16px;" /></td>
54
+ </tr>
55
+ <tr>
56
+ <td></td>
57
+ <td>
58
+
59
+ <input type="file" id="redactor_file" name="file" />
60
+
61
+ </td>
62
+ </tr>
63
+ </table>
64
+
65
+ </div>
66
+
67
+
68
+ </form>
69
+
70
+ <span class="redactor_btns_box">
71
+ <input type="button" id="redactor_insert_link_btn" value="%RLANG.insert%" />&nbsp;&nbsp;
72
+ <a href="javascript:void(null);" style="color: #777; font-size: 12px;" id="redactor_btn_modal_close">%RLANG.cancel%</a>
73
+ </span>
74
+ <div style="clear: both;"></div>
@@ -0,0 +1,25 @@
1
+
2
+ <table class="redactor_ruler" width="99%">
3
+ <tr>
4
+ <td>%RLANG.Rows%:</td>
5
+ <td width="100%"><input size="5" value="2" id="redactor_table_rows" /></td>
6
+ </tr>
7
+ <tr>
8
+ <td>%RLANG.Columns%:</td>
9
+ <td><input size="5" value="3" id="redactor_table_columns" /></td>
10
+ </tr>
11
+
12
+ <tr>
13
+ <td></td>
14
+ <td>
15
+ <br />
16
+ <span class="redactor_btns_box">
17
+ <input type="button" name="upload" id="redactor_insert_table_btn" value="%RLANG.insert%" />&nbsp;&nbsp;
18
+ <a href="javascript:void(null);" style="color: #777; font-size: 12px;" id="redactor_btn_modal_close">%RLANG.cancel%</a>
19
+ </span>
20
+ <div style="clear: both;"></div>
21
+
22
+ </td>
23
+ </tr>
24
+ </table>
25
+
@@ -0,0 +1,15 @@
1
+ <form id="redactorInsertVideoForm">
2
+ <div style="font-size: 11px; margin-bottom: 3px;">%RLANG.video_html_code%</div>
3
+ <table class="redactor_ruler" style="width: 99%;">
4
+ <tr>
5
+ <textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>
6
+ </tr>
7
+ </table>
8
+ </form>
9
+
10
+
11
+ <span class="redactor_btns_box">
12
+ <input type="button" id="redactor_insert_video_btn" value="%RLANG.insert%" />&nbsp;&nbsp;
13
+ <a href="javascript:void(null);" style="color: #777; font-size: 12px;" id="redactor_btn_modal_close">%RLANG.cancel%</a>
14
+ </span>
15
+ <div style="clear: both;"></div>
@@ -0,0 +1,2259 @@
1
+ /*
2
+ Redactor v7.6.3
3
+ Updated 31.05.2012
4
+
5
+ http://redactorjs.com/
6
+
7
+ Copyright (c) 2009-2012, Imperavi Ltd.
8
+ Licensed under Creative Commons Attribution-NonCommercial 3.0 license.
9
+
10
+ Usage: $('#content').redactor();
11
+ */
12
+
13
+ var RTOOLBAR = {};
14
+
15
+ (function($){
16
+
17
+ // Plugin
18
+ jQuery.fn.redactor = function(option)
19
+ {
20
+ return this.each(function()
21
+ {
22
+ var $this = $(this);
23
+
24
+ var data = $this.data('redactor');
25
+ if (!data) $this.data('redactor', (data = new Redactor(this, option)));
26
+ });
27
+ };
28
+
29
+
30
+ // Initialization
31
+ var Redactor = function(element, options)
32
+ {
33
+ // Element
34
+ this.$el = $(element);
35
+
36
+ // Options
37
+ this.opts = $.extend({
38
+
39
+ lang: 'en',
40
+ toolbar: 'default',
41
+
42
+ load: true,
43
+
44
+ path: false,
45
+ css: 'style.css',
46
+ focus: true,
47
+ resize: true,
48
+ autoresize: false,
49
+ fixed: false,
50
+
51
+ autoformat: true,
52
+ cleanUp: true,
53
+ convertDivs: true,
54
+ removeClasses: true,
55
+ removeStyles: false,
56
+ convertLinks: true,
57
+
58
+ handler: false, // false or url
59
+
60
+ autosave: false, // false or url
61
+ interval: 60, // seconds
62
+
63
+ imageGetJson: false, // url (ex. /folder/images.json ) or false
64
+
65
+ imageUpload: false, // url
66
+ linkFileUpload: false, // url
67
+ fileUpload: false, // url
68
+
69
+ visual: true,
70
+ fullscreen: false,
71
+ overlay: true, // modal overlay
72
+
73
+ colors: Array(
74
+ '#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00',
75
+ '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca',
76
+ '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694',
77
+ '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314',
78
+ '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100',
79
+ '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000'),
80
+
81
+ // private
82
+ allEmptyHtml: '<p><br /></p>',
83
+ mozillaEmptyHtml: '<p>&nbsp;</p>'
84
+
85
+
86
+ }, options, this.$el.data());
87
+
88
+ this.dropdowns = [];
89
+
90
+ // Init
91
+ this.init();
92
+ };
93
+
94
+ // Functionality
95
+ Redactor.prototype = {
96
+
97
+ // DYNAMICALLY LOAD
98
+ _loadFile: function(file, array)
99
+ {
100
+ var item = array[0];
101
+ array.splice(0, 1);
102
+
103
+ var callback;
104
+ if (typeof(item) == 'function') callback = item;
105
+ else callback = $.proxy(function() { this._loadFile(item, array); }, this);
106
+
107
+ this.dynamicallyLoad(file, callback);
108
+ },
109
+ loadFiles: function(array)
110
+ {
111
+ var item = array[0];
112
+ array.splice(0, 1);
113
+
114
+ this._loadFile(item, array);
115
+ },
116
+ dynamicallyLoad: function (url, callback)
117
+ {
118
+ var head = document.getElementsByTagName("head")[0];
119
+ var script = document.createElement("script");
120
+ script.src = url;
121
+
122
+ var done = false;
123
+
124
+ script.onload = script.onreadystatechange = function()
125
+ {
126
+ if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete"))
127
+ {
128
+ done = true;
129
+ if (callback) callback();
130
+ script.onload = script.onreadystatechange = null;
131
+ }
132
+ };
133
+
134
+ head.appendChild(script);
135
+
136
+ },
137
+
138
+ // Initialization
139
+ init: function()
140
+ {
141
+ // get path to styles
142
+ this.getPath();
143
+
144
+ if (this.opts.load)
145
+ {
146
+ // load files
147
+ var files = [];
148
+
149
+ files.push(this.opts.path + '/langs/' + this.opts.lang + '.js');
150
+ if (this.opts.toolbar !== false) files.push(this.opts.path + '/toolbars/' + this.opts.toolbar + '.js');
151
+ files.push($.proxy(this.start, this));
152
+
153
+ this.loadFiles(files);
154
+ }
155
+ else this.start();
156
+
157
+
158
+ },
159
+ start: function()
160
+ {
161
+
162
+ // get dimensions
163
+ this.height = this.$el.css('height');
164
+ this.width = this.$el.css('width');
165
+
166
+ // construct editor
167
+ this.build();
168
+
169
+ // get html
170
+ var html = this.$el.val();
171
+
172
+ // preformatter
173
+ html = this.preformater(html);
174
+
175
+ // conver newlines to p
176
+ if (this.opts.autoformat) html = this.paragraphy(html);
177
+
178
+ // enable
179
+ this.$editor = this.enable(html);
180
+
181
+ // focus always on page
182
+ $(this.doc).click($.proxy(function(e) { this.$editor.focus(); }, this));
183
+
184
+ // cleanup
185
+ $(this.doc).bind('paste', $.proxy(function(e)
186
+ {
187
+ setTimeout($.proxy(function ()
188
+ {
189
+ var node = $('<span id="pastemarkerend">&nbsp;</span>');
190
+ this.insertNodeAtCaret(node.get(0));
191
+
192
+ this.pasteCleanUp();
193
+
194
+ }, this), 200);
195
+
196
+
197
+
198
+ }, this));
199
+
200
+ // keypress
201
+ $(this.doc).keypress($.proxy(function(e)
202
+ {
203
+ var key = e.keyCode || e.which;
204
+
205
+ // safari shift key + enter
206
+ if (navigator.userAgent.indexOf('AppleWebKit') != -1) return this.safariShiftKeyEnter(e, key);
207
+
208
+ }, this))
209
+
210
+ // keyup
211
+ .keyup($.proxy(function(e)
212
+ {
213
+ var key = e.keyCode || e.which;
214
+
215
+ if (this.opts.autoformat)
216
+ {
217
+ // if empty
218
+ if (key == 8 || key == 46) return this.formatEmpty(e);
219
+
220
+ // new line p
221
+ if (key == 13 && !e.shiftKey && !e.ctrlKey && !e.metaKey) return this.formatNewLine(e);
222
+ }
223
+ //console.log(e);
224
+ this.syncCode();
225
+
226
+ }, this));
227
+
228
+ // toolbar
229
+ this.buildToolbar();
230
+
231
+ // resizer
232
+ if (this.opts.autoresize === false) this.buildResizer();
233
+ else this.observeAutoResize();
234
+
235
+ // shortcuts
236
+ this.shortcuts();
237
+
238
+ // autosave
239
+ this.autoSave();
240
+
241
+ // observers
242
+ this.observeImages();
243
+
244
+ // fullscreen on start
245
+ if (this.opts.fullscreen)
246
+ {
247
+ this.opts.fullscreen = false;
248
+ this.fullscreen();
249
+ }
250
+
251
+ // focus
252
+ if (this.opts.focus) this.focus();
253
+
254
+ // fixed
255
+ if (this.opts.fixed)
256
+ {
257
+ this.observeScroll();
258
+ $(document).scroll($.proxy(this.observeScroll, this));
259
+ }
260
+ },
261
+ shortcuts: function()
262
+ {
263
+ $(this.doc).keydown($.proxy(function(e)
264
+ {
265
+ var key = e.keyCode || e.which;
266
+
267
+ if (e.ctrlKey)
268
+ {
269
+ if (key == 90) this._shortcuts(e, 'undo'); // Ctrl + z
270
+ else if (key == 90 && e.shiftKey) this._shortcuts(e, 'redo'); // Ctrl + Shift + z
271
+ else if (key == 77) this._shortcuts(e, 'removeFormat'); // Ctrl + m
272
+ else if (key == 66) this._shortcuts(e, 'bold'); // Ctrl + b
273
+ else if (key == 73) this._shortcuts(e, 'italic'); // Ctrl + i
274
+ else if (key == 74) this._shortcuts(e, 'insertunorderedlist'); // Ctrl + j
275
+ else if (key == 75) this._shortcuts(e, 'insertorderedlist'); // Ctrl + k
276
+ else if (key == 76) this._shortcuts(e, 'superscript'); // Ctrl + l
277
+ }
278
+
279
+ if (!e.shiftKey && key == 9) this._shortcuts(e, 'indent'); // Tab
280
+ else if (e.shiftKey && key == 9 ) this._shortcuts(e, 'outdent'); // Shift + tab
281
+
282
+ }, this));
283
+
284
+ },
285
+ _shortcuts: function(e, cmd)
286
+ {
287
+ if (e.preventDefault) e.preventDefault();
288
+ this.execCommand(cmd, null);
289
+ },
290
+ getPath: function()
291
+ {
292
+ if (this.opts.path !== false) return this.opts.path;
293
+
294
+ $('script').each($.proxy(function(i,s)
295
+ {
296
+ if (s.src)
297
+ {
298
+ // Match redactor.js or redactor.min.js, followed by an optional querystring (often used for cache purposes)
299
+ var regexp = new RegExp(/\/redactor(\.min)?\.js(\?.*)?/);
300
+ if (s.src.match(regexp)) this.opts.path = s.src.replace(regexp, '');
301
+ }
302
+ }, this));
303
+
304
+ },
305
+ build: function()
306
+ {
307
+ // container
308
+ this.$box = $('<div class="redactor_box"></div>');
309
+
310
+ // frame
311
+ this.$frame = $('<iframe frameborder="0" scrolling="auto" style="height: ' + this.height + ';" class="redactor_frame"></iframe>');
312
+
313
+ // hide textarea
314
+ this.$el.css('width', '100%').hide();
315
+
316
+ // append box and frame
317
+ this.$box.insertAfter(this.$el).append(this.$frame).append(this.$el);
318
+
319
+ },
320
+ write: function(html)
321
+ {
322
+ this.doc.open();
323
+ this.doc.write(html);
324
+ this.doc.close();
325
+ },
326
+ enable: function(html)
327
+ {
328
+ this.doc = this.getDoc(this.$frame.get(0));
329
+
330
+ if (this.doc !== null)
331
+ {
332
+ this.write(this.setDoc(html));
333
+ if ($.browser.mozilla) this.doc.execCommand("useCSS", false, true);
334
+ return $(this.doc).find('#page');
335
+ }
336
+ else return false;
337
+ },
338
+ setDoc: function(html)
339
+ {
340
+ var frameHtml = '<!DOCTYPE html>\n';
341
+ frameHtml += '<html><head><link media="all" type="text/css" href="' + this.opts.path + '/css/' + this.opts.css + '" rel="stylesheet"></head>';
342
+ frameHtml += '<body><div id="page" contenteditable="true">';
343
+ frameHtml += html;
344
+ frameHtml += '</div></body></html>';
345
+ return frameHtml;
346
+ },
347
+ getDoc: function(frame)
348
+ {
349
+ if (frame.contentDocument) return frame.contentDocument;
350
+ else if (frame.contentWindow && frame.contentWindow.document) return frame.contentWindow.document;
351
+ else if (frame.document) return frame.document;
352
+ else return null;
353
+ },
354
+ focus: function()
355
+ {
356
+ this.$editor.focus();
357
+ },
358
+ syncCode: function()
359
+ {
360
+ var html = this.formating(this.$editor.html());
361
+ this.$el.val(html);
362
+ },
363
+
364
+ // API functions
365
+ setCode: function(html)
366
+ {
367
+ html = this.preformater(html);
368
+
369
+ this.$editor.html(html).focus();
370
+
371
+ this.syncCode();
372
+ },
373
+ getCode: function()
374
+ {
375
+ var html = this.$editor ? this.$editor.html() : this.$el.val();
376
+ html = this.reformater(html);
377
+
378
+ return html;
379
+ },
380
+ insertHtml: function(html)
381
+ {
382
+ this.execCommand('inserthtml', html);
383
+ },
384
+ destroy: function()
385
+ {
386
+ var html = this.getCode();
387
+
388
+ this.$box.after(this.$el);
389
+ this.$box.remove();
390
+ this.$el.val(html).show();
391
+
392
+ this.dropdowns.forEach(function(dropdown, i)
393
+ {
394
+ dropdown.remove();
395
+ delete(this.dropdowns[i]);
396
+ }, this);
397
+ },
398
+ handler: function()
399
+ {
400
+ $.ajax({
401
+ url: this.opts.handler,
402
+ type: 'post',
403
+ data: 'redactor=' + escape(encodeURIComponent(this.getCode())),
404
+ success: $.proxy(function(data)
405
+ {
406
+ this.setCode(data);
407
+ this.syncCode();
408
+
409
+ }, this)
410
+ });
411
+
412
+ },
413
+ // end API functions
414
+
415
+ // OBSERVERS
416
+ observeImages: function()
417
+ {
418
+ if ($.browser.mozilla) this.doc.execCommand("enableObjectResizing", false, "false");
419
+
420
+ $(this.doc).find('img').attr('unselectable', 'on').each($.proxy(function(i,s)
421
+ {
422
+ this.resizeImage(s);
423
+
424
+ }, this));
425
+
426
+ },
427
+ observeScroll: function()
428
+ {
429
+ var scrolltop = $(document).scrollTop();
430
+ var boxtop = this.$box.offset().top;
431
+
432
+ if (scrolltop > boxtop)
433
+ {
434
+ this.fixed = true;
435
+ this.$toolbar.css({position: 'fixed', width: '100%'});
436
+ }
437
+ else
438
+ {
439
+ this.fixed = false;
440
+ this.$toolbar.css({position: 'relative', width: 'auto'});
441
+ }
442
+ },
443
+ observeAutoResize: function()
444
+ {
445
+ this.$editor.css({ 'min-height':this.$el.height()+'px' });
446
+ this.$frame.css({ 'overflow-x':'auto', 'overflow-y':'hidden' });
447
+ this.$frame.load($.proxy(this.setAutoSize, this));
448
+ $(this.doc).keyup($.proxy(this.setAutoSize, this));
449
+ },
450
+ setAutoSize: function()
451
+ {
452
+ this.$frame.height(this.$editor.outerHeight(true)+30);
453
+ },
454
+
455
+
456
+ // EXECCOMMAND
457
+ execCommand: function(cmd, param)
458
+ {
459
+ if (this.opts.visual && this.doc)
460
+ {
461
+ try
462
+ {
463
+ if ($.browser.msie) this.focus();
464
+
465
+ if (cmd == 'inserthtml' && $.browser.msie) this.doc.selection.createRange().pasteHTML(param);
466
+ else if (cmd == 'formatblock' && $.browser.msie) this.doc.execCommand(cmd, false, '<' +param + '>');
467
+ else
468
+ {
469
+ this.doc.execCommand(cmd, false, param);
470
+ }
471
+
472
+ this.syncCode();
473
+ this.focus();
474
+ }
475
+ catch (e) { }
476
+
477
+ }
478
+ },
479
+
480
+ // FORMAT NEW LINE
481
+ formatNewLine: function(e)
482
+ {
483
+ var parent = this.getParentNode();
484
+ if (parent.nodeName == 'DIV' && parent.id == 'page')
485
+ {
486
+ if (e.preventDefault) e.preventDefault();
487
+
488
+ element = $(this.getCurrentNode());
489
+ if (element.get(0).tagName == 'DIV' && (element.html() == '' || element.html() == '<br>'))
490
+ {
491
+ newElement = $('<p>').append(element.clone().get(0).childNodes);
492
+ element.replaceWith(newElement);
493
+ newElement.html('<br />');
494
+ this.setFocusNode(newElement.get(0));
495
+
496
+ this.syncCode();
497
+ return false;
498
+ }
499
+ else this.syncCode();
500
+
501
+ // convert links
502
+ if (this.opts.convertLinks) this.$editor.linkify();
503
+ }
504
+ else
505
+ {
506
+ this.syncCode();
507
+ return true;
508
+ }
509
+ },
510
+
511
+ // SAFARI SHIFT KEY + ENTER
512
+ safariShiftKeyEnter: function(e, key)
513
+ {
514
+ if (e.shiftKey && key == 13)
515
+ {
516
+ if (e.preventDefault) e.preventDefault();
517
+
518
+ var node1 = $('<span><br /></span>');
519
+ this.insertNodeAtCaret(node1.get(0));
520
+ this.setFocusNode(node1.get(0));
521
+
522
+ this.syncCode();
523
+ return false;
524
+ }
525
+ },
526
+
527
+ // FORMAT EMPTY
528
+ formatEmpty: function(e)
529
+ {
530
+ var html = $.trim(this.$editor.html());
531
+
532
+ if ($.browser.mozilla) html = html.replace(/<br>/gi, '');
533
+
534
+ if (html === '')
535
+ {
536
+ if (e.preventDefault) e.preventDefault();
537
+
538
+ var nodehtml = this.opts.allEmptyHtml;
539
+ if ($.browser.mozilla) nodehtml = this.opts.mozillaEmptyHtml;
540
+
541
+ var node = $(nodehtml).get(0);
542
+ this.$editor.html(node);
543
+ this.setFocusNode(node);
544
+
545
+ this.syncCode();
546
+ return false;
547
+ }
548
+ else this.syncCode();
549
+ },
550
+
551
+ // PARAGRAPHY
552
+ paragraphy: function (str)
553
+ {
554
+ str = $.trim(str);
555
+ if (str === '')
556
+ {
557
+ if (!$.browser.mozilla) return this.opts.allEmptyHtml;
558
+ else return this.opts.mozillaEmptyHtml;
559
+ }
560
+
561
+ // convert div to p
562
+ if (this.opts.convertDivs) str = str.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>');
563
+
564
+ // inner functions
565
+ var X = function(x, a, b) { return x.replace(new RegExp(a, 'g'), b); };
566
+ var R = function(a, b) { return X(str, a, b); };
567
+
568
+ // block elements
569
+ var blocks = '(table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|address|math|style|script|object|input|param|p|h[1-6])';
570
+
571
+ str += '\n';
572
+
573
+ R('<br />\\s*<br />', '\n\n');
574
+ R('(<' + blocks + '[^>]*>)', '\n$1');
575
+ R('(</' + blocks + '>)', '$1\n\n');
576
+ R('\r\n|\r', '\n'); // newlines
577
+ R('\n\n+', '\n\n'); // remove duplicates
578
+ R('\n?((.|\n)+?)$', '<p>$1</p>\n'); // including one at the end
579
+ R('<p>\\s*?</p>', ''); // remove empty p
580
+ R('<p>(<div[^>]*>\\s*)', '$1<p>');
581
+ R('<p>([^<]+)\\s*?(</(div|address|form)[^>]*>)', '<p>$1</p>$2');
582
+ R('<p>\\s*(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
583
+ R('<p>(<li.+?)</p>', '$1');
584
+ R('<p>\\s*(</?' + blocks + '[^>]*>)', '$1');
585
+ R('(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
586
+ R('(</?' + blocks + '[^>]*>)\\s*<br />', '$1');
587
+ R('<br />(\\s*</?(p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', '$1');
588
+
589
+ // pre
590
+ if (str.indexOf('<pre') != -1)
591
+ {
592
+ R('(<pre(.|\n)*?>)((.|\n)*?)</pre>', function(m0, m1, m2, m3)
593
+ {
594
+ return X(m1, '\\\\([\'\"\\\\])', '$1') + X(X(X(m3, '<p>', '\n'), '</p>|<br />', ''), '\\\\([\'\"\\\\])', '$1') + '</pre>';
595
+ });
596
+ }
597
+
598
+ return R('\n</p>$', '</p>');
599
+ },
600
+
601
+ // PREPARE FORMATER
602
+ preformater: function(html)
603
+ {
604
+ html = html.replace(/<br>/gi,'<br />');
605
+
606
+ html = html.replace(/<blockquote\b[^>]*>([\w\W]*?)<p>([\w\W]*?)<\/p>([\w\W]*?)<\/blockquote[^>]*>/gi,'<blockquote>$1$2<br />$3</blockquote>');
607
+
608
+ html = html.replace(/<strong\b[^>]*>([\w\W]*?)<\/strong[^>]*>/gi,'<b>$1</b>');
609
+ html = html.replace(/<em\b[^>]*>([\w\W]*?)<\/em[^>]*>/gi,'<i>$1</i>');
610
+ html = html.replace(/<del\b[^>]*>([\w\W]*?)<\/del[^>]*>/gi,'<strike>$1</strike>');
611
+
612
+ return html;
613
+ },
614
+
615
+ // REVERT FORMATER
616
+ reformater: function(html)
617
+ {
618
+ html = html.replace(/<br>/gi,'<br />');
619
+
620
+ html = html.replace(/<b\b[^>]*>([\w\W]*?)<\/b[^>]*>/gi,'<strong>$1</strong>');
621
+ html = html.replace(/<i\b[^>]*>([\w\W]*?)<\/i[^>]*>/gi,'<em>$1</em>');
622
+ html = html.replace(/<strike\b[^>]*>([\w\W]*?)<\/strike[^>]*>/gi,'<del>$1</del>');
623
+ html = html.replace(/<span(.*?)style="font-weight: bold;">([\w\W]*?)<\/span>/gi, "<strong>$2</strong>");
624
+ html = html.replace(/<span(.*?)style="font-style: italic;">([\w\W]*?)<\/span>/gi, "<em>$2</em>");
625
+ html = html.replace(/<span(.*?)style="font-weight: bold; font-style: italic;">([\w\W]*?)<\/span>/gi, "<em><strong>$2</strong></em>");
626
+ html = html.replace(/<span(.*?)style="font-style: italic; font-weight: bold;">([\w\W]*?)<\/span>/gi, "<strong><em>$2</em></strong>");
627
+
628
+ return html;
629
+ },
630
+
631
+ // REMOVE CLASSES AND STYLES
632
+ cleanUpClasses: function(html)
633
+ {
634
+ html = html.replace(/\s*class="TOC(.*?)"/gi, "" );
635
+ html = html.replace(/\s*class="Heading(.*?)"/gi, "" );
636
+ html = html.replace(/\s*class="Body(.*?)"/gi, "" );
637
+
638
+ return html;
639
+ },
640
+ cleanUpStyles: function(html)
641
+ {
642
+
643
+ html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, "" );
644
+ html = html.replace( /\s*margin(.*?)pt\s*;/gi, "" );
645
+ html = html.replace( /\s*margin(.*?)cm\s*;/gi, "" );
646
+ html = html.replace( /\s*text-indent:(.*?)\s*;/gi, "" );
647
+ html = html.replace( /\s*line-height:(.*?)\s*;/gi, "" );
648
+ html = html.replace( /\s*page-break-before: [^\s;]+;?"/gi, "\"" );
649
+ html = html.replace( /\s*font-variant: [^\s;]+;?"/gi, "\"" );
650
+ html = html.replace( /\s*tab-stops:[^;"]*;?/gi, "" );
651
+ html = html.replace( /\s*tab-stops:[^"]*/gi, "" );
652
+ html = html.replace( /\s*face="[^"]*"/gi, "" );
653
+ html = html.replace( /\s*face=[^ >]*/gi, "" );
654
+ html = html.replace( /\s*font:(.*?);/gi, "" );
655
+ html = html.replace( /\s*font-size:(.*?);/gi, "" );
656
+ html = html.replace( /\s*font-weight:(.*?);/gi, "" );
657
+ html = html.replace( /\s*font-family:[^;"]*;?/gi, "" );
658
+ html = html.replace(/<span style="Times New Roman&quot;">\s\n<\/span>/gi, '');
659
+
660
+ return html;
661
+
662
+ },
663
+ cleanUp: function(html)
664
+ {
665
+ // clean comments
666
+ html = html.replace(/(<\!\-\-([\w\W]*?)\-\->)/ig, "");
667
+
668
+ if (this.opts.convertDivs)
669
+ {
670
+ html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>');
671
+ }
672
+
673
+ // clean dirty
674
+ html = html.replace(/ lang="([\w\W]*?)"/gi, '');
675
+ html = html.replace(/<a name="(.*?)">([\w\W]*?)<\/a>/gi, '');
676
+ html = html.replace(/\&nbsp;\&nbsp;\&nbsp;/gi, ' ');
677
+ html = html.replace(/\&nbsp;\&nbsp;/gi, ' ');
678
+ html = html.replace(/<o:p>(.*?)<\/o:p>/gi, '');
679
+
680
+
681
+ // empty style
682
+ html = html.replace( /\s*style="\s*"/gi, '' );
683
+
684
+ // spans
685
+ html = html.replace(/<span>&nbsp;<\/span>/gi, '');
686
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
687
+
688
+ return html;
689
+ },
690
+ removeTags: function(html)
691
+ {
692
+ return html.replace(/<(?!\s*\/?(code|span|div|label|a|br|p|b|i|del|strike|img|video|audio|iframe|object|embed|param|blockquote|mark|cite|small|ul|ol|li|hr|dl|dt|dd|sup|sub|big|pre|code|figure|figcaption|strong|em|table|tr|td|th|tbody|thead|tfoot|h1|h2|h3|h4|h5|h6)\b)[^>]+>/gi,"");
693
+ },
694
+
695
+ // PASTE CLEANUP
696
+ pasteCleanUp: function()
697
+ {
698
+ var html = this.$editor.html();
699
+
700
+ html = html.replace(/<span id="pastemarkerend">&nbsp;<\/span>/, '#marker#');
701
+
702
+ html = this.formating(html);
703
+ html = this.cleanUp(html);
704
+
705
+ if (this.opts.removeClasses) html = html.replace(/ class="([\w\W]*?)"/gi, '');
706
+ else html = this.cleanUpClasses(html);
707
+
708
+ if (this.opts.removeStyles) html = html.replace(/ style="([\w\W]*?)"/gi, '');
709
+ else html = this.cleanUpStyles(html);
710
+
711
+ html = this.cleanUp(html);
712
+ html = this.formating(html);
713
+
714
+ html = html.replace(/<b(.*?)id="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$3");
715
+
716
+ html = html.replace(/#marker#/, '<span id="pastemarkerend">&nbsp;</span>');
717
+
718
+ this.$editor.html(html);
719
+
720
+ var node = $(this.doc.body).find('#pastemarkerend').get(0);
721
+ this.setFocusNode(node);
722
+
723
+ this.syncCode();
724
+ this.observeImages();
725
+ },
726
+
727
+ // TEXTAREA CODE FORMATTING
728
+ formating: function (html)
729
+ {
730
+ // lowercase
731
+ if ($.browser.msie)
732
+ {
733
+ html = html.replace(/<*(\/ *)?(\w+)/g, function(w) { return w.toLowerCase(); });
734
+ html = html.replace(/style="(.*?)"/g, function(w) { return w.toLowerCase(); });
735
+ html = html.replace(/ jQuery(.*?)=\"(.*?)\"/gi, '');
736
+ }
737
+
738
+ html = html.replace(/<font([\w\W]*?)color="(.*?)">([\w\W]*?)<\/font\>/gi, '<span style="color: $2;">$3</span>');
739
+ html = html.replace(/<font([\w\W]*?)>([\w\W]*?)<\/font\>/gi, "<span$1>$2</span>");
740
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
741
+
742
+ // mini clean
743
+ html = html.replace(/ class="Apple-style-span"/gi, '');
744
+ html = html.replace(/ class="Apple-tab-span"/gi, '');
745
+ html = html.replace(/<p><p>/g, '<p>');
746
+ html = html.replace(/<\/p><\/p>/g, '</p>');
747
+ html = html.replace(/<hr(.*?)>/g, '<hr />');
748
+ html = html.replace(/<p>&nbsp;/g, '<p>');
749
+ html = html.replace(/<p><ul>/g, '<ul>');
750
+ html = html.replace(/<p><ol>/g, '<ol>');
751
+ html = html.replace(/<\/ul><\/p>/g, '</ul>');
752
+ html = html.replace(/<\/ol><\/p>/g, '</ol>');
753
+ html = html.replace( /<p(.*?)>&nbsp;<\/p>/gi, '');
754
+
755
+ // remove formatting
756
+ html = html.replace(/[\t]*/g, '');
757
+ html = html.replace(/\n\s*\n/g, "\n");
758
+ html = html.replace(/^[\s\n]*/, '');
759
+ html = html.replace(/[\s\n]*$/, '');
760
+
761
+ // empty tags
762
+ var etags = ["<pre></pre>","<blockquote>\\s*</blockquote>","<em>\\s*</em>","<b>\\s*</b>","<ul></ul>","<ol></ol>","<li></li>","<table></table>","<tr></tr>","<span>\\s*<span>", "<span>&nbsp;<span>", "<p>\\s*</p>", "<p>&nbsp;</p>", "<p>\\s*<br>\\s*</p>", "<div>\\s*</div>", "<div>\\s*<br>\\s*</div>"];
763
+ for (var i = 0; i < etags.length; ++i)
764
+ {
765
+ var bbb = etags[i];
766
+ html = html.replace(new RegExp(bbb,'gi'), "");
767
+ }
768
+
769
+
770
+ // add formatting before
771
+ var lb = '\r\n';
772
+ var btags = ["<form","<fieldset","<legend","<object","<embed","<select","<option","<input","<textarea","<pre","<blockquote","<ul","<ol","<li","<dl","<dt","<dd","<table", "<thead","<tbody","<caption","</caption>","<th","<tr","<td","<figure"];
773
+ for (var i = 0; i < btags.length; ++i)
774
+ {
775
+ var eee = btags[i];
776
+ html = html.replace(new RegExp(eee,'gi'),lb+eee);
777
+ }
778
+
779
+ // add formatting after
780
+ var atags = ['</p>', '</div>', '</ul>', '</ol>', '</h1>', '</h2>', '</h3>', '</h4>', '</h5>', '</h6>', '<br>', '<br />', '</dl>', '</dt>', '</dd>', '</form>', '</blockquote>', '</pre>', '</legend>', '</fieldset>', '</object>', '</embed>', '</textarea>', '</select>', '</option>', '</table>', '</thead>', '</tbody>', '</tr>', '</td>', '</th>', '</figure>'];
781
+ for (var i = 0; i < atags.length; ++i)
782
+ {
783
+ var aaa = atags[i];
784
+ html = html.replace(new RegExp(aaa,'gi'),aaa+lb);
785
+ }
786
+
787
+ // indenting
788
+ html = html.replace(/<li/g, "\t<li");
789
+ html = html.replace(/<tr/g, "\t<tr");
790
+ html = html.replace(/<td/g, "\t\t<td");
791
+ html = html.replace(/<\/tr>/g, "\t</tr>");
792
+
793
+ return html;
794
+ },
795
+
796
+ // TOGGLE
797
+ toggle: function()
798
+ {
799
+ var html;
800
+
801
+ if (this.opts.visual)
802
+ {
803
+ this.$frame.hide();
804
+
805
+ html = this.$editor.html();
806
+ html = $.trim(this.formating(html));
807
+
808
+ this.$el.val(html).show().focus();
809
+
810
+ this.setBtnActive('html');
811
+ this.opts.visual = false;
812
+ }
813
+ else
814
+ {
815
+ this.$el.hide();
816
+
817
+ this.$editor.html(this.$el.val());
818
+
819
+ this.$frame.show();
820
+
821
+ if (this.$editor.html() === '')
822
+ {
823
+ if (!$.browser.mozilla) html = this.opts.allEmptyHtml;
824
+ else html = this.opts.mozillaEmptyHtml;
825
+
826
+ this.setCode(html);
827
+ }
828
+
829
+ this.focus();
830
+
831
+ this.setBtnInactive('html');
832
+ this.opts.visual = true;
833
+ this.observeImages();
834
+ }
835
+ },
836
+
837
+ // AUTOSAVE
838
+ autoSave: function()
839
+ {
840
+ if (this.opts.autosave === false) return false;
841
+
842
+ setInterval($.proxy(function()
843
+ {
844
+ $.post(this.opts.autosave, { data: this.getCode() });
845
+
846
+ }, this), this.opts.interval*1000);
847
+ },
848
+
849
+ // TOOLBAR
850
+ buildToolbar: function()
851
+ {
852
+ if (this.opts.toolbar === false) return false;
853
+
854
+ this.$toolbar = $('<ul>').addClass('redactor_toolbar');
855
+ this.$box.prepend(this.$toolbar);
856
+
857
+ $.each(RTOOLBAR[this.opts.toolbar], $.proxy(function(key,s)
858
+ {
859
+ if (this.opts.fileUpload === false && key == 'file') return true;
860
+
861
+ var li = $('<li>');
862
+
863
+ if (key == 'fullscreen') $(li).addClass('redactor_toolbar_right');
864
+
865
+ var a = this.buildButton(key, s);
866
+
867
+ // dropdown
868
+ if (key == 'backcolor' || key == 'fontcolor' || typeof(s.dropdown) != 'undefined')
869
+ {
870
+ var dropdown = $('<div class="redactor_dropdown" style="display: none;">');
871
+
872
+ if (key == 'backcolor' || key == 'fontcolor') dropdown = this.buildColorPicker(dropdown, key);
873
+ else dropdown = this.buildDropdown(dropdown, s.dropdown);
874
+
875
+ this.dropdowns.push(dropdown.appendTo($(document.body)));
876
+
877
+ // observing dropdown
878
+ this.hdlHideDropDown = $.proxy(function(e) { this.hideDropDown(e, dropdown, key); }, this);
879
+ this.hdlShowDropDown = $.proxy(function(e) { this.showDropDown(e, dropdown, key); }, this);
880
+
881
+ a.click(this.hdlShowDropDown);
882
+ }
883
+
884
+ this.$toolbar.append($(li).append(a));
885
+ if (typeof(s.separator) != 'undefined') this.$toolbar.append($('<li class="redactor_separator"></li>'));
886
+
887
+ }, this));
888
+
889
+ $(document).click(this.hdlHideDropDown);
890
+ $(this.doc).click(this.hdlHideDropDown);
891
+
892
+ },
893
+ buildButton: function(key, s)
894
+ {
895
+ var button = $('<a href="javascript:void(null);" title="' + s.title + '" class="redactor_btn_' + key + '"><span>&nbsp;</span></a>');
896
+ if (typeof(s.func) == 'undefined') button.click($.proxy(function() { this.execCommand(s.exec, key); }, this));
897
+ else if (s.func != 'show') button.click($.proxy(function(e) { this[s.func](e); }, this));
898
+
899
+ return button;
900
+ },
901
+ buildDropdown: function(dropdown, obj)
902
+ {
903
+ $.each(obj, $.proxy(
904
+ function (x, d)
905
+ {
906
+ if (typeof(d.style) == 'undefined') d.style = '';
907
+
908
+ var drop_a;
909
+ if (d.name == 'separator') drop_a = $('<a class="redactor_separator_drop">');
910
+ else
911
+ {
912
+ drop_a = $('<a href="javascript:void(null);" style="' + d.style + '">' + d.title + '</a>');
913
+
914
+ if (typeof(d.func) == 'undefined') $(drop_a).click($.proxy(function() { this.execCommand(d.exec, x); }, this));
915
+ else $(drop_a).click($.proxy(function(e) { this[d.func](e); }, this));
916
+ }
917
+
918
+ $(dropdown).append(drop_a);
919
+
920
+ }, this)
921
+ );
922
+
923
+ return dropdown;
924
+
925
+ },
926
+ buildColorPicker: function(dropdown, key)
927
+ {
928
+ var mode;
929
+ if (key == 'backcolor')
930
+ {
931
+ if ($.browser.msie) mode = 'BackColor';
932
+ else mode = 'hilitecolor';
933
+ }
934
+ else mode = 'forecolor';
935
+
936
+ $(dropdown).width(210);
937
+
938
+ var len = this.opts.colors.length;
939
+ for (var i = 0; i < len; ++i)
940
+ {
941
+ var color = this.opts.colors[i];
942
+
943
+ var swatch = $('<a rel="' + color + '" href="javascript:void(null);" class="redactor_color_link"></a>').css({ 'backgroundColor': color });
944
+ $(dropdown).append(swatch);
945
+
946
+ var _self = this;
947
+ $(swatch).click(function() { _self.execCommand(mode, $(this).attr('rel')); });
948
+ }
949
+
950
+ var elnone = $('<a href="javascript:void(null);" class="redactor_color_none"></a>').html(RLANG.none);
951
+
952
+ if (key == 'backcolor') elnone.click($.proxy(this.setBackgroundNone, this));
953
+ else elnone.click($.proxy(this.setColorNone, this));
954
+
955
+ $(dropdown).append(elnone);
956
+
957
+ return dropdown;
958
+ },
959
+ setBackgroundNone: function()
960
+ {
961
+ $(this.getParentNode()).css('background-color', 'transparent');
962
+ this.syncCode();
963
+ },
964
+ setColorNone: function()
965
+ {
966
+ $(this.getParentNode()).attr('color', '').css('color', '');
967
+ this.syncCode();
968
+ },
969
+
970
+ // DROPDOWNS
971
+ showDropDown: function(e, dropdown, key)
972
+ {
973
+ this.hideAllDropDown();
974
+
975
+ this.setBtnActive(key);
976
+ this.getBtn(key).addClass('dropact');
977
+
978
+ var left = this.getBtn(key).offset().left;
979
+
980
+
981
+ if (this.opts.fixed && this.fixed)
982
+ {
983
+ $(dropdown).css({ position: 'fixed', left: left + 'px', top: '30px' }).show();
984
+ }
985
+ else
986
+ {
987
+ var top = this.$toolbar.offset().top + 30;
988
+ $(dropdown).css({ position: 'absolute', left: left + 'px', top: top + 'px' }).show();
989
+ }
990
+
991
+ },
992
+ hideAllDropDown: function()
993
+ {
994
+ this.$toolbar.find('a.dropact').removeClass('act').removeClass('dropact');
995
+ $('.redactor_dropdown').hide();
996
+ },
997
+ hideDropDown: function(e, dropdown, key)
998
+ {
999
+ if (!$(e.target).parent().hasClass('dropact'))
1000
+ {
1001
+ $(dropdown).removeClass('act');
1002
+ this.showedDropDown = false;
1003
+ this.hideAllDropDown();
1004
+ }
1005
+ },
1006
+
1007
+ // SELECTION AND NODE MANIPULATION
1008
+ getSelection: function ()
1009
+ {
1010
+ if (this.$frame.get(0).contentWindow.getSelection) return this.$frame.get(0).contentWindow.getSelection();
1011
+ else if (this.$frame.get(0).contentWindow.document.selection) return this.$frame.get(0).contentWindow.document.selection.createRange();
1012
+ },
1013
+ getParentNode: function()
1014
+ {
1015
+ if (window.getSelection) return this.getSelection().getRangeAt(0).startContainer.parentNode;
1016
+ else if (document.selection) return this.getSelection().parentElement();
1017
+ },
1018
+ getCurrentNode: function()
1019
+ {
1020
+ if (window.getSelection) return this.getSelection().getRangeAt(0).startContainer;
1021
+ else if (document.selection) return this.getSelection();
1022
+ },
1023
+ setFocusNode: function(node, toStart)
1024
+ {
1025
+ var range = this.doc.createRange();
1026
+
1027
+ var selection = this.getSelection();
1028
+ toStart = toStart ? 0 : 1;
1029
+
1030
+ if (selection !== null)
1031
+ {
1032
+ range.selectNodeContents(node);
1033
+ selection.addRange(range);
1034
+ selection.collapse(node, toStart);
1035
+ }
1036
+
1037
+ this.focus();
1038
+ },
1039
+ insertNodeAtCaret: function (node)
1040
+ {
1041
+ if (typeof window.getSelection != "undefined")
1042
+ {
1043
+ var sel = this.getSelection();
1044
+ if (sel.rangeCount)
1045
+ {
1046
+ var range = sel.getRangeAt(0);
1047
+ range.collapse(false);
1048
+ range.insertNode(node);
1049
+ range = range.cloneRange();
1050
+ range.selectNodeContents(node);
1051
+ range.collapse(false);
1052
+ sel.removeAllRanges();
1053
+ sel.addRange(range);
1054
+ }
1055
+ }
1056
+ else if (typeof document.selection != "undefined" && document.selection.type != "Control")
1057
+ {
1058
+ var html = (node.nodeType == 1) ? node.outerHTML : node.data;
1059
+ var id = "marker_" + ("" + Math.random()).slice(2);
1060
+ html += '<span id="' + id + '"></span>';
1061
+ var textRange = this.getSelection();
1062
+ textRange.collapse(false);
1063
+ textRange.pasteHTML(html);
1064
+ var markerSpan = document.getElementById(id);
1065
+ textRange.moveToElementText(markerSpan);
1066
+ textRange.select();
1067
+ markerSpan.parentNode.removeChild(markerSpan);
1068
+ }
1069
+ },
1070
+
1071
+ // BUTTONS MANIPULATIONS
1072
+ getBtn: function(key)
1073
+ {
1074
+ return $(this.$toolbar.find('a.redactor_btn_' + key));
1075
+ },
1076
+ setBtnActive: function(key)
1077
+ {
1078
+ this.getBtn(key).addClass('act');
1079
+ },
1080
+ setBtnInactive: function(key)
1081
+ {
1082
+ this.getBtn(key).removeClass('act');
1083
+ },
1084
+ changeBtnIcon: function(key, classname)
1085
+ {
1086
+ this.getBtn(key).addClass('redactor_btn_' + classname);
1087
+ },
1088
+ removeBtnIcon: function(key, classname)
1089
+ {
1090
+ this.getBtn(key).removeClass('redactor_btn_' + classname);
1091
+ },
1092
+ removeBtn: function(key)
1093
+ {
1094
+ this.getBtn(key).remove();
1095
+ },
1096
+ addBtn: function(key, obj)
1097
+ {
1098
+ this.$toolbar.append($('<li>').append(this.buildButton(key, obj)));
1099
+ },
1100
+
1101
+ // FULLSCREEN
1102
+ fullscreen: function()
1103
+ {
1104
+ var html;
1105
+
1106
+ if (this.opts.fullscreen === false)
1107
+ {
1108
+ this.changeBtnIcon('fullscreen', 'normalscreen');
1109
+ this.setBtnActive('fullscreen');
1110
+ this.opts.fullscreen = true;
1111
+
1112
+ this.height = this.$frame.css('height');
1113
+ this.width = (this.$box.width() - 2) + 'px';
1114
+
1115
+ html = this.getCode();
1116
+
1117
+ this.tmpspan = $('<span></span>');
1118
+ this.$box.addClass('redactor_box_fullscreen').after(this.tmpspan);
1119
+
1120
+ $(document.body).prepend(this.$box).css('overflow', 'hidden');
1121
+
1122
+ this.$editor = this.enable(html);
1123
+
1124
+ $(this.doc).click($.proxy(this.hideAllDropDown, this));
1125
+ // focus always on page
1126
+ $(this.doc).click($.proxy(function(e) { this.$editor.focus(); }, this));
1127
+
1128
+ this.observeImages();
1129
+ this.$box.find('.redactor_resizer').hide();
1130
+
1131
+ this.fullScreenResize();
1132
+ $(window).resize($.proxy(this.fullScreenResize, this));
1133
+ $(document).scrollTop(0,0);
1134
+ this.focus();
1135
+
1136
+ }
1137
+ else
1138
+ {
1139
+ this.removeBtnIcon('fullscreen', 'normalscreen');
1140
+ this.setBtnInactive('fullscreen');
1141
+ this.opts.fullscreen = false;
1142
+
1143
+ $(window).unbind('resize', $.proxy(this.fullScreenResize, this));
1144
+ $(document.body).css('overflow', '');
1145
+
1146
+ html = this.getCode();
1147
+
1148
+ this.$box.removeClass('redactor_box_fullscreen').css('width', 'auto');
1149
+
1150
+ this.tmpspan.after(this.$box).remove();
1151
+
1152
+ this.$editor = this.enable(html);
1153
+
1154
+ this.observeImages();
1155
+ this.observeAutoResize();
1156
+ this.$box.find('.redactor_resizer').show();
1157
+
1158
+ $(this.doc).click($.proxy(this.hideAllDropDown, this));
1159
+ // focus always on page
1160
+ $(this.doc).click($.proxy(function(e) { this.$editor.focus(); }, this));
1161
+
1162
+ this.syncCode();
1163
+
1164
+ this.$frame.css('height', this.height);
1165
+ this.$el.css('height', this.height);
1166
+ this.focus();
1167
+ }
1168
+ },
1169
+ fullScreenResize: function()
1170
+ {
1171
+ if (this.opts.fullscreen === false) return;
1172
+
1173
+ var hfix = 42;
1174
+ if (this.opts.air) hfix = 2;
1175
+
1176
+ var height = $(window).height() - hfix;
1177
+
1178
+ this.$box.width($(window).width() - 2);
1179
+ this.$frame.height(height);
1180
+ this.$el.height(height);
1181
+ },
1182
+
1183
+ // RESIZE
1184
+ buildResizer: function()
1185
+ {
1186
+ if (this.opts.resize === false) return false;
1187
+
1188
+ this.$resizer = $('<div class="redactor_resizer">&mdash;</div>');
1189
+ this.$box.append(this.$resizer);
1190
+
1191
+ this.$resizer.mousedown($.proxy(this.initResize, this));
1192
+
1193
+ },
1194
+ initResize: function(e)
1195
+ {
1196
+ if (e.preventDefault) e.preventDefault();
1197
+
1198
+ this.splitter = e.target;
1199
+
1200
+ if (this.opts.visual)
1201
+ {
1202
+ this.element_resize = this.$frame;
1203
+ this.element_resize.get(0).style.visibility = 'hidden';
1204
+ this.element_resize_parent = this.$el;
1205
+ }
1206
+ else
1207
+ {
1208
+ this.element_resize = this.$el;
1209
+ this.element_resize_parent = this.$frame;
1210
+ }
1211
+
1212
+ this.stopResizeHdl = $.proxy(this.stopResize, this);
1213
+ this.startResizeHdl = $.proxy(this.startResize, this);
1214
+ this.resizeHdl = $.proxy(this.resize, this);
1215
+
1216
+ $(document).mousedown(this.startResizeHdl);
1217
+ $(document).mouseup(this.stopResizeHdl);
1218
+ $(this.splitter).mouseup(this.stopResizeHdl);
1219
+
1220
+ this.null_point = false;
1221
+ this.h_new = false;
1222
+ this.h = this.element_resize.height();
1223
+ },
1224
+ startResize: function()
1225
+ {
1226
+ $(document).mousemove(this.resizeHdl);
1227
+ },
1228
+ resize: function(e)
1229
+ {
1230
+ if (e.preventDefault) e.preventDefault();
1231
+
1232
+ var y = e.pageY;
1233
+ if (this.null_point === false) this.null_point = y;
1234
+ if (this.h_new === false) this.h_new = this.element_resize.height();
1235
+
1236
+ var s_new = (this.h_new + y - this.null_point) - 10;
1237
+
1238
+ if (s_new <= 30) return true;
1239
+
1240
+ if (s_new >= 0)
1241
+ {
1242
+ this.element_resize.get(0).style.height = s_new + 'px';
1243
+ this.element_resize_parent.get(0).style.height = s_new + 'px';
1244
+ }
1245
+ },
1246
+ stopResize: function(e)
1247
+ {
1248
+ $(document).unbind('mousemove', this.resizeHdl);
1249
+ $(document).unbind('mousedown', this.startResizeHdl);
1250
+ $(document).unbind('mouseup', this.stopResizeHdl);
1251
+ $(this.splitter).unbind('mouseup', this.stopResizeHdl);
1252
+
1253
+ this.element_resize.get(0).style.visibility = 'visible';
1254
+ },
1255
+
1256
+ // RESIZE IMAGES
1257
+ resizeImage: function(resize)
1258
+ {
1259
+ var clicked = false;
1260
+ var clicker = false;
1261
+ var start_x;
1262
+ var start_y;
1263
+ var ratio = $(resize).width()/$(resize).height();
1264
+
1265
+ var y = 1;
1266
+ var x = 1;
1267
+ var min_w = 1;
1268
+ var min_h = 1;
1269
+
1270
+ $(resize).hover(function(){$(resize).css('cursor', 'nw-resize');}, function(){$(resize).css('cursor','default');clicked=false;});
1271
+
1272
+ $(resize).mousedown(function(e)
1273
+ {
1274
+ if (e.preventDefault) e.preventDefault();
1275
+
1276
+ clicked = true;
1277
+ clicker = true;
1278
+
1279
+ start_x = Math.round(e.pageX - $(resize).eq(0).offset().left);
1280
+ start_y = Math.round(e.pageY - $(resize).eq(0).offset().top);
1281
+ });
1282
+
1283
+ $(resize).mouseup($.proxy(function(e)
1284
+ {
1285
+ clicked = false;
1286
+ this.syncCode();
1287
+ }, this));
1288
+
1289
+ $(resize).click($.proxy(function(e)
1290
+ {
1291
+ if (clicker) this.imageEdit(e);
1292
+
1293
+ }, this));
1294
+
1295
+ $(resize).mousemove(function(e)
1296
+ {
1297
+ if (clicked)
1298
+ {
1299
+ clicker = false;
1300
+
1301
+ var mouse_x = Math.round(e.pageX - $(this).eq(0).offset().left) - start_x;
1302
+ var mouse_y = Math.round(e.pageY - $(this).eq(0).offset().top) - start_y;
1303
+
1304
+ var div_h = $(resize).height();
1305
+
1306
+ var new_h = parseInt(div_h)+mouse_y;
1307
+ var new_w = new_h*ratio;
1308
+
1309
+
1310
+
1311
+ if(x==1 || (typeof(x) == "number" && new_w < x && new_w > min_w) ){ $(resize).width(new_w); }
1312
+ if(y==1 || (typeof(y) == "number" && new_h < y && new_h > min_h) ){ $(resize).height(new_h); }
1313
+ start_x = Math.round(e.pageX - $(this).eq(0).offset().left);
1314
+ start_y = Math.round(e.pageY - $(this).eq(0).offset().top);
1315
+ }
1316
+ });
1317
+ },
1318
+
1319
+ // TABLE
1320
+ showTable: function()
1321
+ {
1322
+ this.modalInit(RLANG.table, this.opts.path + '/plugins/table.html', 300, $.proxy(function()
1323
+ {
1324
+ $('#redactor_table_rows').focus();
1325
+ $('#redactor_insert_table_btn').click($.proxy(this.insertTable, this));
1326
+
1327
+ }, this));
1328
+ },
1329
+ insertTable: function()
1330
+ {
1331
+ var rows = $('#redactor_table_rows').val();
1332
+ var columns = $('#redactor_table_columns').val();
1333
+
1334
+ var table_box = $('<div></div>');
1335
+
1336
+ var tableid = Math.floor(Math.random() * 99999);
1337
+ var table = $('<table id="table' + tableid + '"><tbody></tbody></table>');
1338
+
1339
+ for (var i = 0; i < rows; i++)
1340
+ {
1341
+ var row = $('<tr></tr>');
1342
+ for (var z = 0; z < columns; z++)
1343
+ {
1344
+ var column = $('<td>&nbsp;</td>');
1345
+ $(row).append(column);
1346
+ }
1347
+ $(table).append(row);
1348
+ }
1349
+
1350
+ $(table_box).append(table);
1351
+ var html = $(table_box).html();
1352
+
1353
+ if ($.browser.msie) html += '<p></p>';
1354
+ else html += '<p>&nbsp;</p>';
1355
+
1356
+ this.execCommand('inserthtml', html);
1357
+ this.modalClose();
1358
+
1359
+ this.$table = $(this.doc).find('body').find('#table' + tableid);
1360
+ this.$table.click($.proxy(this.tableObserver, this));
1361
+ },
1362
+ tableObserver: function(e)
1363
+ {
1364
+ this.$table = $(e.target).parents('table');
1365
+
1366
+ this.$table_tr = this.$table.find('tr');
1367
+ this.$table_td = this.$table.find('td');
1368
+
1369
+ this.$table_td.removeClass('current');
1370
+
1371
+ this.$tbody = $(e.target).parents('tbody');
1372
+ this.$thead = $(this.$table).find('thead');
1373
+
1374
+ this.$current_td = $(e.target);
1375
+ this.$current_td.addClass('current');
1376
+
1377
+ this.$current_tr = $(e.target).parents('tr');
1378
+ },
1379
+ deleteTable: function()
1380
+ {
1381
+ $(this.$table).remove();
1382
+ this.$table = false;
1383
+ this.syncCode();
1384
+ },
1385
+ deleteRow: function()
1386
+ {
1387
+ $(this.$current_tr).remove();
1388
+ this.syncCode();
1389
+ },
1390
+ deleteColumn: function()
1391
+ {
1392
+ var index = $(this.$current_td).get(0).cellIndex;
1393
+
1394
+ $(this.$table).find('tr').each(function()
1395
+ {
1396
+ $(this).find('td').eq(index).remove();
1397
+ });
1398
+
1399
+ this.syncCode();
1400
+ },
1401
+ addHead: function()
1402
+ {
1403
+ if ($(this.$table).find('thead').size() !== 0) this.deleteHead();
1404
+ else
1405
+ {
1406
+ var tr = $(this.$table).find('tr').first().clone();
1407
+ tr.find('td').html('&nbsp;');
1408
+ this.$thead = $('<thead></thead>');
1409
+ this.$thead.append(tr);
1410
+ $(this.$table).prepend(this.$thead);
1411
+ this.syncCode();
1412
+ }
1413
+ },
1414
+ deleteHead: function()
1415
+ {
1416
+ $(this.$thead).remove();
1417
+ this.$thead = false;
1418
+ this.syncCode();
1419
+ },
1420
+ insertRowAbove: function()
1421
+ {
1422
+ this.insertRow('before');
1423
+ },
1424
+ insertRowBelow: function()
1425
+ {
1426
+ this.insertRow('after');
1427
+ },
1428
+ insertColumnLeft: function()
1429
+ {
1430
+ this.insertColumn('before');
1431
+ },
1432
+ insertColumnRight: function()
1433
+ {
1434
+ this.insertColumn('after');
1435
+ },
1436
+ insertRow: function(type)
1437
+ {
1438
+ var new_tr = $(this.$current_tr).clone();
1439
+ new_tr.find('td').html('&nbsp;');
1440
+ if (type == 'after') $(this.$current_tr).after(new_tr);
1441
+ else $(this.$current_tr).before(new_tr);
1442
+
1443
+ this.syncCode();
1444
+ },
1445
+ insertColumn: function(type)
1446
+ {
1447
+ var index = 0;
1448
+
1449
+ this.$current_td.addClass('current');
1450
+
1451
+ this.$current_tr.find('td').each(function(i,s)
1452
+ {
1453
+ if ($(s).hasClass('current')) index = i;
1454
+ });
1455
+
1456
+ this.$table_tr.each(function(i,s)
1457
+ {
1458
+ var current = $(s).find('td').eq(index);
1459
+
1460
+ var td = current.clone();
1461
+ td.html('&nbsp;');
1462
+
1463
+ if (type == 'after') $(current).after(td);
1464
+ else $(current).before(td);
1465
+
1466
+ });
1467
+
1468
+ this.syncCode();
1469
+ },
1470
+
1471
+ // INSERT VIDEO
1472
+ showVideo: function()
1473
+ {
1474
+ if ($.browser.msie) this.markerIE();
1475
+
1476
+ this.modalInit(RLANG.video, this.opts.path + '/plugins/video.html', 600, $.proxy(function()
1477
+ {
1478
+ $('#redactor_insert_video_area').focus();
1479
+ $('#redactor_insert_video_btn').click($.proxy(this.insertVideo, this));
1480
+
1481
+ }, this));
1482
+ },
1483
+ insertVideo: function()
1484
+ {
1485
+ var data = $('#redactor_insert_video_area').val();
1486
+
1487
+ if ($.browser.msie)
1488
+ {
1489
+ $(this.doc.getElementById('span' + this.spanid)).after(data).remove();
1490
+ this.syncCode();
1491
+ }
1492
+ else this.execCommand('inserthtml', data);
1493
+
1494
+ this.modalClose();
1495
+ },
1496
+
1497
+ // INSERT IMAGE
1498
+ imageEdit: function(e)
1499
+ {
1500
+ var $el = $(e.target);
1501
+ var parent = $el.parent();
1502
+
1503
+ var handler = $.proxy(function()
1504
+ {
1505
+ $('#redactor_file_alt').val($el.attr('alt'));
1506
+ $('#redactor_image_edit_src').attr('href', $el.attr('src'));
1507
+ $('#redactor_form_image_align').val($el.css('float'));
1508
+
1509
+ if ($(parent).get(0).tagName == 'A') $('#redactor_file_link').val($(parent).attr('href'));
1510
+
1511
+ $('#redactor_image_delete_btn').click($.proxy(function() { this.imageDelete($el); }, this));
1512
+ $('#redactorSaveBtn').click($.proxy(function() { this.imageSave($el); }, this));
1513
+
1514
+ }, this);
1515
+
1516
+ this.modalInit(RLANG.image, this.opts.path + '/plugins/image_edit.html', 380, handler);
1517
+
1518
+ },
1519
+ imageDelete: function(el)
1520
+ {
1521
+ $(el).remove();
1522
+ this.modalClose();
1523
+ this.syncCode();
1524
+ },
1525
+ imageSave: function(el)
1526
+ {
1527
+ var parent = $(el).parent();
1528
+
1529
+ $(el).attr('alt', $('#redactor_file_alt').val());
1530
+
1531
+ var floating = $('#redactor_form_image_align').val();
1532
+
1533
+ if (floating == 'left') $(el).css({ 'float': 'left', margin: '0 10px 10px 0' });
1534
+ else if (floating == 'right') $(el).css({ 'float': 'right', margin: '0 0 10px 10px' });
1535
+ else $(el).css({ 'float': 'none', margin: '0' });
1536
+
1537
+ // as link
1538
+ var link = $.trim($('#redactor_file_link').val());
1539
+ if (link !== '')
1540
+ {
1541
+ if ($(parent).get(0).tagName != 'A')
1542
+ {
1543
+ $(el).replaceWith('<a href="' + link + '">' + this.outerHTML(el) + '</a>');
1544
+ }
1545
+ else
1546
+ {
1547
+ $(parent).attr('href', link);
1548
+ }
1549
+ }
1550
+
1551
+ this.modalClose();
1552
+ this.observeImages();
1553
+ this.syncCode();
1554
+
1555
+ },
1556
+ showImage: function()
1557
+ {
1558
+ if ($.browser.msie) this.markerIE();
1559
+
1560
+ var handler = $.proxy(function()
1561
+ {
1562
+ // json
1563
+ if (this.opts.imageGetJson !== false)
1564
+ {
1565
+ $.getJSON(this.opts.imageGetJson, $.proxy(function(data) {
1566
+
1567
+ $.each(data, $.proxy(function(key, val)
1568
+ {
1569
+ var img = $('<img src="' + val.thumb + '" rel="' + val.image + '" />');
1570
+ $('#redactor_image_box').append(img);
1571
+ $(img).click($.proxy(this.imageSetThumb, this));
1572
+
1573
+ }, this));
1574
+
1575
+ }, this));
1576
+ }
1577
+ else
1578
+ {
1579
+ $('#redactor_tabs a').eq(1).remove();
1580
+ }
1581
+
1582
+ if (this.opts.imageUpload !== false)
1583
+ {
1584
+ // dragupload
1585
+ if ($('#redactor_file').size() !== 0)
1586
+ {
1587
+ $('#redactor_file').dragupload(
1588
+ {
1589
+ url: this.opts.imageUpload,
1590
+ success: $.proxy(this.imageUploadCallback, this)
1591
+ });
1592
+ }
1593
+
1594
+ // ajax upload
1595
+ this.uploadInit('redactor_file', { auto: true, url: this.opts.imageUpload, success: $.proxy(this.imageUploadCallback, this) });
1596
+ }
1597
+ else
1598
+ {
1599
+ $('.redactor_tab').hide();
1600
+ if (this.opts.imageGetJson === false)
1601
+ {
1602
+ $('#redactor_tabs').remove();
1603
+ $('#redactor_tab3').show();
1604
+ }
1605
+ else
1606
+ {
1607
+ var tabs = $('#redactor_tabs a');
1608
+ tabs.eq(0).remove();
1609
+ tabs.eq(1).addClass('redactor_tabs_act');
1610
+ $('#redactor_tab2').show();
1611
+ }
1612
+ }
1613
+
1614
+ $('#redactor_upload_btn').click($.proxy(this.imageUploadCallbackLink, this));
1615
+
1616
+ }, this);
1617
+
1618
+ this.modalInit(RLANG.image, this.opts.path + '/plugins/image.html', 570, handler, true);
1619
+
1620
+ },
1621
+ imageSetThumb: function(e)
1622
+ {
1623
+ this._imageSet('<img alt="" src="' + $(e.target).attr('rel') + '" />');
1624
+ },
1625
+ imageUploadCallbackLink: function()
1626
+ {
1627
+ if ($('#redactor_file_link').val() !== '')
1628
+ {
1629
+ var data = '<img src="' + $('#redactor_file_link').val() + '" />';
1630
+
1631
+ this._imageSet(data);
1632
+ }
1633
+ else this.modalClose();
1634
+ },
1635
+ imageUploadCallback: function(data)
1636
+ {
1637
+ this._imageSet(data);
1638
+ },
1639
+ _imageSet: function(html)
1640
+ {
1641
+ html = '<p>' + html + '</p>';
1642
+
1643
+ this.focus();
1644
+
1645
+ if ($.browser.msie)
1646
+ {
1647
+ $(this.doc.getElementById('span' + this.spanid)).after(html).remove();
1648
+ this.syncCode();
1649
+ }
1650
+ else
1651
+ {
1652
+ this.execCommand('inserthtml', html);
1653
+ }
1654
+
1655
+ this.modalClose();
1656
+ this.observeImages();
1657
+ },
1658
+
1659
+ // INSERT LINK
1660
+ showLink: function()
1661
+ {
1662
+ var handler = $.proxy(function()
1663
+ {
1664
+ var sel = this.getSelection();
1665
+
1666
+ if ($.browser.msie)
1667
+ {
1668
+ var parent = this.getParentNode();
1669
+ if (parent.nodeName == 'A')
1670
+ {
1671
+ this.insert_link_node = $(parent);
1672
+ var text = this.insert_link_node.text();
1673
+ var url = this.insert_link_node.attr('href');
1674
+ }
1675
+ else
1676
+ {
1677
+ if (this.oldIE()) var text = sel.text;
1678
+ else var text = sel.toString();
1679
+
1680
+ var url = '';
1681
+
1682
+ this.spanid = Math.floor(Math.random() * 99999);
1683
+
1684
+ var html = '<span id="span' + this.spanid + '">' + text + '</span>';
1685
+ if (text != '') html = '<span id="span' + this.spanid + '">' + text + '</span>';
1686
+ this.execCommand('inserthtml', html);
1687
+ }
1688
+ }
1689
+ else
1690
+ {
1691
+ if (sel && sel.anchorNode.parentNode.tagName == 'A')
1692
+ {
1693
+ var url = sel.anchorNode.parentNode.href;
1694
+ var text = sel.anchorNode.parentNode.text;
1695
+ if (sel.toString() === '') this.insert_link_node = sel.anchorNode.parentNode;
1696
+ }
1697
+ else
1698
+ {
1699
+ var text = sel.toString();
1700
+ var url = '';
1701
+ }
1702
+ }
1703
+
1704
+ $('.redactor_link_text').val(text);
1705
+ $('#redactor_link_url').val(url).focus();
1706
+
1707
+ $('#redactor_insert_link_btn').click($.proxy(this.insertLink, this));
1708
+
1709
+ if (this.opts.linkFileUpload === false)
1710
+ {
1711
+ $('#redactor_tabs a').eq(3).remove();
1712
+ }
1713
+ else
1714
+ {
1715
+ // dragupload
1716
+ if ($('#redactor_file').size() != 0)
1717
+ {
1718
+ $('#redactor_file').dragupload(
1719
+ {
1720
+ url: this.opts.linkFileUpload,
1721
+ success: $.proxy(this.insertLinkFile, this)
1722
+ });
1723
+ }
1724
+
1725
+ // ajax upload
1726
+ this.uploadInit('redactor_file', { auto: true, url: this.opts.linkFileUpload, success: $.proxy(this.insertLinkFile, this) });
1727
+ }
1728
+
1729
+ }, this);
1730
+
1731
+ this.modalInit(RLANG.link, this.opts.path + '/plugins/link.html', 460, handler);
1732
+
1733
+ },
1734
+ insertLink: function()
1735
+ {
1736
+ var tab_selected = $('#redactor_tab_selected').val();
1737
+
1738
+ var link = '', text = '';
1739
+
1740
+ if (tab_selected == 1) // url
1741
+ {
1742
+ link = $('#redactor_link_url').val();
1743
+ text = $('#redactor_link_url_text').val();
1744
+ }
1745
+ else if (tab_selected == 2) // mailto
1746
+ {
1747
+ link = 'mailto:' + $('#redactor_link_mailto').val();
1748
+ text = $('#redactor_link_mailto_text').val();
1749
+ }
1750
+ else if (tab_selected == 3) // anchor
1751
+ {
1752
+ link = '#' + $('#redactor_link_anchor').val();
1753
+ text = $('#redactor_link_anchor_text').val();
1754
+ }
1755
+
1756
+ this._insertLink('<a href="' + link + '">' + text + '</a> ', $.trim(text), link);
1757
+
1758
+ },
1759
+ insertLinkFile: function(data)
1760
+ {
1761
+ text = $('#redactor_link_file_text').val();
1762
+
1763
+ this._insertLink('<a href="' + data + '">' + text + '</a> ', $.trim(text), data);
1764
+ },
1765
+ _insertLink: function(a, text, link)
1766
+ {
1767
+ if (text != '')
1768
+ {
1769
+ if (this.insert_link_node)
1770
+ {
1771
+ $(this.insert_link_node).text(text);
1772
+ $(this.insert_link_node).attr('href', link);
1773
+ this.syncCode();
1774
+ }
1775
+ else
1776
+ {
1777
+ if ($.browser.msie)
1778
+ {
1779
+ $(this.doc.getElementById('span' + this.spanid)).replaceWith(a);
1780
+ this.syncCode();
1781
+ }
1782
+ else this.execCommand('inserthtml', a);
1783
+ }
1784
+ }
1785
+
1786
+ this.modalClose();
1787
+ },
1788
+
1789
+ // INSERT FILE
1790
+ showFile: function()
1791
+ {
1792
+ if ($.browser.msie) this.markerIE();
1793
+
1794
+ var handler = $.proxy(function()
1795
+ {
1796
+ $('#redactor_file').dragupload(
1797
+ {
1798
+ url: this.opts.fileUpload,
1799
+ success: $.proxy(function(data)
1800
+ {
1801
+ this.fileUploadCallback(data);
1802
+ }, this)
1803
+ });
1804
+
1805
+ this.uploadInit('redactor_file', { auto: true, url: this.opts.fileUpload, success: $.proxy(function(data) {
1806
+
1807
+ this.fileUploadCallback(data);
1808
+
1809
+ }, this)});
1810
+ }, this);
1811
+
1812
+ this.modalInit(RLANG.file, this.opts.path + '/plugins/file.html', 500, handler);
1813
+ },
1814
+ fileUploadCallback: function(data)
1815
+ {
1816
+ // chrome fix
1817
+ if ($.browser.webkit && !!window.chrome) data = data + '&nbsp;';
1818
+
1819
+ if ($.browser.msie)
1820
+ {
1821
+ $(this.doc.getElementById('span' + this.spanid)).after(data).remove();
1822
+ this.syncCode();
1823
+ }
1824
+ else this.execCommand('inserthtml', data);
1825
+
1826
+ this.modalClose();
1827
+ },
1828
+
1829
+
1830
+
1831
+ // MODAL
1832
+ modalInit: function(title, url, width, handler, scroll)
1833
+ {
1834
+ // modal overlay
1835
+ if ($('#redactor_modal_overlay').size() == 0)
1836
+ {
1837
+ this.overlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>');
1838
+ $('body').prepend(this.overlay);
1839
+ }
1840
+
1841
+ if (this.opts.overlay)
1842
+ {
1843
+ $('#redactor_modal_overlay').show();
1844
+ $('#redactor_modal_overlay').click($.proxy(this.modalClose, this));
1845
+ }
1846
+
1847
+ if ($('#redactor_modal').size() == 0)
1848
+ {
1849
+ this.modal = $('<div id="redactor_modal" style="display: none;"><div id="redactor_modal_close">&times;</div><div id="redactor_modal_header"></div><div id="redactor_modal_inner"></div></div>');
1850
+ $('body').append(this.modal);
1851
+ }
1852
+
1853
+ $('#redactor_modal_close').click($.proxy(this.modalClose, this));
1854
+
1855
+ this.hdlModalClose = $.proxy(function(e) { if( e.keyCode == 27) this.modalClose(); }, this);
1856
+
1857
+ $(document).keyup(this.hdlModalClose);
1858
+ $(this.doc).keyup(this.hdlModalClose);
1859
+
1860
+ $.ajax({
1861
+ dataType: 'html',
1862
+ type: 'get',
1863
+ url: url,
1864
+ success: $.proxy(function(data)
1865
+ {
1866
+ // parse lang
1867
+ $.each(RLANG, function(i,s)
1868
+ {
1869
+ var re = new RegExp("%RLANG\." + i + "%","gi");
1870
+ data = data.replace(re, s);
1871
+ });
1872
+
1873
+ $('#redactor_modal_inner').html(data);
1874
+ $('#redactor_modal_header').html(title);
1875
+
1876
+ // tabs
1877
+ if ($('#redactor_tabs').size() != 0)
1878
+ {
1879
+ $('#redactor_tabs a').each(function(i,s)
1880
+ {
1881
+ i++;
1882
+ $(s).click(function()
1883
+ {
1884
+ $('#redactor_tabs a').removeClass('redactor_tabs_act');
1885
+ $(this).addClass('redactor_tabs_act');
1886
+ $('.redactor_tab').hide();
1887
+ $('#redactor_tab' + i).show();
1888
+ $('#redactor_tab_selected').val(i);
1889
+
1890
+ var height = $('#redactor_modal').outerHeight();
1891
+ $('#redactor_modal').css('margin-top', '-' + (height+10)/2 + 'px');
1892
+ });
1893
+ });
1894
+ }
1895
+
1896
+ $('#redactor_btn_modal_close').click($.proxy(this.modalClose, this));
1897
+
1898
+ // callback
1899
+ if (typeof(handler) == 'function') handler();
1900
+
1901
+ // setup
1902
+ var height = $('#redactor_modal').outerHeight();
1903
+
1904
+ $('#redactor_modal').css({ width: width + 'px', height: 'auto', marginTop: '-' + (height+10)/2 + 'px', marginLeft: '-' + (width+60)/2 + 'px' }).fadeIn('fast');
1905
+
1906
+ if (scroll === true)
1907
+ {
1908
+ $('#redactor_image_box').height(300).css('overflow', 'auto');
1909
+ }
1910
+
1911
+ }, this)
1912
+ });
1913
+ },
1914
+ modalClose: function()
1915
+ {
1916
+
1917
+ $('#redactor_modal_close').unbind('click', this.modalClose);
1918
+ $('#redactor_modal').fadeOut('fast', $.proxy(function()
1919
+ {
1920
+ $('#redactor_modal_inner').html('');
1921
+
1922
+ if (this.opts.overlay)
1923
+ {
1924
+ $('#redactor_modal_overlay').hide();
1925
+ $('#redactor_modal_overlay').unbind('click', this.modalClose);
1926
+ }
1927
+
1928
+ $(document).unbind('keyup', this.hdlModalClose);
1929
+ $(this.doc).unbind('keyup', this.hdlModalClose);
1930
+
1931
+ }, this));
1932
+
1933
+ },
1934
+
1935
+ // UPLOAD
1936
+ uploadInit: function(element, options)
1937
+ {
1938
+ // Upload Options
1939
+ this.uploadOptions = {
1940
+ url: false,
1941
+ success: false,
1942
+ start: false,
1943
+ trigger: false,
1944
+ auto: false,
1945
+ input: false
1946
+ };
1947
+
1948
+ $.extend(this.uploadOptions, options);
1949
+
1950
+ // Test input or form
1951
+ if ($('#' + element).size() != 0 && $('#' + element).get(0).tagName == 'INPUT')
1952
+ {
1953
+ this.uploadOptions.input = $('#' + element);
1954
+ this.element = $($('#' + element).get(0).form);
1955
+ }
1956
+ else
1957
+ {
1958
+ this.element = $('#' + element);
1959
+ }
1960
+
1961
+ this.element_action = this.element.attr('action');
1962
+
1963
+ // Auto or trigger
1964
+ if (this.uploadOptions.auto)
1965
+ {
1966
+ $(this.uploadOptions.input).change($.proxy(function()
1967
+ {
1968
+ this.element.submit(function(e) { return false; });
1969
+ this.uploadSubmit();
1970
+ }, this));
1971
+
1972
+ }
1973
+ else if (this.uploadOptions.trigger)
1974
+ {
1975
+ $('#' + this.uploadOptions.trigger).click($.proxy(this.uploadSubmit, this));
1976
+ }
1977
+ },
1978
+ uploadSubmit : function()
1979
+ {
1980
+ this.uploadForm(this.element, this.uploadFrame());
1981
+ },
1982
+ uploadFrame : function()
1983
+ {
1984
+ this.id = 'f' + Math.floor(Math.random() * 99999);
1985
+
1986
+ var d = document.createElement('div');
1987
+ var iframe = '<iframe style="display:none" src="about:blank" id="'+this.id+'" name="'+this.id+'"></iframe>';
1988
+ d.innerHTML = iframe;
1989
+ document.body.appendChild(d);
1990
+
1991
+ // Start
1992
+ if (this.uploadOptions.start) this.uploadOptions.start();
1993
+
1994
+ $('#' + this.id).load($.proxy(this.uploadLoaded, this));
1995
+
1996
+ return this.id;
1997
+ },
1998
+ uploadForm : function(f, name)
1999
+ {
2000
+ if (this.uploadOptions.input)
2001
+ {
2002
+ var formId = 'redactorUploadForm' + this.id;
2003
+ var fileId = 'redactorUploadFile' + this.id;
2004
+ this.form = $('<form action="' + this.uploadOptions.url + '" method="POST" target="' + name + '" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
2005
+
2006
+ var oldElement = this.uploadOptions.input;
2007
+ var newElement = $(oldElement).clone();
2008
+ $(oldElement).attr('id', fileId);
2009
+ $(oldElement).before(newElement);
2010
+ $(oldElement).appendTo(this.form);
2011
+ $(this.form).css('position', 'absolute');
2012
+ $(this.form).css('top', '-2000px');
2013
+ $(this.form).css('left', '-2000px');
2014
+ $(this.form).appendTo('body');
2015
+
2016
+ this.form.submit();
2017
+ }
2018
+ else
2019
+ {
2020
+ f.attr('target', name);
2021
+ f.attr('method', 'POST');
2022
+ f.attr('enctype', 'multipart/form-data');
2023
+ f.attr('action', this.uploadOptions.url);
2024
+
2025
+ this.element.submit();
2026
+ }
2027
+
2028
+ },
2029
+ uploadLoaded : function()
2030
+ {
2031
+ var i = $('#' + this.id);
2032
+
2033
+ if (i.contentDocument) var d = i.contentDocument;
2034
+ else if (i.contentWindow) var d = i.contentWindow.document;
2035
+ else var d = window.frames[this.id].document;
2036
+
2037
+ if (d.location.href == "about:blank") return true;
2038
+
2039
+ // Success
2040
+ if (this.uploadOptions.success) this.uploadOptions.success(d.body.innerHTML);
2041
+
2042
+ this.element.attr('action', this.element_action);
2043
+ this.element.attr('target', '');
2044
+
2045
+ },
2046
+
2047
+ // UTILITY
2048
+ markerIE: function()
2049
+ {
2050
+ this.spanid = Math.floor(Math.random() * 99999);
2051
+ this.execCommand('inserthtml', '<span id="span' + this.spanid + '"></span>');
2052
+ },
2053
+ oldIE: function()
2054
+ {
2055
+ if ($.browser.msie && parseInt($.browser.version, 10) < 9) return true;
2056
+ return false;
2057
+ },
2058
+ outerHTML: function(s)
2059
+ {
2060
+ return $("<p>").append($(s).eq(0).clone()).html();
2061
+ },
2062
+ normalize: function(str)
2063
+ {
2064
+ return parseInt(str.replace('px',''));
2065
+ }
2066
+
2067
+ };
2068
+
2069
+
2070
+ // API
2071
+ $.fn.getDoc = function()
2072
+ {
2073
+ return $(this.data('redactor').doc);
2074
+ };
2075
+
2076
+ $.fn.getFrame = function()
2077
+ {
2078
+ return this.data('redactor').$frame;
2079
+ };
2080
+
2081
+ $.fn.getEditor = function()
2082
+ {
2083
+ return this.data('redactor').$editor;
2084
+ };
2085
+
2086
+ $.fn.getCode = function()
2087
+ {
2088
+ return this.data('redactor').getCode();
2089
+ };
2090
+
2091
+ $.fn.setCode = function(html)
2092
+ {
2093
+ this.data('redactor').setCode(html);
2094
+ };
2095
+
2096
+ $.fn.insertHtml = function(html)
2097
+ {
2098
+ this.data('redactor').insertHtml(html);
2099
+ };
2100
+
2101
+ $.fn.destroyEditor = function()
2102
+ {
2103
+ this.data('redactor').destroy();
2104
+ this.removeData('redactor');
2105
+ };
2106
+
2107
+ $.fn.setFocus = function()
2108
+ {
2109
+ this.data('redactor').focus();
2110
+ };
2111
+
2112
+ $.fn.execCommand = function(cmd, param)
2113
+ {
2114
+ this.data('redactor').execCommand(cmd, param);
2115
+ };
2116
+
2117
+ })(jQuery);
2118
+
2119
+ /*
2120
+ Plugin Drag and drop Upload v1.0.1
2121
+ http://imperavi.com/
2122
+ Copyright 2012, Imperavi Ltd.
2123
+ */
2124
+ (function($){
2125
+
2126
+ // Initialization
2127
+ $.fn.dragupload = function(options)
2128
+ {
2129
+ return this.each(function() {
2130
+ var obj = new Construct(this, options);
2131
+ obj.init();
2132
+ });
2133
+ };
2134
+
2135
+ // Options and variables
2136
+ function Construct(el, options) {
2137
+
2138
+ this.opts = $.extend({
2139
+
2140
+ url: false,
2141
+ success: false,
2142
+ preview: false,
2143
+
2144
+ text: RLANG.drop_file_here,
2145
+ atext: RLANG.or_choose
2146
+
2147
+ }, options);
2148
+
2149
+ this.$el = $(el);
2150
+ }
2151
+
2152
+ // Functionality
2153
+ Construct.prototype = {
2154
+ init: function()
2155
+ {
2156
+ if (!$.browser.opera && !$.browser.msie)
2157
+ {
2158
+
2159
+ this.droparea = $('<div class="redactor_droparea"></div>');
2160
+ this.dropareabox = $('<div class="redactor_dropareabox">' + this.opts.text + '</div>');
2161
+ this.dropalternative = $('<div class="redactor_dropalternative">' + this.opts.atext + '</div>');
2162
+
2163
+ this.droparea.append(this.dropareabox);
2164
+
2165
+ this.$el.before(this.droparea);
2166
+ this.$el.before(this.dropalternative);
2167
+
2168
+ // drag over
2169
+ this.dropareabox.bind('dragover', $.proxy(function() { return this.ondrag(); }, this));
2170
+
2171
+ // drag leave
2172
+ this.dropareabox.bind('dragleave', $.proxy(function() { return this.ondragleave(); }, this));
2173
+
2174
+ // drop
2175
+ this.dropareabox.get(0).ondrop = $.proxy(function(event)
2176
+ {
2177
+ event.preventDefault();
2178
+
2179
+ this.dropareabox.removeClass('hover').addClass('drop');
2180
+
2181
+ var file = event.dataTransfer.files[0];
2182
+
2183
+ var fd = new FormData();
2184
+ fd.append('file', file);
2185
+
2186
+ $.ajax({
2187
+ dataType: 'html',
2188
+ url: this.opts.url,
2189
+ data: fd,
2190
+ //xhr: provider,
2191
+ cache: false,
2192
+ contentType: false,
2193
+ processData: false,
2194
+ type: 'POST',
2195
+ success: $.proxy(function(data)
2196
+ {
2197
+ if (this.opts.success !== false) this.opts.success(data);
2198
+ if (this.opts.preview === true) this.dropareabox.html(data);
2199
+ }, this)
2200
+ });
2201
+
2202
+ }, this);
2203
+ }
2204
+ },
2205
+ ondrag: function()
2206
+ {
2207
+ this.dropareabox.addClass('hover');
2208
+ return false;
2209
+ },
2210
+ ondragleave: function()
2211
+ {
2212
+ this.dropareabox.removeClass('hover');
2213
+ return false;
2214
+ }
2215
+ };
2216
+
2217
+ })(jQuery);
2218
+
2219
+
2220
+ // Define: Linkify plugin from stackoverflow
2221
+ (function($){
2222
+
2223
+ var url1 = /(^|&lt;|\s)(www\..+?\..+?)(\s|&gt;|$)/g,
2224
+ url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/g,
2225
+
2226
+ linkifyThis = function ()
2227
+ {
2228
+ var childNodes = this.childNodes,
2229
+ i = childNodes.length;
2230
+ while(i--)
2231
+ {
2232
+ var n = childNodes[i];
2233
+ if (n.nodeType == 3)
2234
+ {
2235
+ var html = n.nodeValue;
2236
+ if (html)
2237
+ {
2238
+ html = html.replace(/&/g, '&amp;')
2239
+ .replace(/</g, '&lt;')
2240
+ .replace(/>/g, '&gt;')
2241
+ .replace(url1, '$1<a href="http://$2">$2</a>$3')
2242
+ .replace(url2, '$1<a href="$2">$2</a>$5');
2243
+
2244
+ $(n).after(html).remove();
2245
+ }
2246
+ }
2247
+ else if (n.nodeType == 1 && !/^(a|button|textarea)$/i.test(n.tagName))
2248
+ {
2249
+ linkifyThis.call(n);
2250
+ }
2251
+ }
2252
+ };
2253
+
2254
+ $.fn.linkify = function ()
2255
+ {
2256
+ this.each(linkifyThis);
2257
+ };
2258
+
2259
+ })(jQuery);