activeadmin-settings 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/app/{controller → controllers}/activeadmin_settings/admin_users_controller.rb +0 -0
  2. data/app/controllers/activeadmin_settings/pictures_controller.rb +19 -0
  3. data/app/{controller → controllers}/activeadmin_settings/settings_controller.rb +0 -0
  4. data/app/models/activeadmin_settings/picture.rb +48 -0
  5. data/app/uploaders/activeadmin_settings/redactor_picture_uploader.rb +97 -0
  6. data/app/views/admin/settings/_settings_table.html.erb +8 -4
  7. data/config/routes.rb +3 -0
  8. data/lib/activeadmin-settings.rb +13 -0
  9. data/lib/activeadmin-settings/version.rb +1 -1
  10. data/vendor/assets/javascripts/activeadmin_settings/index.js.coffee +1 -0
  11. data/vendor/assets/javascripts/activeadmin_settings/settings.js.coffee +0 -2
  12. data/vendor/assets/javascripts/activeadmin_settings/tabs.js.coffee +26 -0
  13. data/vendor/assets/javascripts/redactor/css/docstyle.css +139 -0
  14. data/vendor/assets/javascripts/redactor/css/style.css +135 -0
  15. data/vendor/assets/javascripts/redactor/css/wym.css +151 -0
  16. data/vendor/assets/javascripts/redactor/index.js +1 -0
  17. data/vendor/assets/javascripts/redactor/langs/bg.js +67 -0
  18. data/vendor/assets/javascripts/redactor/langs/by.js +65 -0
  19. data/vendor/assets/javascripts/redactor/langs/cs.js +77 -0
  20. data/vendor/assets/javascripts/redactor/langs/de.js +70 -0
  21. data/vendor/assets/javascripts/redactor/langs/en.js +66 -0
  22. data/vendor/assets/javascripts/redactor/langs/eo.js +66 -0
  23. data/vendor/assets/javascripts/redactor/langs/es.js +66 -0
  24. data/vendor/assets/javascripts/redactor/langs/fa.js +66 -0
  25. data/vendor/assets/javascripts/redactor/langs/fi.js +69 -0
  26. data/vendor/assets/javascripts/redactor/langs/fr.js +76 -0
  27. data/vendor/assets/javascripts/redactor/langs/hr.js +69 -0
  28. data/vendor/assets/javascripts/redactor/langs/hu.js +67 -0
  29. data/vendor/assets/javascripts/redactor/langs/it.js +68 -0
  30. data/vendor/assets/javascripts/redactor/langs/ja.js +66 -0
  31. data/vendor/assets/javascripts/redactor/langs/ko.js +66 -0
  32. data/vendor/assets/javascripts/redactor/langs/lv.js +65 -0
  33. data/vendor/assets/javascripts/redactor/langs/nl.js +69 -0
  34. data/vendor/assets/javascripts/redactor/langs/pl.js +66 -0
  35. data/vendor/assets/javascripts/redactor/langs/pt_br.js +72 -0
  36. data/vendor/assets/javascripts/redactor/langs/ru.js +66 -0
  37. data/vendor/assets/javascripts/redactor/langs/sk.js +66 -0
  38. data/vendor/assets/javascripts/redactor/langs/sq.js +69 -0
  39. data/vendor/assets/javascripts/redactor/langs/tr.js +66 -0
  40. data/vendor/assets/javascripts/redactor/langs/ua.js +67 -0
  41. data/vendor/assets/javascripts/redactor/langs/zh_cn.js +67 -0
  42. data/vendor/assets/javascripts/redactor/langs/zh_tw.js +66 -0
  43. data/vendor/assets/javascripts/redactor/redactor.js.erb +3375 -0
  44. data/vendor/assets/stylesheets/activeadmin_settings.css.scss +4 -1
  45. data/vendor/assets/stylesheets/redactor/css/docstyle.css +139 -0
  46. data/vendor/assets/stylesheets/redactor/css/redactor.css +410 -0
  47. data/vendor/assets/stylesheets/redactor/css/style.css +135 -0
  48. data/vendor/assets/stylesheets/redactor/css/wym.css +151 -0
  49. data/vendor/assets/stylesheets/redactor/img/icons.png +0 -0
  50. data/vendor/assets/stylesheets/redactor/index.css +1 -0
  51. metadata +44 -4
@@ -0,0 +1,3375 @@
1
+ /*
2
+ Redactor v7.7.2
3
+ Updated: July 19, 2012
4
+
5
+ http://redactorjs.com/
6
+
7
+ Copyright (c) 2009-2012, Imperavi Ltd.
8
+ License: http://redactorjs.com/license/
9
+
10
+ Usage: $('#content').redactor();
11
+ */
12
+
13
+ if (typeof RELANG === 'undefined')
14
+ {
15
+ var RELANG = {};
16
+ }
17
+
18
+ var RLANG = {
19
+ html: 'HTML',
20
+ video: 'Insert Video...',
21
+ image: 'Insert Image...',
22
+ table: 'Table',
23
+ link: 'Link',
24
+ link_insert: 'Insert Link ...',
25
+ unlink: 'Unlink',
26
+ formatting: 'Formatting',
27
+ paragraph: 'Paragraph',
28
+ quote: 'Quote',
29
+ code: 'Code',
30
+ header1: 'Header 1',
31
+ header2: 'Header 2',
32
+ header3: 'Header 3',
33
+ header4: 'Header 4',
34
+ bold: 'Bold',
35
+ italic: 'Italic',
36
+ fontcolor: 'Font Color',
37
+ backcolor: 'Back Color',
38
+ unorderedlist: 'Unordered List',
39
+ orderedlist: 'Ordered List',
40
+ outdent: 'Outdent',
41
+ indent: 'Indent',
42
+ cancel: 'Cancel',
43
+ insert: 'Insert',
44
+ save: 'Save',
45
+ _delete: 'Delete',
46
+ insert_table: 'Insert Table...',
47
+ insert_row_above: 'Add Row Above',
48
+ insert_row_below: 'Add Row Below',
49
+ insert_column_left: 'Add Column Left',
50
+ insert_column_right: 'Add Column Right',
51
+ delete_column: 'Delete Column',
52
+ delete_row: 'Delete Row',
53
+ delete_table: 'Delete Table',
54
+ rows: 'Rows',
55
+ columns: 'Columns',
56
+ add_head: 'Add Head',
57
+ delete_head: 'Delete Head',
58
+ title: 'Title',
59
+ image_position: 'Position',
60
+ none: 'None',
61
+ left: 'Left',
62
+ right: 'Right',
63
+ image_web_link: 'Image Web Link',
64
+ text: 'Text',
65
+ mailto: 'Email',
66
+ web: 'URL',
67
+ video_html_code: 'Video Embed Code',
68
+ file: 'Insert File...',
69
+ upload: 'Upload',
70
+ download: 'Download',
71
+ choose: 'Choose',
72
+ or_choose: 'Or choose',
73
+ drop_file_here: 'Drop file here',
74
+ align_left: 'Align Left',
75
+ align_center: 'Align Center',
76
+ align_right: 'Align Right',
77
+ align_justify: 'Justify',
78
+ horizontalrule: 'Insert Horizontal Rule',
79
+ fullscreen: 'Fullscreen',
80
+ deleted: 'Deleted',
81
+ anchor: 'Anchor'
82
+ };
83
+
84
+
85
+
86
+
87
+ (function($){
88
+
89
+ "use strict";
90
+
91
+ // Plugin
92
+ jQuery.fn.redactor = function(option)
93
+ {
94
+ return this.each(function()
95
+ {
96
+ var $obj = $(this);
97
+
98
+ var data = $obj.data('redactor');
99
+ if (!data)
100
+ {
101
+ $obj.data('redactor', (data = new Redactor(this, option)));
102
+ }
103
+ });
104
+ };
105
+
106
+
107
+ // Initialization
108
+ var Redactor = function(element, options)
109
+ {
110
+ // Element
111
+ this.$el = $(element);
112
+
113
+ // Lang
114
+ if (typeof options !== 'undefined' && typeof options.lang !== 'undefined' && options.lang !== 'en' && typeof RELANG[options.lang] !== 'undefined')
115
+ {
116
+ RLANG = RELANG[options.lang];
117
+ }
118
+
119
+ // Options
120
+ this.opts = $.extend({
121
+
122
+ lang: 'en',
123
+ direction: 'ltr', // ltr or rtl
124
+
125
+ callback: false, // function
126
+ keyupCallback: false, // function
127
+ keydownCallback: false, // function
128
+ execCommandCallback: false, // function
129
+
130
+ path: false,
131
+ css: 'style.css',
132
+ css_path: '<%= asset_path 'redactor/css/style.css' %>',
133
+ focus: false,
134
+ resize: true,
135
+ autoresize: false,
136
+ fixed: false,
137
+
138
+ autoformat: true,
139
+ cleanUp: true,
140
+ removeStyles: false,
141
+ removeClasses: false,
142
+ convertDivs: true,
143
+ convertLinks: true,
144
+ xhtml: false,
145
+
146
+ handler: false, // false or url
147
+
148
+ autosave: false, // false or url
149
+ interval: 60, // seconds
150
+
151
+ imageGetJson: '/admin/redactor/pictures', // url (ex. /folder/images.json ) or false
152
+
153
+ imageUpload: '/admin/redactor/pictures', // url
154
+ imageUploadCallback: false, // function
155
+
156
+ fileUpload: false, // url
157
+ fileUploadCallback: false, // function
158
+
159
+ observeImages: true,
160
+ visual: true,
161
+ fullscreen: false,
162
+ overlay: true, // modal overlay
163
+
164
+ buttonsCustom: {},
165
+ buttonsAdd: [],
166
+ buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
167
+ 'image', 'video', 'file', 'table', 'link', '|',
168
+ 'fontcolor', 'backcolor', '|', 'alignleft', 'aligncenter', 'alignright', 'justify', '|',
169
+ 'horizontalrule', 'fullscreen'],
170
+
171
+ colors: [
172
+ '#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00',
173
+ '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca',
174
+ '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694',
175
+ '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314',
176
+ '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100',
177
+ '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000'],
178
+
179
+ // private
180
+ allEmptyHtml: '<p><br /></p>',
181
+ mozillaEmptyHtml: '<p>&nbsp;</p>',
182
+
183
+ // modal windows container
184
+ modal_file: String() +
185
+ '<form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">' +
186
+ '<label>Name (optional)</label>' +
187
+ '<input type="text" id="redactor_filename" class="redactor_input" />' +
188
+ '<div style="margin-top: 7px;">' +
189
+ '<input type="file" id="redactor_file" name="file" />' +
190
+ '</div>' +
191
+ '</form>',
192
+
193
+ modal_image_edit: String() +
194
+ '<label>' + RLANG.title + '</label>' +
195
+ '<input id="redactor_file_alt" class="redactor_input" />' +
196
+ '<label>' + RLANG.link + '</label>' +
197
+ '<input id="redactor_file_link" class="redactor_input" />' +
198
+ '<label>' + RLANG.image_position + '</label>' +
199
+ '<select id="redactor_form_image_align">' +
200
+ '<option value="none">' + RLANG.none + '</option>' +
201
+ '<option value="left">' + RLANG.left + '</option>' +
202
+ '<option value="right">' + RLANG.right + '</option>' +
203
+ '</select>' +
204
+ '<div id="redactor_modal_footer">' +
205
+ '<a href="javascript:void(null);" id="redactor_image_delete_btn" style="color: #000;">' + RLANG._delete + '</a>' +
206
+ '<span class="redactor_btns_box">' +
207
+ '<input type="button" name="save" id="redactorSaveBtn" value="' + RLANG.save + '" />' +
208
+ '<a href="javascript:void(null);" id="redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
209
+ '</span>' +
210
+ '</div>',
211
+
212
+ modal_image: String() +
213
+ '<div id="redactor_tabs">' +
214
+ '<a href="javascript:void(null);" class="redactor_tabs_act">' + RLANG.upload + '</a>' +
215
+ '<a href="javascript:void(null);">' + RLANG.choose + '</a>' +
216
+ '<a href="javascript:void(null);">' + RLANG.link + '</a>' +
217
+ '</div>' +
218
+ '<form id="redactorInsertImageForm" method="post" action="" enctype="multipart/form-data">' +
219
+ '<div id="redactor_tab1" class="redactor_tab">' +
220
+ '<input type="file" id="redactor_file" name="file" />' +
221
+ '</div>' +
222
+ '<div id="redactor_tab2" class="redactor_tab" style="display: none;">' +
223
+ '<div id="redactor_image_box"></div>' +
224
+ '</div>' +
225
+ '</form>' +
226
+ '<div id="redactor_tab3" class="redactor_tab" style="display: none;">' +
227
+ '<label>' + RLANG.image_web_link + '</label>' +
228
+ '<input name="redactor_file_link" id="redactor_file_link" class="redactor_input" />' +
229
+ '</div>' +
230
+ '<div id="redactor_modal_footer">' +
231
+ '<span class="redactor_btns_box">' +
232
+ '<input type="button" name="upload" id="redactor_upload_btn" value="' + RLANG.insert + '" />' +
233
+ '<a href="javascript:void(null);" id="redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
234
+ '</span>' +
235
+ '</div>',
236
+
237
+ modal_link: String() +
238
+ '<form id="redactorInsertLinkForm" method="post" action="">' +
239
+ '<div id="redactor_tabs">' +
240
+ '<a href="javascript:void(null);" class="redactor_tabs_act">URL</a>' +
241
+ '<a href="javascript:void(null);">Email</a>' +
242
+ '<a href="javascript:void(null);">' + RLANG.anchor + '</a>' +
243
+ '</div>' +
244
+ '<input type="hidden" id="redactor_tab_selected" value="1" />' +
245
+ '<div class="redactor_tab" id="redactor_tab1">' +
246
+ '<label>URL</label><input id="redactor_link_url" class="redactor_input" />' +
247
+ '<label>' + RLANG.text + '</label><input class="redactor_input redactor_link_text" id="redactor_link_url_text" />' +
248
+ '</div>' +
249
+ '<div class="redactor_tab" id="redactor_tab2" style="display: none;">' +
250
+ '<label>Email</label><input id="redactor_link_mailto" class="redactor_input" />' +
251
+ '<label>' + RLANG.text + '</label><input class="redactor_input redactor_link_text" id="redactor_link_mailto_text" />' +
252
+ '</div>' +
253
+ '<div class="redactor_tab" id="redactor_tab3" style="display: none;">' +
254
+ '<label>' + RLANG.anchor + '</label><input class="redactor_input" id="redactor_link_anchor" />' +
255
+ '<label>' + RLANG.text + '</label><input class="redactor_input redactor_link_text" id="redactor_link_anchor_text" />' +
256
+ '</div>' +
257
+ '</form>' +
258
+ '<div id="redactor_modal_footer">' +
259
+ '<span class="redactor_btns_box">' +
260
+ '<input type="button" id="redactor_insert_link_btn" value="' + RLANG.insert + '" />' +
261
+ '<a href="javascript:void(null);" id="redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
262
+ '</span>' +
263
+ '</div>',
264
+
265
+ modal_table: String() +
266
+ '<label>' + RLANG.rows + '</label>' +
267
+ '<input size="5" value="2" id="redactor_table_rows" />' +
268
+ '<label>' + RLANG.columns + '</label>' +
269
+ '<input size="5" value="3" id="redactor_table_columns" />' +
270
+ '<div id="redactor_modal_footer">' +
271
+ '<span class="redactor_btns_box">' +
272
+ '<input type="button" name="upload" id="redactor_insert_table_btn" value="' + RLANG.insert + '" />' +
273
+ '<a href="javascript:void(null);" id="redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
274
+ '</span>' +
275
+ '</div>',
276
+
277
+ modal_video: String() +
278
+ '<form id="redactorInsertVideoForm">' +
279
+ '<label>' + RLANG.video_html_code + '</label>' +
280
+ '<textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>' +
281
+ '</form>' +
282
+ '<div id="redactor_modal_footer">' +
283
+ '<span class="redactor_btns_box">' +
284
+ '<input type="button" id="redactor_insert_video_btn" value="' + RLANG.insert + '" />' +
285
+ '<a href="javascript:void(null);" id="redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
286
+ '</span>' +
287
+ '</div>',
288
+
289
+
290
+ toolbar: {
291
+ html:
292
+ {
293
+ title: RLANG.html,
294
+ func: 'toggle'
295
+ },
296
+ formatting:
297
+ {
298
+ title: RLANG.formatting,
299
+ func: 'show',
300
+ dropdown:
301
+ {
302
+ p:
303
+ {
304
+ title: RLANG.paragraph,
305
+ exec: 'formatblock'
306
+ },
307
+ blockquote:
308
+ {
309
+ title: RLANG.quote,
310
+ exec: 'formatblock',
311
+ className: 'redactor_format_blockquote'
312
+ },
313
+ pre:
314
+ {
315
+ title: RLANG.code,
316
+ exec: 'formatblock',
317
+ className: 'redactor_format_pre'
318
+ },
319
+ h1:
320
+ {
321
+ title: RLANG.header1,
322
+ exec: 'formatblock',
323
+ className: 'redactor_format_h1'
324
+ },
325
+ h2:
326
+ {
327
+ title: RLANG.header2,
328
+ exec: 'formatblock',
329
+ className: 'redactor_format_h2'
330
+ },
331
+ h3:
332
+ {
333
+ title: RLANG.header3,
334
+ exec: 'formatblock',
335
+ className: 'redactor_format_h3'
336
+ },
337
+ h4:
338
+ {
339
+ title: RLANG.header4,
340
+ exec: 'formatblock',
341
+ className: 'redactor_format_h4'
342
+ }
343
+ }
344
+ },
345
+ bold:
346
+ {
347
+ title: RLANG.bold,
348
+ exec: 'bold'
349
+ },
350
+ italic:
351
+ {
352
+ title: RLANG.italic,
353
+ exec: 'italic'
354
+ },
355
+ deleted:
356
+ {
357
+ title: RLANG.deleted,
358
+ exec: 'strikethrough'
359
+ },
360
+ unorderedlist:
361
+ {
362
+ title: '&bull; ' + RLANG.unorderedlist,
363
+ exec: 'insertunorderedlist'
364
+ },
365
+ orderedlist:
366
+ {
367
+ title: '1. ' + RLANG.orderedlist,
368
+ exec: 'insertorderedlist'
369
+ },
370
+ outdent:
371
+ {
372
+ title: '< ' + RLANG.outdent,
373
+ exec: 'outdent'
374
+ },
375
+ indent:
376
+ {
377
+ title: '> ' + RLANG.indent,
378
+ exec: 'indent'
379
+ },
380
+ image:
381
+ {
382
+ title: RLANG.image,
383
+ func: 'showImage'
384
+ },
385
+ video:
386
+ {
387
+ title: RLANG.video,
388
+ func: 'showVideo'
389
+ },
390
+ file:
391
+ {
392
+ title: RLANG.file,
393
+ func: 'showFile'
394
+ },
395
+ table:
396
+ {
397
+ title: RLANG.table,
398
+ func: 'show',
399
+ dropdown:
400
+ {
401
+ insert_table:
402
+ {
403
+ title: RLANG.insert_table,
404
+ func: 'showTable'
405
+ },
406
+ separator_drop1:
407
+ {
408
+ name: 'separator'
409
+ },
410
+ insert_row_above:
411
+ {
412
+ title: RLANG.insert_row_above,
413
+ func: 'insertRowAbove'
414
+ },
415
+ insert_row_below:
416
+ {
417
+ title: RLANG.insert_row_below,
418
+ func: 'insertRowBelow'
419
+ },
420
+ insert_column_left:
421
+ {
422
+ title: RLANG.insert_column_left,
423
+ func: 'insertColumnLeft'
424
+ },
425
+ insert_column_right:
426
+ {
427
+ title: RLANG.insert_column_right,
428
+ func: 'insertColumnRight'
429
+ },
430
+ separator_drop2:
431
+ {
432
+ name: 'separator'
433
+ },
434
+ add_head:
435
+ {
436
+ title: RLANG.add_head,
437
+ func: 'addHead'
438
+ },
439
+ delete_head:
440
+ {
441
+ title: RLANG.delete_head,
442
+ func: 'deleteHead'
443
+ },
444
+ separator_drop3:
445
+ {
446
+ name: 'separator'
447
+ },
448
+ delete_column:
449
+ {
450
+ title: RLANG.delete_column,
451
+ func: 'deleteColumn'
452
+ },
453
+ delete_row:
454
+ {
455
+ title: RLANG.delete_row,
456
+ func: 'deleteRow'
457
+ },
458
+ delete_table:
459
+ {
460
+ title: RLANG.delete_table,
461
+ func: 'deleteTable'
462
+ }
463
+ }
464
+ },
465
+ link:
466
+ {
467
+ title: RLANG.link,
468
+ func: 'show',
469
+ dropdown:
470
+ {
471
+ link:
472
+ {
473
+ title: RLANG.link_insert,
474
+ func: 'showLink'
475
+ },
476
+ unlink:
477
+ {
478
+ title: RLANG.unlink,
479
+ exec: 'unlink'
480
+ }
481
+ }
482
+ },
483
+ fontcolor:
484
+ {
485
+ title: RLANG.fontcolor,
486
+ func: 'show'
487
+ },
488
+ backcolor:
489
+ {
490
+ title: RLANG.backcolor,
491
+ func: 'show'
492
+ },
493
+ alignleft:
494
+ {
495
+ exec: 'JustifyLeft',
496
+ title: RLANG.align_left
497
+ },
498
+ aligncenter:
499
+ {
500
+ exec: 'JustifyCenter',
501
+ title: RLANG.align_center
502
+ },
503
+ alignright:
504
+ {
505
+ exec: 'JustifyRight',
506
+ title: RLANG.align_right
507
+ },
508
+ justify:
509
+ {
510
+ exec: 'justifyfull',
511
+ title: RLANG.align_justify
512
+ },
513
+ horizontalrule:
514
+ {
515
+ exec: 'inserthorizontalrule',
516
+ title: RLANG.horizontalrule
517
+ },
518
+ fullscreen:
519
+ {
520
+ title: RLANG.fullscreen,
521
+ func: 'fullscreen'
522
+ }
523
+ }
524
+
525
+
526
+ }, options, this.$el.data());
527
+
528
+ this.dropdowns = [];
529
+
530
+ // Init
531
+ this.init();
532
+ };
533
+
534
+ // Functionality
535
+ Redactor.prototype = {
536
+
537
+
538
+ // Initialization
539
+ init: function()
540
+ {
541
+ // get path to styles
542
+ this.getPath();
543
+
544
+ if (this.opts.toolbar !== false)
545
+ {
546
+ $.extend(this.opts.toolbar, this.opts.buttonsCustom);
547
+
548
+ $.each(this.opts.buttonsAdd, $.proxy(function(i,s)
549
+ {
550
+ this.opts.buttons.push(s);
551
+ }, this));
552
+ }
553
+
554
+ // get dimensions
555
+ this.height = this.$el.css('height');
556
+ this.width = this.$el.css('width');
557
+
558
+ // construct editor
559
+ this.build();
560
+
561
+ // get html
562
+ var html = this.$el.val();
563
+
564
+ // preformatter
565
+ html = this.preformater(html);
566
+
567
+ // conver newlines to p
568
+ if (this.opts.autoformat)
569
+ {
570
+ html = this.paragraphy(html);
571
+ }
572
+
573
+ // enable
574
+ this.$editor = this.enable(html);
575
+
576
+ // focus always on page
577
+ this.observeFocus();
578
+
579
+ // cleanup
580
+ if (this.opts.cleanUp === true)
581
+ {
582
+ $(this.doc).bind('paste', $.proxy(function(e)
583
+ {
584
+ setTimeout($.proxy(function ()
585
+ {
586
+ var marker = Math.floor(Math.random() * 99999);
587
+ var marker_text = '';
588
+ if ($.browser.mozilla) marker_text = '&nbsp;';
589
+ var node = $('<span rel="pastemarkerend" id="pastemarkerend' + marker + '">' + marker_text + '</span>');
590
+ this.insertNodeAtCaret(node.get(0));
591
+
592
+ this.pasteCleanUp(marker);
593
+
594
+ }, this), 100);
595
+
596
+ }, this));
597
+ }
598
+
599
+ // keyup
600
+ $(this.doc).keyup($.proxy(function(e)
601
+ {
602
+ var key = e.keyCode || e.which;
603
+
604
+ // callback as you type
605
+ if (typeof this.opts.keyupCallback === 'function')
606
+ {
607
+ this.opts.keyupCallback(this, e);
608
+ }
609
+
610
+ if (this.opts.autoformat)
611
+ {
612
+ // if empty
613
+ if (key === 8 || key === 46)
614
+ {
615
+ return this.formatEmpty(e);
616
+ }
617
+
618
+ // new line p
619
+ if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.metaKey)
620
+ {
621
+ return this.formatNewLine(e);
622
+ }
623
+ }
624
+
625
+ this.syncCode();
626
+
627
+ }, this));
628
+
629
+ // toolbar
630
+ this.buildToolbar();
631
+
632
+ // resizer
633
+ if (this.opts.autoresize === false)
634
+ {
635
+ this.buildResizer();
636
+ }
637
+ else
638
+ {
639
+ this.observeAutoResize();
640
+ }
641
+
642
+ // shortcuts
643
+ this.shortcuts();
644
+
645
+ // autosave
646
+ this.autoSave();
647
+
648
+ // observers
649
+ this.observeImages();
650
+ this.observeTables();
651
+
652
+ // fullscreen on start
653
+ if (this.opts.fullscreen)
654
+ {
655
+ this.opts.fullscreen = false;
656
+ this.fullscreen();
657
+ }
658
+
659
+ // focus
660
+ if (this.opts.focus)
661
+ {
662
+ this.focus();
663
+ }
664
+
665
+ // fixed
666
+ if (this.opts.fixed)
667
+ {
668
+ this.observeScroll();
669
+ $(document).scroll($.proxy(this.observeScroll, this));
670
+ }
671
+
672
+ // callback
673
+ if (typeof this.opts.callback === 'function')
674
+ {
675
+ this.opts.callback(this);
676
+ }
677
+
678
+ },
679
+ shortcuts: function()
680
+ {
681
+ $(this.doc).keydown($.proxy(function(e)
682
+ {
683
+ var key = e.keyCode || e.which;
684
+
685
+ // callback keydown
686
+ if (typeof this.opts.keydownCallback === 'function')
687
+ {
688
+ this.opts.keydownCallback(this, e);
689
+ }
690
+
691
+ if (e.ctrlKey)
692
+ {
693
+ if (key === 90)
694
+ {
695
+ this._shortcuts(e, 'undo'); // Ctrl + z
696
+ }
697
+ else if (key === 90 && e.shiftKey)
698
+ {
699
+ this._shortcuts(e, 'redo'); // Ctrl + Shift + z
700
+ }
701
+ else if (key === 77)
702
+ {
703
+ this._shortcuts(e, 'removeFormat'); // Ctrl + m
704
+ }
705
+ else if (key === 66)
706
+ {
707
+ this._shortcuts(e, 'bold'); // Ctrl + b
708
+ }
709
+ else if (key === 73)
710
+ {
711
+ this._shortcuts(e, 'italic'); // Ctrl + i
712
+ }
713
+ else if (key === 74)
714
+ {
715
+ this._shortcuts(e, 'insertunorderedlist'); // Ctrl + j
716
+ }
717
+ else if (key === 75)
718
+ {
719
+ this._shortcuts(e, 'insertorderedlist'); // Ctrl + k
720
+ }
721
+ else if (key === 76)
722
+ {
723
+ this._shortcuts(e, 'superscript'); // Ctrl + l
724
+ }
725
+ else if (key === 72)
726
+ {
727
+ this._shortcuts(e, 'subscript'); // Ctrl + h
728
+ }
729
+ }
730
+
731
+ if (!e.shiftKey && key === 9)
732
+ {
733
+ this._shortcuts(e, 'indent'); // Tab
734
+ }
735
+ else if (e.shiftKey && key === 9 )
736
+ {
737
+ this._shortcuts(e, 'outdent'); // Shift + tab
738
+ }
739
+
740
+ // safari shift key + enter
741
+ if ($.browser.webkit && navigator.userAgent.indexOf('Chrome') === -1)
742
+ {
743
+ return this.safariShiftKeyEnter(e, key);
744
+ }
745
+
746
+ }, this));
747
+
748
+ },
749
+ _shortcuts: function(e, cmd)
750
+ {
751
+ if (e.preventDefault)
752
+ {
753
+ e.preventDefault();
754
+ }
755
+
756
+ this.execCommand(cmd, false);
757
+ },
758
+ getPath: function()
759
+ {
760
+ if (this.opts.path !== false)
761
+ {
762
+ return this.opts.path;
763
+ }
764
+
765
+ $('script').each($.proxy(function(i,s)
766
+ {
767
+ if (s.src)
768
+ {
769
+ // Match redactor.js or redactor.min.js, followed by an optional querystring (often used for cache purposes)
770
+ var regexp = new RegExp(/\/redactor(\.min)?\.js(\?.*)?/);
771
+ if (s.src.match(regexp))
772
+ {
773
+ this.opts.path = s.src.replace(regexp, '');
774
+ }
775
+ }
776
+ }, this));
777
+
778
+ },
779
+ build: function()
780
+ {
781
+ // container
782
+ this.$box = $('<div class="redactor_box"></div>');
783
+
784
+ // frame
785
+ this.$frame = $('<iframe frameborder="0" scrolling="auto" style="height: ' + this.height + ';" class="redactor_frame"></iframe>');
786
+
787
+ // hide textarea
788
+ this.$el.css('width', '100%').hide();
789
+
790
+ // append box and frame
791
+ this.$box.insertAfter(this.$el).append(this.$frame).append(this.$el);
792
+
793
+ },
794
+ write: function(html)
795
+ {
796
+ this.doc.open();
797
+ this.doc.write(html);
798
+ this.doc.close();
799
+ },
800
+ enable: function(html)
801
+ {
802
+ this.doc = this.getDoc(this.$frame.get(0));
803
+
804
+ if (this.doc !== null)
805
+ {
806
+ this.write(this.setDoc(html));
807
+ return $(this.doc).find('#page');
808
+ }
809
+ else
810
+ {
811
+ return false;
812
+ }
813
+ },
814
+ setDoc: function(html)
815
+ {
816
+ // use absolute css path option if defined
817
+ var css_path = this.opts.path + '/css/' + this.opts.css;
818
+
819
+ if (this.opts.css_path) css_path = this.opts.css_path;
820
+
821
+ var frameHtml = '<!DOCTYPE html>\n' +
822
+ '<html><head><link media="all" type="text/css" href="' + css_path + '" rel="stylesheet"></head>' +
823
+ '<body><div id="page" contenteditable="true" dir="' + this.opts.direction + '">' +
824
+ html +
825
+ '</div></body></html>';
826
+
827
+ return frameHtml;
828
+ },
829
+ getDoc: function(frame)
830
+ {
831
+ if (frame.contentDocument)
832
+ {
833
+ return frame.contentDocument;
834
+ }
835
+ else if (frame.contentWindow && frame.contentWindow.document)
836
+ {
837
+ return frame.contentWindow.document;
838
+ }
839
+ else if (frame.document)
840
+ {
841
+ return frame.document;
842
+ }
843
+ else
844
+ {
845
+ return null;
846
+ }
847
+ },
848
+ focus: function()
849
+ {
850
+ this.$editor.focus();
851
+ },
852
+ syncCode: function()
853
+ {
854
+ var html = this.formatting(this.$editor.html());
855
+ this.$el.val(html);
856
+ },
857
+
858
+ // API functions
859
+ setCode: function(html)
860
+ {
861
+ html = this.preformater(html);
862
+
863
+ this.$editor.html(html).focus();
864
+
865
+ this.syncCode();
866
+ },
867
+ getCode: function()
868
+ {
869
+ var html = this.$editor ? this.$editor.html() : this.$el.val();
870
+ html = this.reformater(html);
871
+
872
+ return html;
873
+ },
874
+ insertHtml: function(html)
875
+ {
876
+ this.execCommand('inserthtml', html);
877
+ this.observeImages();
878
+ },
879
+ destroy: function()
880
+ {
881
+ var html = this.getCode();
882
+
883
+ this.$box.after(this.$el);
884
+ this.$box.remove();
885
+ this.$el.val(html).show();
886
+
887
+ for (var i = 0; i < this.dropdowns.length; i++)
888
+ {
889
+ this.dropdowns[i].remove();
890
+ delete(this.dropdowns[i]);
891
+ }
892
+
893
+ },
894
+ handler: function()
895
+ {
896
+ $.ajax({
897
+ url: this.opts.handler,
898
+ type: 'POST',
899
+ data: 'redactor=' + escape(encodeURIComponent(this.getCode())),
900
+ success: $.proxy(function(data)
901
+ {
902
+ this.setCode(data);
903
+ this.syncCode();
904
+
905
+ }, this)
906
+ });
907
+
908
+ },
909
+ // end API functions
910
+
911
+ // OBSERVERS
912
+ observeFocus: function()
913
+ {
914
+ if ($.browser.msie)
915
+ {
916
+ return false;
917
+ }
918
+
919
+ if ($(this.doc).find('body').height() < $(this.$frame.get(0).contentWindow).height())
920
+ {
921
+ $(this.doc).click($.proxy(function(e) { this.$editor.focus(); }, this));
922
+ }
923
+ },
924
+ observeImages: function()
925
+ {
926
+ if (this.opts.observeImages === false)
927
+ {
928
+ return false;
929
+ }
930
+
931
+ $(this.doc).find('img').each($.proxy(function(i,s)
932
+ {
933
+ if ($.browser.msie) $(s).attr('unselectable', 'on');
934
+ this.resizeImage(s);
935
+
936
+ }, this));
937
+
938
+ },
939
+ observeTables: function()
940
+ {
941
+ $(this.doc).find('body').find('table').click($.proxy(this.tableObserver, this));
942
+ },
943
+ observeScroll: function()
944
+ {
945
+ var scrolltop = $(document).scrollTop();
946
+ var boxtop = this.$box.offset().top;
947
+
948
+ if (scrolltop > boxtop)
949
+ {
950
+ this.fixed = true;
951
+ this.$toolbar.css({ position: 'fixed', width: '100%' });
952
+ }
953
+ else
954
+ {
955
+ this.fixed = false;
956
+ this.$toolbar.css({ position: 'relative', width: 'auto' });
957
+ }
958
+ },
959
+ observeAutoResize: function()
960
+ {
961
+ this.$editor.css({ 'min-height': this.$el.height() + 'px' });
962
+ $(this.doc).find('body').css({ 'overflow': 'hidden' });
963
+ this.setAutoSize(false);
964
+ $(this.doc).keyup($.proxy(this.setAutoSize, this));
965
+ },
966
+ setAutoSize: function(e)
967
+ {
968
+ var key = false;
969
+ if (e !== false)
970
+ {
971
+ key = e.keyCode || e.which;
972
+ }
973
+
974
+ var height = this.$editor.outerHeight(true);
975
+
976
+ if (e === true && (key === 8 || key === 46))
977
+ {
978
+ this.$frame.height(height);
979
+ }
980
+ else
981
+ {
982
+ this.$frame.height(height+30);
983
+ }
984
+
985
+
986
+ },
987
+
988
+
989
+ // EXECCOMMAND
990
+ execCommand: function(cmd, param)
991
+ {
992
+ if (this.opts.visual && this.doc)
993
+ {
994
+ try
995
+ {
996
+ if ($.browser.msie)
997
+ {
998
+ this.focus();
999
+ }
1000
+
1001
+ if (cmd === 'inserthtml' && $.browser.msie)
1002
+ {
1003
+ this.doc.selection.createRange().pasteHTML(param);
1004
+ }
1005
+ else if (cmd === 'formatblock' && $.browser.msie)
1006
+ {
1007
+ this.doc.execCommand(cmd, false, '<' +param + '>');
1008
+ }
1009
+ else
1010
+ {
1011
+ this.doc.execCommand(cmd, false, param);
1012
+ }
1013
+
1014
+ this.syncCode();
1015
+ this.focus();
1016
+
1017
+ if (typeof this.opts.execCommandCallback === 'function')
1018
+ {
1019
+ this.opts.execCommandCallback(this, cmd);
1020
+ }
1021
+ }
1022
+ catch (e) { }
1023
+
1024
+ }
1025
+ },
1026
+
1027
+ // FORMAT NEW LINE
1028
+ formatNewLine: function(e)
1029
+ {
1030
+ var parent = this.getParentNode();
1031
+ if (parent.nodeName === 'DIV' && parent.id === 'page')
1032
+ {
1033
+ if (e.preventDefault)
1034
+ {
1035
+ e.preventDefault();
1036
+ }
1037
+
1038
+ var element = $(this.getCurrentNode());
1039
+ if (element.get(0).tagName === 'DIV' && (element.html() === '' || element.html() === '<br>'))
1040
+ {
1041
+ var newElement = $('<p>').append(element.clone().get(0).childNodes);
1042
+ element.replaceWith(newElement);
1043
+ newElement.html('<br />');
1044
+ this.setFocusNode(newElement.get(0));
1045
+
1046
+ this.syncCode();
1047
+ return false;
1048
+ }
1049
+ else
1050
+ {
1051
+ this.syncCode();
1052
+ }
1053
+
1054
+ // convert links
1055
+ if (this.opts.convertLinks)
1056
+ {
1057
+ this.$editor.linkify();
1058
+ }
1059
+ }
1060
+ else
1061
+ {
1062
+ this.syncCode();
1063
+ return true;
1064
+ }
1065
+ },
1066
+
1067
+ // SAFARI SHIFT KEY + ENTER
1068
+ safariShiftKeyEnter: function(e, key)
1069
+ {
1070
+ if (e.shiftKey && key === 13)
1071
+ {
1072
+ e.preventDefault();
1073
+
1074
+ var node1 = $('<span><br /></span>');
1075
+ this.insertNodeAtCaret(node1.get(0));
1076
+ this.setFocusNode(node1.get(0));
1077
+
1078
+ this.syncCode();
1079
+
1080
+ return false;
1081
+ }
1082
+ else
1083
+ {
1084
+ return true;
1085
+ }
1086
+ },
1087
+
1088
+ // FORMAT EMPTY
1089
+ formatEmpty: function(e)
1090
+ {
1091
+ var html = $.trim(this.$editor.html());
1092
+
1093
+ if ($.browser.mozilla)
1094
+ {
1095
+ html = html.replace(/<br>/gi, '');
1096
+ }
1097
+
1098
+ if (html === '')
1099
+ {
1100
+ if (e.preventDefault)
1101
+ {
1102
+ e.preventDefault();
1103
+ }
1104
+
1105
+ var nodehtml = this.opts.allEmptyHtml;
1106
+ if ($.browser.mozilla)
1107
+ {
1108
+ nodehtml = this.opts.mozillaEmptyHtml;
1109
+ }
1110
+
1111
+ var node = $(nodehtml).get(0);
1112
+ this.$editor.html(node);
1113
+ this.setFocusNode(node);
1114
+
1115
+ this.syncCode();
1116
+ return false;
1117
+ }
1118
+ else
1119
+ {
1120
+ this.syncCode();
1121
+ }
1122
+ },
1123
+
1124
+ // PARAGRAPHY
1125
+ paragraphy: function (str)
1126
+ {
1127
+ str = $.trim(str);
1128
+ if (str === '')
1129
+ {
1130
+ if (!$.browser.mozilla)
1131
+ {
1132
+ return this.opts.allEmptyHtml;
1133
+ }
1134
+ else
1135
+ {
1136
+ return this.opts.mozillaEmptyHtml;
1137
+ }
1138
+ }
1139
+
1140
+ // convert div to p
1141
+ if (this.opts.convertDivs) str = str.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>');
1142
+
1143
+ // inner functions
1144
+ var X = function(x, a, b) { return x.replace(new RegExp(a, 'g'), b); };
1145
+ var R = function(a, b) { return X(str, a, b); };
1146
+
1147
+ // block elements
1148
+ 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])';
1149
+
1150
+ str += '\n';
1151
+
1152
+ R('<br />\\s*<br />', '\n\n');
1153
+ R('(<' + blocks + '[^>]*>)', '\n$1');
1154
+ R('(</' + blocks + '>)', '$1\n\n');
1155
+ R('\r\n|\r', '\n'); // newlines
1156
+ R('\n\n+', '\n\n'); // remove duplicates
1157
+ R('\n?((.|\n)+?)$', '<p>$1</p>\n'); // including one at the end
1158
+ R('<p>\\s*?</p>', ''); // remove empty p
1159
+ R('<p>(<div[^>]*>\\s*)', '$1<p>');
1160
+ R('<p>([^<]+)\\s*?(</(div|address|form)[^>]*>)', '<p>$1</p>$2');
1161
+ R('<p>\\s*(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
1162
+ R('<p>(<li.+?)</p>', '$1');
1163
+ R('<p>\\s*(</?' + blocks + '[^>]*>)', '$1');
1164
+ R('(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
1165
+ R('(</?' + blocks + '[^>]*>)\\s*<br />', '$1');
1166
+ R('<br />(\\s*</?(p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', '$1');
1167
+
1168
+ // pre
1169
+ if (str.indexOf('<pre') != -1)
1170
+ {
1171
+ R('(<pre(.|\n)*?>)((.|\n)*?)</pre>', function(m0, m1, m2, m3)
1172
+ {
1173
+ return X(m1, '\\\\([\'\"\\\\])', '$1') + X(X(X(m3, '<p>', '\n'), '</p>|<br />', ''), '\\\\([\'\"\\\\])', '$1') + '</pre>';
1174
+ });
1175
+ }
1176
+
1177
+ return R('\n</p>$', '</p>');
1178
+ },
1179
+
1180
+ // PREPARE FORMATER
1181
+ preformater: function(html)
1182
+ {
1183
+ if (html !== null)
1184
+ {
1185
+ html = html.replace(/<br>/gi,'<br />');
1186
+ //html = html.replace(/<blockquote\b[^>]*>([\w\W]*?)<p>([\w\W]*?)<\/p>([\w\W]*?)<\/blockquote[^>]*>/gi,'<blockquote>$1$2<br />$3</blockquote>');
1187
+ html = html.replace(/<strong\b[^>]*>([\w\W]*?)<\/strong[^>]*>/gi,'<b>$1</b>');
1188
+ html = html.replace(/<em\b[^>]*>([\w\W]*?)<\/em[^>]*>/gi,'<i>$1</i>');
1189
+ html = html.replace(/<del\b[^>]*>([\w\W]*?)<\/del[^>]*>/gi,'<strike>$1</strike>');
1190
+ }
1191
+ else
1192
+ {
1193
+ html = '';
1194
+ }
1195
+
1196
+ return html;
1197
+ },
1198
+
1199
+ // REVERT FORMATER
1200
+ reformater: function(html)
1201
+ {
1202
+ html = html.replace(/<br>/gi,'<br />');
1203
+ html = html.replace(/<b\b[^>]*>([\w\W]*?)<\/b[^>]*>/gi,'<strong>$1</strong>');
1204
+ html = html.replace(/<i\b[^>]*>([\w\W]*?)<\/i[^>]*>/gi,'<em>$1</em>');
1205
+ html = html.replace(/<strike\b[^>]*>([\w\W]*?)<\/strike[^>]*>/gi,'<del>$1</del>');
1206
+ html = html.replace(/<span(.*?)style="font-weight: bold;">([\w\W]*?)<\/span>/gi, "<strong>$2</strong>");
1207
+ html = html.replace(/<span(.*?)style="font-style: italic;">([\w\W]*?)<\/span>/gi, "<em>$2</em>");
1208
+ html = html.replace(/<span(.*?)style="font-weight: bold; font-style: italic;">([\w\W]*?)<\/span>/gi, "<em><strong>$2</strong></em>");
1209
+ html = html.replace(/<span(.*?)style="font-style: italic; font-weight: bold;">([\w\W]*?)<\/span>/gi, "<strong><em>$2</em></strong>");
1210
+
1211
+ return html;
1212
+ },
1213
+
1214
+ // REMOVE TAGS
1215
+ stripTags: function(html)
1216
+ {
1217
+ var allowed = ["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"];
1218
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
1219
+ return html.replace(tags, function ($0, $1)
1220
+ {
1221
+ return $.inArray($1.toLowerCase(), allowed) > '-1' ? $0 : '';
1222
+ });
1223
+ },
1224
+ cleanStyles: function (properties, str, m)
1225
+ {
1226
+
1227
+ var attr = m.split('=');
1228
+ var prop = attr[1].split(';');
1229
+
1230
+ var t = '';
1231
+ $.each(prop, function(z,s)
1232
+ {
1233
+ if (typeof s == 'undefined') return true;
1234
+ if (s == '"' || s == "'") return true;
1235
+
1236
+ s = s.replace(/(^"|^')/,'').replace(/("$|'$)/,'').replace(/"(.*?)"/gi, '');
1237
+ s = $.trim(s);
1238
+
1239
+ var p = s.split(':');
1240
+
1241
+ if (typeof p[1] !== 'undefined' && (p[1].search('pt') === -1 && p[1].search('cm') === -1))
1242
+ {
1243
+ if ($.inArray($.trim(p[0]), properties) != '-1') t += s + '; ';
1244
+ }
1245
+ });
1246
+
1247
+ return str.replace(m, 'style="' + t + '"');
1248
+ },
1249
+
1250
+
1251
+ // PASTE CLEANUP
1252
+ pasteCleanUp: function(marker)
1253
+ {
1254
+ var html = this.$editor.html();
1255
+
1256
+ // remove comments and php tags
1257
+ html = html.replace(/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi, '')
1258
+
1259
+ // remove formatting
1260
+ html = this.formattingRemove(html);
1261
+
1262
+ // remove tags
1263
+ html = this.stripTags(html);
1264
+
1265
+ // remove classes
1266
+ if (this.opts.removeClasses)
1267
+ {
1268
+ html = html.replace(/ class="([\w\W]*?)"/gi, '');
1269
+ }
1270
+ else
1271
+ {
1272
+ html = html.replace(/\s*class="TOC(.*?)"/gi, "" );
1273
+ html = html.replace(/\s*class="Heading(.*?)"/gi, "" );
1274
+ html = html.replace(/\s*class="Body(.*?)"/gi, "" );
1275
+ html = html.replace(/\sclass="Nonformat"/gi, '');
1276
+ html = html.replace(/\sclass="Mso(.*?)"/gi, '');
1277
+ html = html.replace(/\sclass="Apple(.*?)"/gi, '');
1278
+ html = html.replace(/"Times New Roman"/gi, '');
1279
+ }
1280
+
1281
+ var attributes = ['width', 'height', 'src', 'style', 'href', 'frameborder', 'class', 'id', 'rel', 'unselectable'];
1282
+ var properties = ['color', 'background-color', 'font-style', 'margin', 'margin-top', 'margin-bottom', 'margin-left', 'margin-right', 'text-align', 'width', 'height', 'cursor', 'float'];
1283
+
1284
+ // remove attributes
1285
+ var matches = html.match(/([\w\-.:]+)\s*=\s*("[^"]*"|'[^']*'|[\w\-.:]+)/gi);
1286
+ $.each(matches, $.proxy(function(i,m)
1287
+ {
1288
+ var attr = m.split('=');
1289
+ if ($.inArray(attr[0], attributes) == '-1')
1290
+ {
1291
+ html = html.replace(m, '');
1292
+ }
1293
+
1294
+ // remove styles
1295
+ if (this.opts.removeStyles === false && attr[0] == 'style')
1296
+ {
1297
+ html = this.cleanStyles(properties, html, m);
1298
+ }
1299
+
1300
+ }, this));
1301
+
1302
+ // remove styles
1303
+ if (this.opts.removeStyles === false)
1304
+ {
1305
+ html = html.replace(/background-color:(\s+)transparent;\s/gi, '');
1306
+ html = html.replace(/font-style:(\s+)normal;\s/gi, '');
1307
+ }
1308
+ else
1309
+ {
1310
+ html = html.replace(/ style="([\w\W]*?)"/gi, '');
1311
+ }
1312
+
1313
+ // remove empty styles
1314
+ html = html.replace(/((\s{2,})?|\s)style=(""|'')/gi, '');
1315
+
1316
+ // remove nbsp
1317
+ html = html.replace(/(&nbsp;){1,}/gi, '&nbsp;');
1318
+
1319
+ // remove empty span
1320
+ html = html.replace(/<span(\s)?>(\s)?<\/span>/gi, ' ');
1321
+
1322
+ // remove double white spaces
1323
+ html = html.replace(/\s{2,}/g, ' ');
1324
+
1325
+ // remove span without styles
1326
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
1327
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
1328
+ html = html.replace(/<span(\s)?>([\w\W]*?)<\/span>/gi, '$2');
1329
+
1330
+ // empty tags
1331
+ html = this.formattingEmptyTags(html);
1332
+
1333
+ // add formatting before
1334
+ html = this.formattingAddBefore(html);
1335
+
1336
+ // add formatting after
1337
+ html = this.formattingAddAfter(html);
1338
+
1339
+ // indenting
1340
+ html = this.formattingIndenting(html);
1341
+
1342
+ // dirty paragraphs
1343
+ html = html.replace(/<p><div>/gi, "");
1344
+ html = html.replace(/<p>\s+\n+<(.*?)/gi, "<$1");
1345
+ html = html.replace(/<\/(.*?)>\s+\n+<\/p>/gi, "</$1>");
1346
+ html = html.replace(/<p style="(.*?)">(\s)?<\/p>/gi, '');
1347
+ html = html.replace(/<p style="(.*?)"><\/p>/gi, '');
1348
+
1349
+ // remove google docs marker
1350
+ html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2");
1351
+
1352
+ // trim spaces
1353
+ html = html.replace(/; ">/gi, ';">');
1354
+
1355
+ // SET HTML
1356
+ this.$editor.html(html);
1357
+
1358
+ // RETURN FOCUS
1359
+ var node = $(this.doc.body).find('#pastemarkerend' + marker).get(0);
1360
+ this.setFocusNode(node);
1361
+
1362
+ this.syncCode();
1363
+
1364
+
1365
+ setTimeout($.proxy(function()
1366
+ {
1367
+ // remove pastemarker
1368
+ $(this.doc.body).find('span[rel=pastemarkerend]').remove();
1369
+
1370
+ if (this.opts.autoresize === true) this.setAutoSize(false);
1371
+
1372
+ this.observeImages();
1373
+ this.observeTables();
1374
+
1375
+ }, this), 100);
1376
+
1377
+
1378
+ },
1379
+
1380
+ // TEXTAREA CODE FORMATTING
1381
+ formattingRemove: function(html)
1382
+ {
1383
+ html = html.replace(/\s{2,}/g, ' ');
1384
+ html = html.replace(/\n/g, ' ');
1385
+ html = html.replace(/[\t]*/g, '');
1386
+ html = html.replace(/\n\s*\n/g, "\n");
1387
+ html = html.replace(/^[\s\n]*/g, '');
1388
+ html = html.replace(/[\s\n]*$/g, '');
1389
+ html = html.replace(/>\s+</g, '><');
1390
+
1391
+ return html;
1392
+ },
1393
+ formattingIndenting: function(html)
1394
+ {
1395
+ html = html.replace(/<li/g, "\t<li");
1396
+ html = html.replace(/<tr/g, "\t<tr");
1397
+ html = html.replace(/<td/g, "\t\t<td");
1398
+ html = html.replace(/<\/tr>/g, "\t</tr>");
1399
+
1400
+ return html;
1401
+ },
1402
+ formattingEmptyTags: function(html)
1403
+ {
1404
+ var etags = ["<pre></pre>","<blockquote>\\s*</blockquote>","<em>\\s*</em>","<ul></ul>","<ol></ol>","<li></li>","<table></table>","<tr></tr>","<span>\\s*<span>", "<span>&nbsp;<span>", "<b>\\s*</b>", "<b>&nbsp;</b>", "<p>\\s*</p>", "<p>&nbsp;</p>", "<p>\\s*<br>\\s*</p>", "<div>\\s*</div>", "<div>\\s*<br>\\s*</div>"];
1405
+ for (var i = 0; i < etags.length; ++i)
1406
+ {
1407
+ var bbb = etags[i];
1408
+ html = html.replace(new RegExp(bbb,'gi'), "");
1409
+ }
1410
+
1411
+ return html;
1412
+ },
1413
+ formattingAddBefore: function(html)
1414
+ {
1415
+ var lb = '\r\n';
1416
+ var btags = ["<p", "<form","</ul>", '</ol>', "<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"];
1417
+ for (var i = 0; i < btags.length; ++i)
1418
+ {
1419
+ var eee = btags[i];
1420
+ html = html.replace(new RegExp(eee,'gi'),lb+eee);
1421
+ }
1422
+
1423
+ return html;
1424
+ },
1425
+ formattingAddAfter: function(html)
1426
+ {
1427
+ var lb = '\r\n';
1428
+ var atags = ['</p>', '</div>', '</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>'];
1429
+ for (var i = 0; i < atags.length; ++i)
1430
+ {
1431
+ var aaa = atags[i];
1432
+ html = html.replace(new RegExp(aaa,'gi'),aaa+lb);
1433
+ }
1434
+
1435
+ return html;
1436
+ },
1437
+ formatting: function(html)
1438
+ {
1439
+ // lowercase
1440
+ if ($.browser.msie)
1441
+ {
1442
+ var match = html.match(/<(.*?)>/gi);
1443
+ $.each(match, function(i,s)
1444
+ {
1445
+ html = html.replace(s, s.toLowerCase());
1446
+ })
1447
+ html = html.replace(/style="(.*?)"/gi, function(w) { return w.toLowerCase(); });
1448
+ html = html.replace(/ jQuery(.*?)=\"(.*?)\"/gi, '');
1449
+ }
1450
+
1451
+ html = html.replace(/<span([\w\W]*?)style="color:(.*?);"><span([\w\W]*?)style="background-color:(.*?);">([\w\W]*?)<\/span><\/span>/gi, '<span style="color: $2; background-color: $4;">$5</span>');
1452
+ html = html.replace(/<span([\w\W]*?)style="background-color:(.*?);"><span([\w\W]*?)style="color:(.*?);">([\w\W]*?)<\/span><\/span>/gi, '<span style="color: $2; background-color: $4;">$5</span>');
1453
+
1454
+ html = html.replace(/<span([\w\W]*?)color="(.*?)">([\w\W]*?)<\/span\>/gi, '<span$1style="color: $2;">$3</span>');
1455
+ html = html.replace(/<font([\w\W]*?)color="(.*?)">([\w\W]*?)<\/font\>/gi, '<span$1style="color: $2;">$3</span>');
1456
+ html = html.replace(/<span style="(.*?)"\s+style="(.*?)"[\s]*>([\w\W]*?)<\/span\>/gi, '<span style="$1;$2">$3</span>');
1457
+ html = html.replace(/<font([\w\W]*?)>([\w\W]*?)<\/font\>/gi, "<span$1>$2</span>");
1458
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
1459
+
1460
+ if (this.opts.xhtml)
1461
+ {
1462
+ html = html.replace(/<br>/gi,'<br />');
1463
+ html = html.replace(/<br ?\/?>$/gi,'');
1464
+ html = html.replace(/^<br ?\/?>/gi,'');
1465
+ html = html.replace(/(<img [^>]+[^\/])>/gi,'$1 />');
1466
+ }
1467
+
1468
+ // mini clean
1469
+ html = html.replace(/<p><p>/g, '<p>');
1470
+ html = html.replace(/<\/p><\/p>/g, '</p>');
1471
+ html = html.replace(/<hr(.*?)>/g, '<hr />');
1472
+ html = html.replace(/<p>&nbsp;/g, '<p>');
1473
+ html = html.replace(/<p><ul>/g, '<ul>');
1474
+ html = html.replace(/<p><ol>/g, '<ol>');
1475
+ html = html.replace(/<\/ul><\/p>/g, '</ul>');
1476
+ html = html.replace(/<\/ol><\/p>/g, '</ol>');
1477
+ html = html.replace( /<p(.*?)>&nbsp;<\/p>/gi, '');
1478
+
1479
+ // remove formatting
1480
+ html = this.formattingRemove(html);
1481
+
1482
+ // empty tags
1483
+ html = this.formattingEmptyTags(html);
1484
+
1485
+ // add formatting before
1486
+ html = this.formattingAddBefore(html);
1487
+
1488
+ // add formatting after
1489
+ html = this.formattingAddAfter(html);
1490
+
1491
+ // indenting
1492
+ html = this.formattingIndenting(html);
1493
+
1494
+ return html;
1495
+ },
1496
+
1497
+ // TOGGLE
1498
+ toggle: function()
1499
+ {
1500
+ var html;
1501
+
1502
+ if (this.opts.visual)
1503
+ {
1504
+ this.$frame.hide();
1505
+
1506
+ html = this.$editor.html();
1507
+ html = $.trim(this.formatting(html));
1508
+
1509
+ this.$el.val(html).show().focus();
1510
+
1511
+ this.setBtnActive('html');
1512
+ this.opts.visual = false;
1513
+ }
1514
+ else
1515
+ {
1516
+ this.$el.hide();
1517
+
1518
+ this.$editor.html(this.$el.val());
1519
+
1520
+ this.$frame.show();
1521
+
1522
+ if (this.$editor.html() === '')
1523
+ {
1524
+ if (!$.browser.mozilla)
1525
+ {
1526
+ html = this.opts.allEmptyHtml;
1527
+ }
1528
+ else
1529
+ {
1530
+ html = this.opts.mozillaEmptyHtml;
1531
+ }
1532
+
1533
+ this.setCode(html);
1534
+ }
1535
+
1536
+ this.focus();
1537
+
1538
+ this.setBtnInactive('html');
1539
+ this.opts.visual = true;
1540
+
1541
+ this.observeImages();
1542
+ this.observeTables();
1543
+
1544
+ if (this.opts.autoresize === true) this.setAutoSize(false);
1545
+ }
1546
+ },
1547
+
1548
+ // AUTOSAVE
1549
+ autoSave: function()
1550
+ {
1551
+ if (this.opts.autosave === false)
1552
+ {
1553
+ return false;
1554
+ }
1555
+
1556
+ setInterval($.proxy(function()
1557
+ {
1558
+ $.post(this.opts.autosave, { data: this.getCode() });
1559
+
1560
+ }, this), this.opts.interval*1000);
1561
+ },
1562
+
1563
+ // TOOLBAR
1564
+ buildToolbar: function()
1565
+ {
1566
+ if (this.opts.toolbar === false)
1567
+ {
1568
+ return false;
1569
+ }
1570
+
1571
+ this.$toolbar = $('<ul>').addClass('redactor_toolbar');
1572
+ this.$box.prepend(this.$toolbar);
1573
+
1574
+ $.each(this.opts.buttons, $.proxy(function(i,key)
1575
+ {
1576
+
1577
+ if (key !== '|' && typeof this.opts.toolbar[key] !== 'undefined')
1578
+ {
1579
+ var s = this.opts.toolbar[key];
1580
+
1581
+ if (this.opts.fileUpload === false && key === 'file')
1582
+ {
1583
+ return true;
1584
+ }
1585
+
1586
+ var li = $('<li>');
1587
+
1588
+ if (key === 'fullscreen')
1589
+ {
1590
+ $(li).addClass('redactor_toolbar_right');
1591
+ }
1592
+
1593
+ var a = this.buildButton(key, s);
1594
+
1595
+ // dropdown
1596
+ if (key === 'backcolor' || key === 'fontcolor' || typeof(s.dropdown) !== 'undefined')
1597
+ {
1598
+ var dropdown = $('<div class="redactor_dropdown" style="display: none;">');
1599
+
1600
+ if (key === 'backcolor' || key === 'fontcolor')
1601
+ {
1602
+ dropdown = this.buildColorPicker(dropdown, key);
1603
+ }
1604
+ else
1605
+ {
1606
+ dropdown = this.buildDropdown(dropdown, s.dropdown);
1607
+ }
1608
+
1609
+ this.dropdowns.push(dropdown.appendTo($(document.body)));
1610
+
1611
+ // observing dropdown
1612
+ this.hdlHideDropDown = $.proxy(function(e) { this.hideDropDown(e, dropdown, key); }, this);
1613
+ this.hdlShowDropDown = $.proxy(function(e) { this.showDropDown(e, dropdown, key); }, this);
1614
+
1615
+ a.click(this.hdlShowDropDown);
1616
+ }
1617
+
1618
+ this.$toolbar.append($(li).append(a));
1619
+ }
1620
+
1621
+
1622
+ if (key === '|')
1623
+ {
1624
+ this.$toolbar.append($('<li class="redactor_separator"></li>'));
1625
+ }
1626
+
1627
+ }, this));
1628
+
1629
+ $(document).click(this.hdlHideDropDown);
1630
+ $(this.doc).click(this.hdlHideDropDown);
1631
+
1632
+ },
1633
+ buildButton: function(key, s)
1634
+ {
1635
+ var button = $('<a href="javascript:void(null);" title="' + s.title + '" class="redactor_btn_' + key + '"><span>&nbsp;</span></a>');
1636
+
1637
+ if (typeof s.func === 'undefined')
1638
+ {
1639
+ button.click($.proxy(function() { this.execCommand(s.exec, key); }, this));
1640
+ }
1641
+ else if (s.func !== 'show')
1642
+ {
1643
+ button.click($.proxy(function(e) { this[s.func](e); }, this));
1644
+ }
1645
+
1646
+ if (typeof s.callback !== 'undefined')
1647
+ {
1648
+ button.click($.proxy(function(e) { s.callback(this, e, key); }, this));
1649
+ }
1650
+
1651
+ return button;
1652
+ },
1653
+ buildDropdown: function(dropdown, obj)
1654
+ {
1655
+ $.each(obj, $.proxy(
1656
+ function (x, d)
1657
+ {
1658
+ if (typeof(d.className) === 'undefined')
1659
+ {
1660
+ d.className = '';
1661
+ }
1662
+
1663
+ var drop_a;
1664
+ if (typeof d.name !== 'undefined' && d.name === 'separator')
1665
+ {
1666
+ drop_a = $('<a class="redactor_separator_drop">');
1667
+ }
1668
+ else
1669
+ {
1670
+ drop_a = $('<a href="javascript:void(null);" class="' + d.className + '">' + d.title + '</a>');
1671
+
1672
+ if (typeof(d.func) === 'undefined')
1673
+ {
1674
+ $(drop_a).click($.proxy(function() { this.execCommand(d.exec, x); }, this));
1675
+ }
1676
+ else
1677
+ {
1678
+ $(drop_a).click($.proxy(function(e) { this[d.func](e); }, this));
1679
+ }
1680
+ }
1681
+
1682
+ $(dropdown).append(drop_a);
1683
+
1684
+ }, this)
1685
+ );
1686
+
1687
+ return dropdown;
1688
+
1689
+ },
1690
+ buildColorPicker: function(dropdown, key)
1691
+ {
1692
+ var mode;
1693
+ if (key === 'backcolor')
1694
+ {
1695
+ if ($.browser.msie)
1696
+ {
1697
+ mode = 'BackColor';
1698
+ }
1699
+ else
1700
+ {
1701
+ mode = 'hilitecolor';
1702
+ }
1703
+ }
1704
+ else
1705
+ {
1706
+ mode = 'forecolor';
1707
+ }
1708
+
1709
+ $(dropdown).width(210);
1710
+
1711
+ var len = this.opts.colors.length;
1712
+ for (var i = 0; i < len; ++i)
1713
+ {
1714
+ var color = this.opts.colors[i];
1715
+
1716
+ var swatch = $('<a rel="' + color + '" href="javascript:void(null);" class="redactor_color_link"></a>').css({ 'backgroundColor': color });
1717
+ $(dropdown).append(swatch);
1718
+
1719
+ var _self = this;
1720
+ $(swatch).click(function()
1721
+ {
1722
+ _self.execCommand(mode, $(this).attr('rel'));
1723
+ });
1724
+ }
1725
+
1726
+ var elnone = $('<a href="javascript:void(null);" class="redactor_color_none"></a>').html(RLANG.none);
1727
+
1728
+ if (key === 'backcolor')
1729
+ {
1730
+ elnone.click($.proxy(this.setBackgroundNone, this));
1731
+ }
1732
+ else
1733
+ {
1734
+ elnone.click($.proxy(this.setColorNone, this));
1735
+ }
1736
+
1737
+ $(dropdown).append(elnone);
1738
+
1739
+ return dropdown;
1740
+ },
1741
+ setBackgroundNone: function()
1742
+ {
1743
+ $(this.getParentNode()).css('background-color', 'transparent');
1744
+ this.syncCode();
1745
+ },
1746
+ setColorNone: function()
1747
+ {
1748
+ $(this.getParentNode()).attr('color', '').css('color', '');
1749
+ this.syncCode();
1750
+ },
1751
+
1752
+
1753
+ // DROPDOWNS
1754
+ showDropDown: function(e, dropdown, key)
1755
+ {
1756
+ if (this.getBtn(key).hasClass('dropact'))
1757
+ {
1758
+ this.hideAllDropDown();
1759
+ }
1760
+ else
1761
+ {
1762
+ this.hideAllDropDown();
1763
+
1764
+ this.setBtnActive(key);
1765
+ this.getBtn(key).addClass('dropact');
1766
+
1767
+ var left = this.getBtn(key).offset().left;
1768
+
1769
+
1770
+ if (this.opts.fixed && this.fixed)
1771
+ {
1772
+ $(dropdown).css({ position: 'fixed', left: left + 'px', top: '30px' }).show();
1773
+ }
1774
+ else
1775
+ {
1776
+ var top = this.$toolbar.offset().top + 30;
1777
+ $(dropdown).css({ position: 'absolute', left: left + 'px', top: top + 'px' }).show();
1778
+ }
1779
+ }
1780
+
1781
+ },
1782
+ hideAllDropDown: function()
1783
+ {
1784
+ this.$toolbar.find('a.dropact').removeClass('act').removeClass('dropact');
1785
+ $('.redactor_dropdown').hide();
1786
+ },
1787
+ hideDropDown: function(e, dropdown, key)
1788
+ {
1789
+ if (!$(e.target).parent().hasClass('dropact'))
1790
+ {
1791
+ $(dropdown).removeClass('act');
1792
+ this.showedDropDown = false;
1793
+ this.hideAllDropDown();
1794
+ }
1795
+ },
1796
+
1797
+ // SELECTION AND NODE MANIPULATION
1798
+ getSelection: function ()
1799
+ {
1800
+ if (this.$frame.get(0).contentWindow.getSelection)
1801
+ {
1802
+ return this.$frame.get(0).contentWindow.getSelection();
1803
+ }
1804
+ else if (this.$frame.get(0).contentWindow.document.selection)
1805
+ {
1806
+ return this.$frame.get(0).contentWindow.document.selection.createRange();
1807
+ }
1808
+ },
1809
+ getParentNode: function()
1810
+ {
1811
+ if (window.getSelection)
1812
+ {
1813
+ return this.getSelection().getRangeAt(0).startContainer.parentNode;
1814
+ }
1815
+ else if (document.selection)
1816
+ {
1817
+ return this.getSelection().parentElement();
1818
+ }
1819
+ },
1820
+ getCurrentNode: function()
1821
+ {
1822
+ if (window.getSelection)
1823
+ {
1824
+ return this.getSelection().getRangeAt(0).startContainer;
1825
+ }
1826
+ else if (document.selection)
1827
+ {
1828
+ return this.getSelection();
1829
+ }
1830
+ },
1831
+ setFocusNode: function(node, toStart)
1832
+ {
1833
+ var range = this.doc.createRange();
1834
+
1835
+ var selection = this.getSelection();
1836
+ toStart = toStart ? 0 : 1;
1837
+
1838
+ if (selection !== null)
1839
+ {
1840
+ range.selectNodeContents(node);
1841
+ selection.addRange(range);
1842
+ selection.collapse(node, toStart);
1843
+ }
1844
+
1845
+ this.focus();
1846
+ },
1847
+ insertNodeAtCaret: function (node)
1848
+ {
1849
+ if (typeof window.getSelection !== "undefined")
1850
+ {
1851
+ var sel = this.getSelection();
1852
+ if (sel.rangeCount)
1853
+ {
1854
+ var range = sel.getRangeAt(0);
1855
+ range.collapse(false);
1856
+ range.insertNode(node);
1857
+ range = range.cloneRange();
1858
+ range.selectNodeContents(node);
1859
+ range.collapse(false);
1860
+ sel.removeAllRanges();
1861
+ sel.addRange(range);
1862
+ }
1863
+ }
1864
+ else if (typeof document.selection !== "undefined" && document.selection.type !== "Control")
1865
+ {
1866
+ var html = (node.nodeType === 1) ? node.outerHTML : node.data;
1867
+ var id = "marker_" + ("" + Math.random()).slice(2);
1868
+ html += '<span id="' + id + '"></span>';
1869
+ var textRange = this.getSelection();
1870
+ textRange.collapse(false);
1871
+ textRange.pasteHTML(html);
1872
+ var markerSpan = document.getElementById(id);
1873
+ textRange.moveToElementText(markerSpan);
1874
+ textRange.select();
1875
+ markerSpan.parentNode.removeChild(markerSpan);
1876
+ }
1877
+ },
1878
+
1879
+ // BUTTONS MANIPULATIONS
1880
+ getBtn: function(key)
1881
+ {
1882
+ return $(this.$toolbar.find('a.redactor_btn_' + key));
1883
+ },
1884
+ setBtnActive: function(key)
1885
+ {
1886
+ this.getBtn(key).addClass('act');
1887
+ },
1888
+ setBtnInactive: function(key)
1889
+ {
1890
+ this.getBtn(key).removeClass('act');
1891
+ },
1892
+ changeBtnIcon: function(key, classname)
1893
+ {
1894
+ this.getBtn(key).addClass('redactor_btn_' + classname);
1895
+ },
1896
+ removeBtnIcon: function(key, classname)
1897
+ {
1898
+ this.getBtn(key).removeClass('redactor_btn_' + classname);
1899
+ },
1900
+ removeBtn: function(key)
1901
+ {
1902
+ this.getBtn(key).remove();
1903
+ },
1904
+ addBtn: function(key, obj)
1905
+ {
1906
+ this.$toolbar.append($('<li>').append(this.buildButton(key, obj)));
1907
+ },
1908
+
1909
+ // FULLSCREEN
1910
+ fullscreen: function()
1911
+ {
1912
+ var html;
1913
+
1914
+ if (this.opts.fullscreen === false)
1915
+ {
1916
+ this.changeBtnIcon('fullscreen', 'normalscreen');
1917
+ this.setBtnActive('fullscreen');
1918
+ this.opts.fullscreen = true;
1919
+
1920
+ this.height = this.$frame.css('height');
1921
+ this.width = (this.$box.width() - 2) + 'px';
1922
+
1923
+ html = this.getCode();
1924
+
1925
+ this.tmpspan = $('<span></span>');
1926
+ this.$box.addClass('redactor_box_fullscreen').after(this.tmpspan);
1927
+
1928
+ $(document.body).prepend(this.$box).css('overflow', 'hidden');
1929
+
1930
+ this.$editor = this.enable(html);
1931
+
1932
+ $(this.doc).click($.proxy(this.hideAllDropDown, this));
1933
+
1934
+ // focus always on page
1935
+ this.observeFocus();
1936
+
1937
+ this.observeImages();
1938
+ this.observeTables();
1939
+
1940
+ this.$box.find('.redactor_resizer').hide();
1941
+
1942
+ this.fullScreenResize();
1943
+ $(window).resize($.proxy(this.fullScreenResize, this));
1944
+ $(document).scrollTop(0,0);
1945
+ this.focus();
1946
+
1947
+ }
1948
+ else
1949
+ {
1950
+ this.removeBtnIcon('fullscreen', 'normalscreen');
1951
+ this.setBtnInactive('fullscreen');
1952
+ this.opts.fullscreen = false;
1953
+
1954
+ $(window).unbind('resize', $.proxy(this.fullScreenResize, this));
1955
+ $(document.body).css('overflow', '');
1956
+
1957
+ html = this.getCode();
1958
+
1959
+ this.$box.removeClass('redactor_box_fullscreen').css('width', 'auto');
1960
+
1961
+ this.tmpspan.after(this.$box).remove();
1962
+
1963
+ this.$editor = this.enable(html);
1964
+
1965
+ this.observeImages();
1966
+ this.observeTables();
1967
+
1968
+ if (this.opts.autoresize)
1969
+ {
1970
+ this.observeAutoResize();
1971
+ }
1972
+ this.$box.find('.redactor_resizer').show();
1973
+
1974
+ $(this.doc).click($.proxy(this.hideAllDropDown, this));
1975
+
1976
+ // focus always on page
1977
+ this.observeFocus();
1978
+
1979
+ this.syncCode();
1980
+
1981
+ this.$frame.css('height', this.height);
1982
+ this.$el.css('height', this.height);
1983
+ this.focus();
1984
+ }
1985
+ },
1986
+ fullScreenResize: function()
1987
+ {
1988
+ if (this.opts.fullscreen === false)
1989
+ {
1990
+ return false;
1991
+ }
1992
+
1993
+ var height = $(window).height() - 42;
1994
+ this.$box.width($(window).width() - 2);
1995
+ this.$frame.height(height);
1996
+ this.$el.height(height);
1997
+ },
1998
+
1999
+ // RESIZE
2000
+ buildResizer: function()
2001
+ {
2002
+ if (this.opts.resize === false)
2003
+ {
2004
+ return false;
2005
+ }
2006
+
2007
+ this.$resizer = $('<div class="redactor_resizer">&mdash;</div>');
2008
+ this.$box.append(this.$resizer);
2009
+ this.$resizer.mousedown($.proxy(this.initResize, this));
2010
+
2011
+ },
2012
+ initResize: function(e)
2013
+ {
2014
+ if (e.preventDefault)
2015
+ {
2016
+ e.preventDefault();
2017
+ }
2018
+
2019
+ this.splitter = e.target;
2020
+
2021
+ if (this.opts.visual)
2022
+ {
2023
+ this.element_resize = this.$frame;
2024
+ this.element_resize.get(0).style.visibility = 'hidden';
2025
+ this.element_resize_parent = this.$el;
2026
+ }
2027
+ else
2028
+ {
2029
+ this.element_resize = this.$el;
2030
+ this.element_resize_parent = this.$frame;
2031
+ }
2032
+
2033
+ this.stopResizeHdl = $.proxy(this.stopResize, this);
2034
+ this.startResizeHdl = $.proxy(this.startResize, this);
2035
+ this.resizeHdl = $.proxy(this.resize, this);
2036
+
2037
+ $(document).mousedown(this.startResizeHdl);
2038
+ $(document).mouseup(this.stopResizeHdl);
2039
+ $(this.splitter).mouseup(this.stopResizeHdl);
2040
+
2041
+ this.null_point = false;
2042
+ this.h_new = false;
2043
+ this.h = this.element_resize.height();
2044
+ },
2045
+ startResize: function()
2046
+ {
2047
+ $(document).mousemove(this.resizeHdl);
2048
+ },
2049
+ resize: function(e)
2050
+ {
2051
+ if (e.preventDefault)
2052
+ {
2053
+ e.preventDefault();
2054
+ }
2055
+
2056
+ var y = e.pageY;
2057
+
2058
+ if (this.null_point === false)
2059
+ {
2060
+ this.null_point = y;
2061
+ }
2062
+
2063
+ if (this.h_new === false)
2064
+ {
2065
+ this.h_new = this.element_resize.height();
2066
+ }
2067
+
2068
+ var s_new = (this.h_new + y - this.null_point) - 10;
2069
+
2070
+ if (s_new <= 30)
2071
+ {
2072
+ return true;
2073
+ }
2074
+
2075
+ if (s_new >= 0)
2076
+ {
2077
+ this.element_resize.get(0).style.height = s_new + 'px';
2078
+ this.element_resize_parent.get(0).style.height = s_new + 'px';
2079
+ }
2080
+ },
2081
+ stopResize: function(e)
2082
+ {
2083
+ $(document).unbind('mousemove', this.resizeHdl);
2084
+ $(document).unbind('mousedown', this.startResizeHdl);
2085
+ $(document).unbind('mouseup', this.stopResizeHdl);
2086
+ $(this.splitter).unbind('mouseup', this.stopResizeHdl);
2087
+
2088
+ this.element_resize.get(0).style.visibility = 'visible';
2089
+ },
2090
+
2091
+ // RESIZE IMAGES
2092
+ resizeImage: function(resize)
2093
+ {
2094
+ var clicked = false;
2095
+ var clicker = false;
2096
+ var start_x;
2097
+ var start_y;
2098
+ var ratio = $(resize).width()/$(resize).height();
2099
+
2100
+ var y = 1;
2101
+ var x = 1;
2102
+ var min_w = 1;
2103
+ var min_h = 1;
2104
+
2105
+ $(resize).hover(function() { $(resize).css('cursor', 'nw-resize'); }, function() { $(resize).css('cursor','default'); clicked=false; });
2106
+
2107
+ $(resize).mousedown(function(e)
2108
+ {
2109
+ if (e.preventDefault)
2110
+ {
2111
+ e.preventDefault();
2112
+ }
2113
+
2114
+ clicked = true;
2115
+ clicker = true;
2116
+
2117
+ start_x = Math.round(e.pageX - $(resize).eq(0).offset().left);
2118
+ start_y = Math.round(e.pageY - $(resize).eq(0).offset().top);
2119
+ });
2120
+
2121
+ $(resize).mouseup($.proxy(function(e)
2122
+ {
2123
+ clicked = false;
2124
+ this.syncCode();
2125
+ if (this.opts.autoresize === true) this.setAutoSize(false);
2126
+
2127
+ }, this));
2128
+
2129
+ $(resize).click($.proxy(function(e)
2130
+ {
2131
+ if (clicker)
2132
+ {
2133
+ this.imageEdit(e);
2134
+ }
2135
+
2136
+ }, this));
2137
+
2138
+ $(resize).mousemove(function(e)
2139
+ {
2140
+ if (clicked)
2141
+ {
2142
+ clicker = false;
2143
+
2144
+ var mouse_x = Math.round(e.pageX - $(this).eq(0).offset().left) - start_x;
2145
+ var mouse_y = Math.round(e.pageY - $(this).eq(0).offset().top) - start_y;
2146
+
2147
+ var div_h = $(resize).height();
2148
+
2149
+ var new_h = parseInt(div_h, 10) + mouse_y;
2150
+ var new_w = new_h*ratio;
2151
+
2152
+ if (x === 1 || (typeof(x) === "number" && new_w < x && new_w > min_w))
2153
+ {
2154
+ $(resize).width(new_w);
2155
+ }
2156
+ if (y === 1 || (typeof(y) === "number" && new_h < y && new_h > min_h))
2157
+ {
2158
+ $(resize).height(new_h);
2159
+ }
2160
+ start_x = Math.round(e.pageX - $(this).eq(0).offset().left);
2161
+ start_y = Math.round(e.pageY - $(this).eq(0).offset().top);
2162
+ }
2163
+ });
2164
+ },
2165
+
2166
+ // TABLE
2167
+ showTable: function()
2168
+ {
2169
+ this.modalInit(RLANG.table, 'table', 300, $.proxy(function()
2170
+ {
2171
+ $('#redactor_insert_table_btn').click($.proxy(this.insertTable, this));
2172
+ }, this),
2173
+
2174
+ function()
2175
+ {
2176
+ $('#redactor_table_rows').focus();
2177
+ }
2178
+ );
2179
+ },
2180
+ insertTable: function()
2181
+ {
2182
+ var rows = $('#redactor_table_rows').val();
2183
+ var columns = $('#redactor_table_columns').val();
2184
+
2185
+ var table_box = $('<div></div>');
2186
+
2187
+ var tableid = Math.floor(Math.random() * 99999);
2188
+ var table = $('<table id="table' + tableid + '"><tbody></tbody></table>');
2189
+
2190
+ for (var i = 0; i < rows; i++)
2191
+ {
2192
+ var row = $('<tr></tr>');
2193
+ for (var z = 0; z < columns; z++)
2194
+ {
2195
+ var column = $('<td>&nbsp;</td>');
2196
+ $(row).append(column);
2197
+ }
2198
+ $(table).append(row);
2199
+ }
2200
+
2201
+ $(table_box).append(table);
2202
+ var html = $(table_box).html();
2203
+
2204
+ if ($.browser.msie)
2205
+ {
2206
+ html += '<p></p>';
2207
+ }
2208
+ else
2209
+ {
2210
+ html += '<p>&nbsp;</p>';
2211
+ }
2212
+
2213
+ this.execCommand('inserthtml', html);
2214
+ this.modalClose();
2215
+
2216
+ this.$table = $(this.doc).find('body').find('#table' + tableid);
2217
+ this.$table.click($.proxy(this.tableObserver, this));
2218
+
2219
+ if (this.opts.autoresize === true) this.setAutoSize(false);
2220
+ },
2221
+ tableObserver: function(e)
2222
+ {
2223
+ this.$table = $(e.target).parents('table');
2224
+
2225
+ this.$table_tr = this.$table.find('tr');
2226
+ this.$table_td = this.$table.find('td');
2227
+
2228
+ this.$table_td.removeClass('current');
2229
+
2230
+ this.$tbody = $(e.target).parents('tbody');
2231
+ this.$thead = $(this.$table).find('thead');
2232
+
2233
+ this.$current_td = $(e.target);
2234
+ this.$current_td.addClass('current');
2235
+
2236
+ this.$current_tr = $(e.target).parents('tr');
2237
+ },
2238
+ deleteTable: function()
2239
+ {
2240
+ $(this.$table).remove();
2241
+ this.$table = false;
2242
+ this.syncCode();
2243
+ },
2244
+ deleteRow: function()
2245
+ {
2246
+ $(this.$current_tr).remove();
2247
+ this.syncCode();
2248
+ },
2249
+ deleteColumn: function()
2250
+ {
2251
+ var index = $(this.$current_td).get(0).cellIndex;
2252
+
2253
+ $(this.$table).find('tr').each(function()
2254
+ {
2255
+ $(this).find('td').eq(index).remove();
2256
+ });
2257
+
2258
+ this.syncCode();
2259
+ },
2260
+ addHead: function()
2261
+ {
2262
+ if ($(this.$table).find('thead').size() !== 0)
2263
+ {
2264
+ this.deleteHead();
2265
+ }
2266
+ else
2267
+ {
2268
+ var tr = $(this.$table).find('tr').first().clone();
2269
+ tr.find('td').html('&nbsp;');
2270
+ this.$thead = $('<thead></thead>');
2271
+ this.$thead.append(tr);
2272
+ $(this.$table).prepend(this.$thead);
2273
+ this.syncCode();
2274
+ }
2275
+ },
2276
+ deleteHead: function()
2277
+ {
2278
+ $(this.$thead).remove();
2279
+ this.$thead = false;
2280
+ this.syncCode();
2281
+ },
2282
+ insertRowAbove: function()
2283
+ {
2284
+ this.insertRow('before');
2285
+ },
2286
+ insertRowBelow: function()
2287
+ {
2288
+ this.insertRow('after');
2289
+ },
2290
+ insertColumnLeft: function()
2291
+ {
2292
+ this.insertColumn('before');
2293
+ },
2294
+ insertColumnRight: function()
2295
+ {
2296
+ this.insertColumn('after');
2297
+ },
2298
+ insertRow: function(type)
2299
+ {
2300
+ var new_tr = $(this.$current_tr).clone();
2301
+ new_tr.find('td').html('&nbsp;');
2302
+ if (type === 'after')
2303
+ {
2304
+ $(this.$current_tr).after(new_tr);
2305
+ }
2306
+ else
2307
+ {
2308
+ $(this.$current_tr).before(new_tr);
2309
+ }
2310
+
2311
+ this.syncCode();
2312
+ },
2313
+ insertColumn: function(type)
2314
+ {
2315
+ var index = 0;
2316
+
2317
+ this.$current_td.addClass('current');
2318
+
2319
+ this.$current_tr.find('td').each(function(i,s)
2320
+ {
2321
+ if ($(s).hasClass('current'))
2322
+ {
2323
+ index = i;
2324
+ }
2325
+ });
2326
+
2327
+ this.$table_tr.each(function(i,s)
2328
+ {
2329
+ var current = $(s).find('td').eq(index);
2330
+
2331
+ var td = current.clone();
2332
+ td.html('&nbsp;');
2333
+
2334
+ if (type === 'after')
2335
+ {
2336
+ $(current).after(td);
2337
+ }
2338
+ else
2339
+ {
2340
+ $(current).before(td);
2341
+ }
2342
+
2343
+ });
2344
+
2345
+ this.syncCode();
2346
+ },
2347
+
2348
+ // INSERT VIDEO
2349
+ showVideo: function()
2350
+ {
2351
+ if ($.browser.msie)
2352
+ {
2353
+ this.markerIE();
2354
+ }
2355
+
2356
+ this.modalInit(RLANG.video, 'video', 600, $.proxy(function()
2357
+ {
2358
+ $('#redactor_insert_video_btn').click($.proxy(this.insertVideo, this));
2359
+ }, this),
2360
+
2361
+ function()
2362
+ {
2363
+ $('#redactor_insert_video_area').focus();
2364
+ }
2365
+ );
2366
+ },
2367
+ insertVideo: function()
2368
+ {
2369
+ var data = $('#redactor_insert_video_area').val();
2370
+ data = this.stripTags(data);
2371
+
2372
+ if ($.browser.msie)
2373
+ {
2374
+ $(this.doc.getElementById('span' + this.spanid)).after(data).remove();
2375
+ this.syncCode();
2376
+ }
2377
+ else
2378
+ {
2379
+ this.execCommand('inserthtml', data);
2380
+ }
2381
+
2382
+ this.modalClose();
2383
+
2384
+ if (this.opts.autoresize === true)
2385
+ {
2386
+ this.setAutoSize(false);
2387
+ }
2388
+ },
2389
+
2390
+ // INSERT IMAGE
2391
+ imageEdit: function(e)
2392
+ {
2393
+ var $el = $(e.target);
2394
+ var parent = $el.parent();
2395
+
2396
+ var handler = $.proxy(function()
2397
+ {
2398
+ $('#redactor_file_alt').val($el.attr('alt'));
2399
+ $('#redactor_image_edit_src').attr('href', $el.attr('src'));
2400
+ $('#redactor_form_image_align').val($el.css('float'));
2401
+
2402
+ if ($(parent).get(0).tagName === 'A')
2403
+ {
2404
+ $('#redactor_file_link').val($(parent).attr('href'));
2405
+ }
2406
+
2407
+ $('#redactor_image_delete_btn').click($.proxy(function() { this.imageDelete($el); }, this));
2408
+ $('#redactorSaveBtn').click($.proxy(function() { this.imageSave($el); }, this));
2409
+
2410
+ }, this);
2411
+
2412
+ this.modalInit(RLANG.image, 'image_edit', 380, handler);
2413
+
2414
+ },
2415
+ imageDelete: function(el)
2416
+ {
2417
+ $(el).remove();
2418
+ this.modalClose();
2419
+ this.syncCode();
2420
+
2421
+ if (this.opts.autoresize === true)
2422
+ {
2423
+ this.setAutoSize(false);
2424
+ }
2425
+ },
2426
+ imageSave: function(el)
2427
+ {
2428
+ var parent = $(el).parent();
2429
+
2430
+ $(el).attr('alt', $('#redactor_file_alt').val());
2431
+
2432
+ var floating = $('#redactor_form_image_align').val();
2433
+
2434
+ if (floating === 'left')
2435
+ {
2436
+ $(el).css({ 'float': 'left', margin: '0 10px 10px 0' });
2437
+ }
2438
+ else if (floating === 'right')
2439
+ {
2440
+ $(el).css({ 'float': 'right', margin: '0 0 10px 10px' });
2441
+ }
2442
+ else
2443
+ {
2444
+ $(el).css({ 'float': 'none', margin: '0' });
2445
+ }
2446
+
2447
+ // as link
2448
+ var link = $.trim($('#redactor_file_link').val());
2449
+ if (link !== '')
2450
+ {
2451
+ if ($(parent).get(0).tagName !== 'A')
2452
+ {
2453
+ $(el).replaceWith('<a href="' + link + '">' + this.outerHTML(el) + '</a>');
2454
+ }
2455
+ else
2456
+ {
2457
+ $(parent).attr('href', link);
2458
+ }
2459
+ }
2460
+ else
2461
+ {
2462
+ if ($(parent).get(0).tagName === 'A')
2463
+ {
2464
+ $(parent).replaceWith(this.outerHTML(el));
2465
+ }
2466
+ }
2467
+
2468
+ this.modalClose();
2469
+ this.observeImages();
2470
+ this.syncCode();
2471
+
2472
+ },
2473
+ showImage: function()
2474
+ {
2475
+ if ($.browser.msie)
2476
+ {
2477
+ this.markerIE();
2478
+ }
2479
+
2480
+ var handler = $.proxy(function()
2481
+ {
2482
+ // json
2483
+ if (this.opts.imageGetJson !== false)
2484
+ {
2485
+ $.getJSON(this.opts.imageGetJson, $.proxy(function(data) {
2486
+
2487
+ $.each(data, $.proxy(function(key, val)
2488
+ {
2489
+ var img = $('<img src="' + val.thumb + '" rel="' + val.image + '" />');
2490
+ $('#redactor_image_box').append(img);
2491
+ $(img).click($.proxy(this.imageSetThumb, this));
2492
+
2493
+ }, this));
2494
+
2495
+ }, this));
2496
+ }
2497
+ else
2498
+ {
2499
+ $('#redactor_tabs a').eq(1).remove();
2500
+ }
2501
+
2502
+ if (this.opts.imageUpload !== false)
2503
+ {
2504
+
2505
+ // dragupload
2506
+ if (this.isMobile() === false)
2507
+ {
2508
+ if ($('#redactor_file').size() !== 0)
2509
+ {
2510
+ $('#redactor_file').dragupload(
2511
+ {
2512
+ url: this.opts.imageUpload,
2513
+ success: $.proxy(this.imageUploadCallback, this)
2514
+ });
2515
+ }
2516
+ }
2517
+
2518
+ // ajax upload
2519
+ this.uploadInit('redactor_file', { auto: true, url: this.opts.imageUpload, success: $.proxy(this.imageUploadCallback, this) });
2520
+ }
2521
+ else
2522
+ {
2523
+ $('.redactor_tab').hide();
2524
+ if (this.opts.imageGetJson === false)
2525
+ {
2526
+ $('#redactor_tabs').remove();
2527
+ $('#redactor_tab3').show();
2528
+ }
2529
+ else
2530
+ {
2531
+ var tabs = $('#redactor_tabs a');
2532
+ tabs.eq(0).remove();
2533
+ tabs.eq(1).addClass('redactor_tabs_act');
2534
+ $('#redactor_tab2').show();
2535
+ }
2536
+ }
2537
+
2538
+ $('#redactor_upload_btn').click($.proxy(this.imageUploadCallbackLink, this));
2539
+
2540
+ }, this);
2541
+
2542
+ var endCallback = $.proxy(function()
2543
+ {
2544
+ if (this.opts.imageUpload === false && this.opts.imageGetJson === false)
2545
+ {
2546
+ $('#redactor_file_link').focus();
2547
+ }
2548
+ }, this);
2549
+
2550
+ this.modalInit(RLANG.image, 'image', 570, handler, endCallback, true);
2551
+
2552
+ },
2553
+ imageSetThumb: function(e)
2554
+ {
2555
+ this._imageSet('<img alt="" src="' + $(e.target).attr('rel') + '" />', true);
2556
+ },
2557
+ imageUploadCallbackLink: function()
2558
+ {
2559
+ if ($('#redactor_file_link').val() !== '')
2560
+ {
2561
+ var data = '<img src="' + $('#redactor_file_link').val() + '" />';
2562
+ this._imageSet(data, true);
2563
+ }
2564
+ else
2565
+ {
2566
+ this.modalClose();
2567
+ }
2568
+ },
2569
+ imageUploadCallback: function(data)
2570
+ {
2571
+ this._imageSet(data);
2572
+ },
2573
+ _imageSet: function(json, link)
2574
+ {
2575
+ var html = '', data = '';
2576
+ if (link !== true)
2577
+ {
2578
+ data = $.parseJSON(json);
2579
+ html = '<p><img src="' + data.filelink + '" /></p>';
2580
+ }
2581
+ else
2582
+ {
2583
+ html = json;
2584
+ }
2585
+
2586
+ this.focus();
2587
+
2588
+ if ($.browser.msie)
2589
+ {
2590
+ $(this.doc.getElementById('span' + this.spanid)).after(html).remove();
2591
+ this.syncCode();
2592
+ }
2593
+ else
2594
+ {
2595
+ this.execCommand('inserthtml', html);
2596
+ }
2597
+
2598
+ // upload image callback
2599
+ if (link !== true && typeof this.opts.imageUploadCallback === 'function')
2600
+ {
2601
+ this.opts.imageUploadCallback(this, data);
2602
+ }
2603
+
2604
+ this.modalClose();
2605
+
2606
+ $(this.doc).find('img').load($.proxy(function()
2607
+ {
2608
+ this.setAutoSize(false);
2609
+
2610
+ }, this));
2611
+
2612
+ this.observeImages();
2613
+ },
2614
+
2615
+ // INSERT LINK
2616
+ showLink: function()
2617
+ {
2618
+ var handler = $.proxy(function()
2619
+ {
2620
+ var sel = this.getSelection();
2621
+ var url = '', text = '';
2622
+
2623
+ if ($.browser.msie)
2624
+ {
2625
+ var parent = this.getParentNode();
2626
+ if (parent.nodeName === 'A')
2627
+ {
2628
+ this.insert_link_node = $(parent);
2629
+ text = this.insert_link_node.text();
2630
+ url = this.insert_link_node.attr('href');
2631
+ }
2632
+ else
2633
+ {
2634
+ if (this.oldIE())
2635
+ {
2636
+ text = sel.text;
2637
+ }
2638
+ else
2639
+ {
2640
+ text = sel.toString();
2641
+ }
2642
+
2643
+ this.spanid = Math.floor(Math.random() * 99999);
2644
+
2645
+ var html = '<span id="span' + this.spanid + '">' + text + '</span>';
2646
+
2647
+ if (text !== '')
2648
+ {
2649
+ html = '<span id="span' + this.spanid + '">' + text + '</span>';
2650
+ }
2651
+
2652
+ this.execCommand('inserthtml', html);
2653
+ }
2654
+ }
2655
+ else
2656
+ {
2657
+ if (sel && sel.anchorNode && sel.anchorNode.parentNode.tagName === 'A')
2658
+ {
2659
+ url = sel.anchorNode.parentNode.href;
2660
+ text = sel.anchorNode.parentNode.text;
2661
+ if (sel.toString() === '')
2662
+ {
2663
+ this.insert_link_node = sel.anchorNode.parentNode;
2664
+ }
2665
+ }
2666
+ else
2667
+ {
2668
+ text = sel.toString();
2669
+ url = '';
2670
+ }
2671
+ }
2672
+
2673
+ $('.redactor_link_text').val(text);
2674
+
2675
+ var turl = url.replace(top.location.href, '');
2676
+
2677
+ if (url.search('mailto:') === 0)
2678
+ {
2679
+ this.setModalTab(2);
2680
+
2681
+ $('#redactor_tab_selected').val(2);
2682
+ $('#redactor_link_mailto').val(url.replace('mailto:', ''));
2683
+ }
2684
+ else if (turl.search(/^#/gi) === 0)
2685
+ {
2686
+ this.setModalTab(3);
2687
+
2688
+ $('#redactor_tab_selected').val(3);
2689
+ $('#redactor_link_anchor').val(turl.replace(/^#/gi, ''));
2690
+ }
2691
+ else
2692
+ {
2693
+ $('#redactor_link_url').val(url);
2694
+ }
2695
+
2696
+ $('#redactor_insert_link_btn').click($.proxy(this.insertLink, this));
2697
+
2698
+
2699
+ }, this);
2700
+
2701
+ var endCallback = function(url)
2702
+ {
2703
+ $('#redactor_link_url').focus();
2704
+ };
2705
+
2706
+ this.modalInit(RLANG.link, 'link', 460, handler, endCallback);
2707
+
2708
+ },
2709
+ insertLink: function()
2710
+ {
2711
+ var tab_selected = $('#redactor_tab_selected').val();
2712
+ var link = '', text = '';
2713
+
2714
+ if (tab_selected === '1') // url
2715
+ {
2716
+ link = $('#redactor_link_url').val();
2717
+ text = $('#redactor_link_url_text').val();
2718
+ }
2719
+ else if (tab_selected === '2') // mailto
2720
+ {
2721
+ link = 'mailto:' + $('#redactor_link_mailto').val();
2722
+ text = $('#redactor_link_mailto_text').val();
2723
+ }
2724
+ else if (tab_selected === '3') // anchor
2725
+ {
2726
+ link = '#' + $('#redactor_link_anchor').val();
2727
+ text = $('#redactor_link_anchor_text').val();
2728
+ }
2729
+
2730
+ this._insertLink('<a href="' + link + '">' + text + '</a> ', $.trim(text), link);
2731
+
2732
+ },
2733
+ _insertLink: function(a, text, link)
2734
+ {
2735
+ if (text != '')
2736
+ {
2737
+ if (this.insert_link_node)
2738
+ {
2739
+ $(this.insert_link_node).text(text);
2740
+ $(this.insert_link_node).attr('href', link);
2741
+ this.syncCode();
2742
+ }
2743
+ else
2744
+ {
2745
+ if ($.browser.msie)
2746
+ {
2747
+ $(this.doc.getElementById('span' + this.spanid)).replaceWith(a);
2748
+ this.syncCode();
2749
+ }
2750
+ else
2751
+ {
2752
+ this.execCommand('inserthtml', a);
2753
+ }
2754
+ }
2755
+ }
2756
+
2757
+ this.modalClose();
2758
+ },
2759
+
2760
+ // INSERT FILE
2761
+ showFile: function()
2762
+ {
2763
+ if ($.browser.msie)
2764
+ {
2765
+ this.markerIE();
2766
+ }
2767
+
2768
+ var handler = $.proxy(function()
2769
+ {
2770
+ var sel = this.getSelection();
2771
+
2772
+ var text = '';
2773
+
2774
+ if (this.oldIE())
2775
+ {
2776
+ text = sel.text;
2777
+ }
2778
+ else
2779
+ {
2780
+ text = sel.toString();
2781
+ }
2782
+
2783
+ $('#redactor_filename').val(text);
2784
+
2785
+ // dragupload
2786
+ if (this.isMobile() === false)
2787
+ {
2788
+ $('#redactor_file').dragupload(
2789
+ {
2790
+ url: this.opts.fileUpload,
2791
+ success: $.proxy(function(data)
2792
+ {
2793
+ this.fileUploadCallback(data);
2794
+ }, this)
2795
+ });
2796
+ }
2797
+
2798
+ this.uploadInit('redactor_file', { auto: true, url: this.opts.fileUpload, success: $.proxy(function(data) {
2799
+
2800
+ this.fileUploadCallback(data);
2801
+
2802
+ }, this)});
2803
+ }, this);
2804
+
2805
+ this.modalInit(RLANG.file, 'file', 500, handler);
2806
+ },
2807
+ fileUploadCallback: function(json)
2808
+ {
2809
+ var data = $.parseJSON(json);
2810
+ var text = $('#redactor_filename').val();
2811
+
2812
+ if (text === '')
2813
+ {
2814
+ text = data.filename;
2815
+ }
2816
+
2817
+ var link = '<a href="' + data.filelink + '">' + text + '</a>';
2818
+
2819
+ // chrome fix
2820
+ if ($.browser.webkit && !!window.chrome)
2821
+ {
2822
+ link = link + '&nbsp;';
2823
+ }
2824
+
2825
+ if ($.browser.msie)
2826
+ {
2827
+ if (text !== '')
2828
+ {
2829
+ $(this.doc.getElementById('span' + this.spanid)).replaceWith(link);
2830
+ }
2831
+ else
2832
+ {
2833
+ $(this.doc.getElementById('span' + this.spanid)).after(link).remove();
2834
+ }
2835
+
2836
+ this.syncCode();
2837
+ }
2838
+ else
2839
+ {
2840
+ this.execCommand('inserthtml', link);
2841
+ }
2842
+
2843
+ // file upload callback
2844
+ if (typeof this.opts.fileUploadCallback === 'function')
2845
+ {
2846
+ this.opts.fileUploadCallback(this, data);
2847
+ }
2848
+
2849
+ this.modalClose();
2850
+ },
2851
+
2852
+
2853
+
2854
+ // MODAL
2855
+ modalInit: function(title, url, width, handler, endCallback, scroll)
2856
+ {
2857
+ // modal overlay
2858
+ if ($('#redactor_modal_overlay').size() === 0)
2859
+ {
2860
+ this.overlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>');
2861
+ $('body').prepend(this.overlay);
2862
+ }
2863
+
2864
+ if (this.opts.overlay)
2865
+ {
2866
+ $('#redactor_modal_overlay').show();
2867
+ $('#redactor_modal_overlay').click($.proxy(this.modalClose, this));
2868
+ }
2869
+
2870
+ if ($('#redactor_modal').size() === 0)
2871
+ {
2872
+ 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>');
2873
+ $('body').append(this.modal);
2874
+ }
2875
+
2876
+ $('#redactor_modal_close').click($.proxy(this.modalClose, this));
2877
+
2878
+ this.hdlModalClose = $.proxy(function(e) { if ( e.keyCode === 27) { this.modalClose(); } }, this);
2879
+
2880
+ $(document).keyup(this.hdlModalClose);
2881
+ $(this.doc).keyup(this.hdlModalClose);
2882
+
2883
+ $('#redactor_modal_inner').html(this.opts['modal_' + url]);
2884
+ $('#redactor_modal_header').html(title);
2885
+
2886
+ // tabs
2887
+ if ($('#redactor_tabs').size() !== 0)
2888
+ {
2889
+ var that = this;
2890
+ $('#redactor_tabs a').each(function(i,s)
2891
+ {
2892
+ i++;
2893
+ $(s).click(function()
2894
+ {
2895
+ $('#redactor_tabs a').removeClass('redactor_tabs_act');
2896
+ $(this).addClass('redactor_tabs_act');
2897
+ $('.redactor_tab').hide();
2898
+ $('#redactor_tab' + i).show();
2899
+ $('#redactor_tab_selected').val(i);
2900
+
2901
+ if (that.isMobile() === false)
2902
+ {
2903
+ var height = $('#redactor_modal').outerHeight();
2904
+ $('#redactor_modal').css('margin-top', '-' + (height+10)/2 + 'px');
2905
+ }
2906
+ });
2907
+ });
2908
+ }
2909
+
2910
+ $('#redactor_btn_modal_close').click($.proxy(this.modalClose, this));
2911
+
2912
+ // callback
2913
+ if (typeof(handler) === 'function')
2914
+ {
2915
+ handler();
2916
+ }
2917
+
2918
+ // setup
2919
+ var height = $('#redactor_modal').outerHeight();
2920
+
2921
+ if (this.isMobile() === false)
2922
+ {
2923
+ $('#redactor_modal').css({ position: 'fixed', top: '50%', left: '50%', width: width + 'px', height: 'auto', marginTop: '-' + (height+10)/2 + 'px', marginLeft: '-' + (width+60)/2 + 'px' }).fadeIn('fast');
2924
+ }
2925
+ else
2926
+ {
2927
+ $('#redactor_modal').css({ position: 'absolute', width: '96%', height: 'auto', top: '20px', left: '0', marginTop: '0px', marginLeft: '2%' }).show();
2928
+ this.scrolltop();
2929
+ }
2930
+
2931
+
2932
+ // end callback
2933
+ if (typeof(endCallback) === 'function')
2934
+ {
2935
+ endCallback();
2936
+ }
2937
+
2938
+ if (scroll === true)
2939
+ {
2940
+ $('#redactor_image_box').height(300).css('overflow', 'auto');
2941
+ }
2942
+
2943
+ },
2944
+ modalClose: function()
2945
+ {
2946
+
2947
+ $('#redactor_modal_close').unbind('click', this.modalClose);
2948
+ $('#redactor_modal').fadeOut('fast', $.proxy(function()
2949
+ {
2950
+ $('#redactor_modal_inner').html('');
2951
+
2952
+ if (this.opts.overlay)
2953
+ {
2954
+ $('#redactor_modal_overlay').hide();
2955
+ $('#redactor_modal_overlay').unbind('click', this.modalClose);
2956
+ }
2957
+
2958
+ $(document).unbind('keyup', this.hdlModalClose);
2959
+ $(this.doc).unbind('keyup', this.hdlModalClose);
2960
+
2961
+ }, this));
2962
+
2963
+ },
2964
+ setModalTab: function(num)
2965
+ {
2966
+ $('.redactor_tab').hide();
2967
+ var tabs = $('#redactor_tabs a');
2968
+ tabs.removeClass('redactor_tabs_act');
2969
+ tabs.eq(num-1).addClass('redactor_tabs_act');
2970
+ $('#redactor_tab' + num).show();
2971
+ },
2972
+
2973
+ // UPLOAD
2974
+ uploadInit: function(element, options)
2975
+ {
2976
+ // Upload Options
2977
+ this.uploadOptions = {
2978
+ url: false,
2979
+ success: false,
2980
+ start: false,
2981
+ trigger: false,
2982
+ auto: false,
2983
+ input: false
2984
+ };
2985
+
2986
+ $.extend(this.uploadOptions, options);
2987
+
2988
+ // Test input or form
2989
+ if ($('#' + element).size() !== 0 && $('#' + element).get(0).tagName === 'INPUT')
2990
+ {
2991
+ this.uploadOptions.input = $('#' + element);
2992
+ this.element = $($('#' + element).get(0).form);
2993
+ }
2994
+ else
2995
+ {
2996
+ this.element = $('#' + element);
2997
+ }
2998
+
2999
+ this.element_action = this.element.attr('action');
3000
+
3001
+ // Auto or trigger
3002
+ if (this.uploadOptions.auto)
3003
+ {
3004
+ $(this.uploadOptions.input).change($.proxy(function()
3005
+ {
3006
+ this.element.submit(function(e) { return false; });
3007
+ this.uploadSubmit();
3008
+ }, this));
3009
+
3010
+ }
3011
+ else if (this.uploadOptions.trigger)
3012
+ {
3013
+ $('#' + this.uploadOptions.trigger).click($.proxy(this.uploadSubmit, this));
3014
+ }
3015
+ },
3016
+ uploadSubmit : function()
3017
+ {
3018
+ this.uploadForm(this.element, this.uploadFrame());
3019
+ },
3020
+ uploadFrame : function()
3021
+ {
3022
+ this.id = 'f' + Math.floor(Math.random() * 99999);
3023
+
3024
+ var d = document.createElement('div');
3025
+ var iframe = '<iframe style="display:none" src="about:blank" id="'+this.id+'" name="'+this.id+'"></iframe>';
3026
+ d.innerHTML = iframe;
3027
+ document.body.appendChild(d);
3028
+
3029
+ // Start
3030
+ if (this.uploadOptions.start)
3031
+ {
3032
+ this.uploadOptions.start();
3033
+ }
3034
+
3035
+ $('#' + this.id).load($.proxy(this.uploadLoaded, this));
3036
+
3037
+ return this.id;
3038
+ },
3039
+ uploadForm : function(f, name)
3040
+ {
3041
+ if (this.uploadOptions.input)
3042
+ {
3043
+ var formId = 'redactorUploadForm' + this.id;
3044
+ var fileId = 'redactorUploadFile' + this.id;
3045
+ this.form = $('<form action="' + this.uploadOptions.url + '" method="POST" target="' + name + '" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
3046
+
3047
+ var oldElement = this.uploadOptions.input;
3048
+ var newElement = $(oldElement).clone();
3049
+ $(oldElement).attr('id', fileId);
3050
+ $(oldElement).before(newElement);
3051
+ $(oldElement).appendTo(this.form);
3052
+ $(this.form).css('position', 'absolute');
3053
+ $(this.form).css('top', '-2000px');
3054
+ $(this.form).css('left', '-2000px');
3055
+ $(this.form).appendTo('body');
3056
+
3057
+ // Rails admin integration workround
3058
+ $('input[name="utf8"]').clone().appendTo(this.form);
3059
+ $('input[name="authenticity_token"]').clone().appendTo(this.form);
3060
+
3061
+ this.form.submit();
3062
+ }
3063
+ else
3064
+ {
3065
+ f.attr('target', name);
3066
+ f.attr('method', 'POST');
3067
+ f.attr('enctype', 'multipart/form-data');
3068
+ f.attr('action', this.uploadOptions.url);
3069
+
3070
+ this.element.submit();
3071
+ }
3072
+
3073
+ },
3074
+ uploadLoaded : function()
3075
+ {
3076
+ var i = $('#' + this.id);
3077
+ var d;
3078
+
3079
+ if (i.contentDocument)
3080
+ {
3081
+ d = i.contentDocument;
3082
+ }
3083
+ else if (i.contentWindow)
3084
+ {
3085
+ d = i.contentWindow.document;
3086
+ }
3087
+ else
3088
+ {
3089
+ d = window.frames[this.id].document;
3090
+ }
3091
+
3092
+ if (d.location.href === "about:blank")
3093
+ {
3094
+ return true;
3095
+ }
3096
+
3097
+ // Success
3098
+ if (this.uploadOptions.success)
3099
+ {
3100
+ // Remove bizarre <pre> tag wrappers around our json data:
3101
+ var rawString = d.body.innerHTML;
3102
+ var jsonString = rawString.match(/\{.*\}/)[0];
3103
+ this.uploadOptions.success(jsonString);
3104
+ }
3105
+
3106
+ this.element.attr('action', this.element_action);
3107
+ this.element.attr('target', '');
3108
+
3109
+ },
3110
+
3111
+ // UTILITY
3112
+ markerIE: function()
3113
+ {
3114
+ this.spanid = Math.floor(Math.random() * 99999);
3115
+ this.execCommand('inserthtml', '<span id="span' + this.spanid + '"></span>');
3116
+ },
3117
+ oldIE: function()
3118
+ {
3119
+ if ($.browser.msie && parseInt($.browser.version, 10) < 9)
3120
+ {
3121
+ return true;
3122
+ }
3123
+
3124
+ return false;
3125
+ },
3126
+ outerHTML: function(s)
3127
+ {
3128
+ return $("<p>").append($(s).eq(0).clone()).html();
3129
+ },
3130
+ normalize: function(str)
3131
+ {
3132
+ return parseInt(str.replace('px',''), 10);
3133
+ },
3134
+ isMobile: function()
3135
+ {
3136
+ if (/(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent))
3137
+ {
3138
+ return true;
3139
+ }
3140
+ else
3141
+ {
3142
+ return false;
3143
+ }
3144
+ },
3145
+ scrolltop: function()
3146
+ {
3147
+ $('html,body').animate({ scrollTop: 0 }, 500);
3148
+ }
3149
+
3150
+ };
3151
+
3152
+
3153
+ // API
3154
+ $.fn.getDoc = function()
3155
+ {
3156
+ return $(this.data('redactor').doc);
3157
+ };
3158
+
3159
+ $.fn.getFrame = function()
3160
+ {
3161
+ return this.data('redactor').$frame;
3162
+ };
3163
+
3164
+ $.fn.getEditor = function()
3165
+ {
3166
+ return this.data('redactor').$editor;
3167
+ };
3168
+
3169
+ $.fn.getCode = function()
3170
+ {
3171
+ return this.data('redactor').getCode();
3172
+ };
3173
+
3174
+ $.fn.getText = function()
3175
+ {
3176
+ return this.data('redactor').$editor.text();
3177
+ };
3178
+
3179
+ $.fn.setCode = function(html)
3180
+ {
3181
+ this.data('redactor').setCode(html);
3182
+ };
3183
+
3184
+ $.fn.insertHtml = function(html)
3185
+ {
3186
+ this.data('redactor').insertHtml(html);
3187
+ };
3188
+
3189
+ $.fn.destroyEditor = function()
3190
+ {
3191
+ this.data('redactor').destroy();
3192
+ this.removeData('redactor');
3193
+ };
3194
+
3195
+ $.fn.setFocus = function()
3196
+ {
3197
+ this.data('redactor').focus();
3198
+ };
3199
+
3200
+ $.fn.execCommand = function(cmd, param)
3201
+ {
3202
+ this.data('redactor').execCommand(cmd, param);
3203
+ };
3204
+
3205
+ })(jQuery);
3206
+
3207
+ /*
3208
+ Plugin Drag and drop Upload v1.0.1
3209
+ http://imperavi.com/
3210
+ Copyright 2012, Imperavi Ltd.
3211
+ */
3212
+ (function($){
3213
+
3214
+ "use strict";
3215
+
3216
+ // Initialization
3217
+ $.fn.dragupload = function(options)
3218
+ {
3219
+ return this.each(function() {
3220
+ var obj = new Construct(this, options);
3221
+ obj.init();
3222
+ });
3223
+ };
3224
+
3225
+ // Options and variables
3226
+ function Construct(el, options) {
3227
+
3228
+ this.opts = $.extend({
3229
+
3230
+ url: false,
3231
+ success: false,
3232
+ preview: false,
3233
+
3234
+ text: RLANG.drop_file_here,
3235
+ atext: RLANG.or_choose
3236
+
3237
+ }, options);
3238
+
3239
+ this.$el = $(el);
3240
+ }
3241
+
3242
+ // Functionality
3243
+ Construct.prototype = {
3244
+ init: function()
3245
+ {
3246
+ if (!$.browser.opera && !$.browser.msie)
3247
+ {
3248
+
3249
+ this.droparea = $('<div class="redactor_droparea"></div>');
3250
+ this.dropareabox = $('<div class="redactor_dropareabox">' + this.opts.text + '</div>');
3251
+ this.dropalternative = $('<div class="redactor_dropalternative">' + this.opts.atext + '</div>');
3252
+
3253
+ this.droparea.append(this.dropareabox);
3254
+
3255
+ this.$el.before(this.droparea);
3256
+ this.$el.before(this.dropalternative);
3257
+
3258
+ // drag over
3259
+ this.dropareabox.bind('dragover', $.proxy(function() { return this.ondrag(); }, this));
3260
+
3261
+ // drag leave
3262
+ this.dropareabox.bind('dragleave', $.proxy(function() { return this.ondragleave(); }, this));
3263
+
3264
+ var uploadProgress = $.proxy(function(e)
3265
+ {
3266
+ var percent = parseInt(e.loaded / e.total * 100, 10);
3267
+ this.dropareabox.text('Loading ' + percent + '%');
3268
+
3269
+ }, this);
3270
+
3271
+ var xhr = jQuery.ajaxSettings.xhr();
3272
+
3273
+ if (xhr.upload)
3274
+ {
3275
+ xhr.upload.addEventListener('progress', uploadProgress, false);
3276
+ }
3277
+
3278
+ var provider = function () { return xhr; };
3279
+
3280
+ // drop
3281
+ this.dropareabox.get(0).ondrop = $.proxy(function(event)
3282
+ {
3283
+ event.preventDefault();
3284
+
3285
+ this.dropareabox.removeClass('hover').addClass('drop');
3286
+
3287
+ var file = event.dataTransfer.files[0];
3288
+
3289
+ var fd = new FormData();
3290
+ fd.append('file', file);
3291
+
3292
+ $.ajax({
3293
+ dataType: 'html',
3294
+ url: this.opts.url,
3295
+ data: fd,
3296
+ xhr: provider,
3297
+ cache: false,
3298
+ contentType: false,
3299
+ processData: false,
3300
+ type: 'POST',
3301
+ success: $.proxy(function(data)
3302
+ {
3303
+ if (this.opts.success !== false)
3304
+ {
3305
+ this.opts.success(data);
3306
+ }
3307
+
3308
+ if (this.opts.preview === true)
3309
+ {
3310
+ this.dropareabox.html(data);
3311
+ }
3312
+
3313
+ }, this)
3314
+ });
3315
+
3316
+ }, this);
3317
+ }
3318
+ },
3319
+ ondrag: function()
3320
+ {
3321
+ this.dropareabox.addClass('hover');
3322
+ return false;
3323
+ },
3324
+ ondragleave: function()
3325
+ {
3326
+ this.dropareabox.removeClass('hover');
3327
+ return false;
3328
+ }
3329
+ };
3330
+
3331
+ })(jQuery);
3332
+
3333
+
3334
+ // Define: Linkify plugin from stackoverflow
3335
+ (function($){
3336
+
3337
+ "use strict";
3338
+
3339
+ var url1 = /(^|&lt;|\s)(www\..+?\..+?)(\s|&gt;|$)/g,
3340
+ url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/g,
3341
+
3342
+ linkifyThis = function ()
3343
+ {
3344
+ var childNodes = this.childNodes,
3345
+ i = childNodes.length;
3346
+ while(i--)
3347
+ {
3348
+ var n = childNodes[i];
3349
+ if (n.nodeType === 3)
3350
+ {
3351
+ var html = n.nodeValue;
3352
+ if (html)
3353
+ {
3354
+ html = html.replace(/&/g, '&amp;')
3355
+ .replace(/</g, '&lt;')
3356
+ .replace(/>/g, '&gt;')
3357
+ .replace(url1, '$1<a href="http://$2">$2</a>$3')
3358
+ .replace(url2, '$1<a href="$2">$2</a>$5');
3359
+
3360
+ $(n).after(html).remove();
3361
+ }
3362
+ }
3363
+ else if (n.nodeType === 1 && !/^(a|button|textarea)$/i.test(n.tagName))
3364
+ {
3365
+ linkifyThis.call(n);
3366
+ }
3367
+ }
3368
+ };
3369
+
3370
+ $.fn.linkify = function ()
3371
+ {
3372
+ this.each(linkifyThis);
3373
+ };
3374
+
3375
+ })(jQuery);