kuhsaft 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module Kuhsaft
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -0,0 +1,4210 @@
1
+ /*
2
+ Redactor v8.2.2
3
+ Updated: January 17, 2013
4
+
5
+ http://redactorjs.com/
6
+
7
+ Copyright (c) 2009-2013, Imperavi Inc.
8
+ License: http://redactorjs.com/license/
9
+
10
+ Usage: $('#content').redactor();
11
+ */
12
+
13
+ var rwindow, rdocument;
14
+
15
+ if (typeof RELANG === 'undefined')
16
+ {
17
+ var RELANG = {};
18
+ }
19
+
20
+ var RLANG = {
21
+ html: 'HTML',
22
+ video: 'Insert Video',
23
+ image: 'Insert Image',
24
+ table: 'Table',
25
+ link: 'Link',
26
+ link_insert: 'Insert link',
27
+ unlink: 'Unlink',
28
+ formatting: 'Formatting',
29
+ paragraph: 'Paragraph',
30
+ quote: 'Quote',
31
+ code: 'Code',
32
+ header1: 'Header 1',
33
+ header2: 'Header 2',
34
+ header3: 'Header 3',
35
+ header4: 'Header 4',
36
+ bold: 'Bold',
37
+ italic: 'Italic',
38
+ fontcolor: 'Font Color',
39
+ backcolor: 'Back Color',
40
+ unorderedlist: 'Unordered List',
41
+ orderedlist: 'Ordered List',
42
+ outdent: 'Outdent',
43
+ indent: 'Indent',
44
+ cancel: 'Cancel',
45
+ insert: 'Insert',
46
+ save: 'Save',
47
+ _delete: 'Delete',
48
+ insert_table: 'Insert Table',
49
+ insert_row_above: 'Add Row Above',
50
+ insert_row_below: 'Add Row Below',
51
+ insert_column_left: 'Add Column Left',
52
+ insert_column_right: 'Add Column Right',
53
+ delete_column: 'Delete Column',
54
+ delete_row: 'Delete Row',
55
+ delete_table: 'Delete Table',
56
+ rows: 'Rows',
57
+ columns: 'Columns',
58
+ add_head: 'Add Head',
59
+ delete_head: 'Delete Head',
60
+ title: 'Title',
61
+ image_position: 'Position',
62
+ none: 'None',
63
+ left: 'Left',
64
+ right: 'Right',
65
+ image_web_link: 'Image Web Link',
66
+ text: 'Text',
67
+ mailto: 'Email',
68
+ web: 'URL',
69
+ video_html_code: 'Video Embed Code',
70
+ file: 'Insert File',
71
+ upload: 'Upload',
72
+ download: 'Download',
73
+ choose: 'Choose',
74
+ or_choose: 'Or choose',
75
+ drop_file_here: 'Drop file here',
76
+ align_left: 'Align text to the left',
77
+ align_center: 'Center text',
78
+ align_right: 'Align text to the right',
79
+ align_justify: 'Justify text',
80
+ horizontalrule: 'Insert Horizontal Rule',
81
+ deleted: 'Deleted',
82
+ anchor: 'Anchor',
83
+ link_new_tab: 'Open link in new tab',
84
+ underline: 'Underline',
85
+ alignment: 'Alignment'
86
+ };
87
+
88
+ (function($){
89
+
90
+ // Plugin
91
+ jQuery.fn.redactor = function(option)
92
+ {
93
+ return this.each(function()
94
+ {
95
+ var $obj = $(this);
96
+
97
+ var data = $obj.data('redactor');
98
+ if (!data)
99
+ {
100
+ $obj.data('redactor', (data = new Redactor(this, option)));
101
+ }
102
+ });
103
+ };
104
+
105
+
106
+ // Initialization
107
+ var Redactor = function(element, options)
108
+ {
109
+ // Element
110
+ this.$el = $(element);
111
+
112
+ // Lang
113
+ if (typeof options !== 'undefined' && typeof options.lang !== 'undefined' && options.lang !== 'en' && typeof RELANG[options.lang] !== 'undefined')
114
+ {
115
+ RLANG = RELANG[options.lang];
116
+ }
117
+
118
+ // Options
119
+ this.opts = $.extend({
120
+
121
+ iframe: false,
122
+ css: false, // url
123
+
124
+ lang: 'en',
125
+ direction: 'ltr', // ltr or rtl
126
+
127
+ callback: false, // function
128
+ keyupCallback: false, // function
129
+ keydownCallback: false, // function
130
+ execCommandCallback: false, // function
131
+
132
+ plugins: false,
133
+ cleanup: true,
134
+
135
+ focus: false,
136
+ tabindex: false,
137
+ autoresize: true,
138
+ minHeight: false,
139
+ fixed: false,
140
+ fixedTop: 0, // pixels
141
+ fixedBox: false,
142
+ source: true,
143
+ shortcuts: true,
144
+
145
+ mobile: true,
146
+ air: false, // true or toolbar
147
+ wym: false,
148
+
149
+ convertLinks: true,
150
+ convertDivs: true,
151
+ protocol: 'http://', // for links http or https or ftp or false
152
+
153
+ autosave: false, // false or url
154
+ autosaveCallback: false, // function
155
+ interval: 60, // seconds
156
+
157
+ imageGetJson: false, // url (ex. /folder/images.json ) or false
158
+
159
+ imageUpload: false, // url
160
+ imageUploadCallback: false, // function
161
+ imageUploadErrorCallback: false, // function
162
+
163
+ fileUpload: false, // url
164
+ fileUploadCallback: false, // function
165
+ fileUploadErrorCallback: false, // function
166
+
167
+ uploadCrossDomain: false,
168
+ uploadFields: false,
169
+
170
+ observeImages: true,
171
+ overlay: true, // modal overlay
172
+
173
+ allowedTags: ["form", "input", "button", "select", "option", "datalist", "output", "textarea", "fieldset", "legend",
174
+ "section", "header", "hgroup", "aside", "footer", "article", "details", "nav", "progress", "time", "canvas",
175
+ "code", "span", "div", "label", "a", "br", "p", "b", "i", "del", "strike", "u",
176
+ "img", "video", "source", "track", "audio", "iframe", "object", "embed", "param", "blockquote",
177
+ "mark", "cite", "small", "ul", "ol", "li", "hr", "dl", "dt", "dd", "sup", "sub",
178
+ "big", "pre", "code", "figure", "figcaption", "strong", "em", "table", "tr", "td",
179
+ "th", "tbody", "thead", "tfoot", "h1", "h2", "h3", "h4", "h5", "h6"],
180
+
181
+ toolbarExternal: false, // ID selector
182
+
183
+ buttonsCustom: {},
184
+ buttonsAdd: [],
185
+ buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
186
+ 'image', 'video', 'file', 'table', 'link', '|',
187
+ 'fontcolor', 'backcolor', '|', 'alignment', '|', 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify'
188
+
189
+ airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'fontcolor', 'backcolor'],
190
+
191
+ formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4'],
192
+
193
+ activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist'], // 'alignleft', 'aligncenter', 'alignright', 'justify'
194
+ activeButtonsStates: {
195
+ b: 'bold',
196
+ strong: 'bold',
197
+ i: 'italic',
198
+ em: 'italic',
199
+ del: 'deleted',
200
+ strike: 'deleted',
201
+ ul: 'unorderedlist',
202
+ ol: 'orderedlist',
203
+ u: 'underline'
204
+ },
205
+
206
+ colors: [
207
+ '#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00',
208
+ '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca',
209
+ '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694',
210
+ '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314',
211
+ '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100',
212
+ '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000'],
213
+
214
+ // private
215
+ emptyHtml: '<p><br /></p>',
216
+ buffer: false,
217
+ visual: true,
218
+
219
+ // modal windows container
220
+ modal_file: String() +
221
+ '<div id="redactor_modal_content">' +
222
+ '<form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">' +
223
+ '<label>Name (optional)</label>' +
224
+ '<input type="text" id="redactor_filename" class="redactor_input" />' +
225
+ '<div style="margin-top: 7px;">' +
226
+ '<input type="file" id="redactor_file" name="file" />' +
227
+ '</div>' +
228
+ '</form><br>' +
229
+ '</div>',
230
+
231
+ modal_image_edit: String() +
232
+ '<div id="redactor_modal_content">' +
233
+ '<label>' + RLANG.title + '</label>' +
234
+ '<input id="redactor_file_alt" class="redactor_input" />' +
235
+ '<label>' + RLANG.link + '</label>' +
236
+ '<input id="redactor_file_link" class="redactor_input" />' +
237
+ '<label>' + RLANG.image_position + '</label>' +
238
+ '<select id="redactor_form_image_align">' +
239
+ '<option value="none">' + RLANG.none + '</option>' +
240
+ '<option value="left">' + RLANG.left + '</option>' +
241
+ '<option value="right">' + RLANG.right + '</option>' +
242
+ '</select>' +
243
+ '</div>' +
244
+ '<div id="redactor_modal_footer">' +
245
+ '<a href="javascript:void(null);" id="redactor_image_delete_btn" class="redactor_modal_btn">' + RLANG._delete + '</a>&nbsp;&nbsp;&nbsp;' +
246
+ '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
247
+ '<input type="button" name="save" class="redactor_modal_btn" id="redactorSaveBtn" value="' + RLANG.save + '" />' +
248
+ '</div>',
249
+
250
+ modal_image: String() +
251
+ '<div id="redactor_modal_content">' +
252
+ '<div id="redactor_tabs">' +
253
+ '<a href="javascript:void(null);" class="redactor_tabs_act">' + RLANG.upload + '</a>' +
254
+ '<a href="javascript:void(null);">' + RLANG.choose + '</a>' +
255
+ '<a href="javascript:void(null);">' + RLANG.link + '</a>' +
256
+ '</div>' +
257
+ '<form id="redactorInsertImageForm" method="post" action="" enctype="multipart/form-data">' +
258
+ '<div id="redactor_tab1" class="redactor_tab">' +
259
+ '<input type="file" id="redactor_file" name="file" />' +
260
+ '</div>' +
261
+ '<div id="redactor_tab2" class="redactor_tab" style="display: none;">' +
262
+ '<div id="redactor_image_box"></div>' +
263
+ '</div>' +
264
+ '</form>' +
265
+ '<div id="redactor_tab3" class="redactor_tab" style="display: none;">' +
266
+ '<label>' + RLANG.image_web_link + '</label>' +
267
+ '<input type="text" name="redactor_file_link" id="redactor_file_link" class="redactor_input" />' +
268
+ '</div>' +
269
+ '</div>' +
270
+ '<div id="redactor_modal_footer">' +
271
+ '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
272
+ '<input type="button" name="upload" class="redactor_modal_btn" id="redactor_upload_btn" value="' + RLANG.insert + '" />' +
273
+ '</div>',
274
+
275
+ modal_link: String() +
276
+ '<div id="redactor_modal_content">' +
277
+ '<form id="redactorInsertLinkForm" method="post" action="">' +
278
+ '<div id="redactor_tabs">' +
279
+ '<a href="javascript:void(null);" class="redactor_tabs_act">URL</a>' +
280
+ '<a href="javascript:void(null);">Email</a>' +
281
+ '<a href="javascript:void(null);">' + RLANG.anchor + '</a>' +
282
+ '</div>' +
283
+ '<input type="hidden" id="redactor_tab_selected" value="1" />' +
284
+ '<div class="redactor_tab" id="redactor_tab1">' +
285
+ '<label>URL</label><input type="text" id="redactor_link_url" class="redactor_input" />' +
286
+ '<label>' + RLANG.text + '</label><input type="text" class="redactor_input redactor_link_text" id="redactor_link_url_text" />' +
287
+ '<label><input type="checkbox" id="redactor_link_blank"> ' + RLANG.link_new_tab + '</label>' +
288
+ '</div>' +
289
+ '<div class="redactor_tab" id="redactor_tab2" style="display: none;">' +
290
+ '<label>Email</label><input type="text" id="redactor_link_mailto" class="redactor_input" />' +
291
+ '<label>' + RLANG.text + '</label><input type="text" class="redactor_input redactor_link_text" id="redactor_link_mailto_text" />' +
292
+ '</div>' +
293
+ '<div class="redactor_tab" id="redactor_tab3" style="display: none;">' +
294
+ '<label>' + RLANG.anchor + '</label><input type="text" class="redactor_input" id="redactor_link_anchor" />' +
295
+ '<label>' + RLANG.text + '</label><input type="text" class="redactor_input redactor_link_text" id="redactor_link_anchor_text" />' +
296
+ '</div>' +
297
+ '</form>' +
298
+ '</div>' +
299
+ '<div id="redactor_modal_footer">' +
300
+ '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
301
+ '<input type="button" class="redactor_modal_btn" id="redactor_insert_link_btn" value="' + RLANG.insert + '" />' +
302
+ '</div>',
303
+
304
+ modal_table: String() +
305
+ '<div id="redactor_modal_content">' +
306
+ '<label>' + RLANG.rows + '</label>' +
307
+ '<input type="text" size="5" value="2" id="redactor_table_rows" />' +
308
+ '<label>' + RLANG.columns + '</label>' +
309
+ '<input type="text" size="5" value="3" id="redactor_table_columns" />' +
310
+ '</div>' +
311
+ '<div id="redactor_modal_footer">' +
312
+ '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
313
+ '<input type="button" name="upload" class="redactor_modal_btn" id="redactor_insert_table_btn" value="' + RLANG.insert + '" />' +
314
+ '</div>',
315
+
316
+ modal_video: String() +
317
+ '<div id="redactor_modal_content">' +
318
+ '<form id="redactorInsertVideoForm">' +
319
+ '<label>' + RLANG.video_html_code + '</label>' +
320
+ '<textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>' +
321
+ '</form>' +
322
+ '</div>'+
323
+ '<div id="redactor_modal_footer">' +
324
+ '<a href="javascript:void(null);" class="redactor_modal_btn redactor_btn_modal_close">' + RLANG.cancel + '</a>' +
325
+ '<input type="button" class="redactor_modal_btn" id="redactor_insert_video_btn" value="' + RLANG.insert + '" />' +
326
+ '</div>',
327
+
328
+ toolbar: {
329
+ html:
330
+ {
331
+ title: RLANG.html,
332
+ func: 'toggle'
333
+ },
334
+ formatting:
335
+ {
336
+ title: RLANG.formatting,
337
+ func: 'show',
338
+ dropdown:
339
+ {
340
+ p:
341
+ {
342
+ title: RLANG.paragraph,
343
+ exec: 'formatblock'
344
+ },
345
+ blockquote:
346
+ {
347
+ title: RLANG.quote,
348
+ exec: 'formatblock',
349
+ className: 'redactor_format_blockquote'
350
+ },
351
+ pre:
352
+ {
353
+ title: RLANG.code,
354
+ exec: 'formatblock',
355
+ className: 'redactor_format_pre'
356
+ },
357
+ h1:
358
+ {
359
+ title: RLANG.header1,
360
+ exec: 'formatblock',
361
+ className: 'redactor_format_h1'
362
+ },
363
+ h2:
364
+ {
365
+ title: RLANG.header2,
366
+ exec: 'formatblock',
367
+ className: 'redactor_format_h2'
368
+ },
369
+ h3:
370
+ {
371
+ title: RLANG.header3,
372
+ exec: 'formatblock',
373
+ className: 'redactor_format_h3'
374
+ },
375
+ h4:
376
+ {
377
+ title: RLANG.header4,
378
+ exec: 'formatblock',
379
+ className: 'redactor_format_h4'
380
+ }
381
+ }
382
+ },
383
+ bold:
384
+ {
385
+ title: RLANG.bold,
386
+ exec: 'bold'
387
+ },
388
+ italic:
389
+ {
390
+ title: RLANG.italic,
391
+ exec: 'italic'
392
+ },
393
+ deleted:
394
+ {
395
+ title: RLANG.deleted,
396
+ exec: 'strikethrough'
397
+ },
398
+ underline:
399
+ {
400
+ title: RLANG.underline,
401
+ exec: 'underline'
402
+ },
403
+ unorderedlist:
404
+ {
405
+ title: '&bull; ' + RLANG.unorderedlist,
406
+ exec: 'insertunorderedlist'
407
+ },
408
+ orderedlist:
409
+ {
410
+ title: '1. ' + RLANG.orderedlist,
411
+ exec: 'insertorderedlist'
412
+ },
413
+ outdent:
414
+ {
415
+ title: '< ' + RLANG.outdent,
416
+ exec: 'outdent'
417
+ },
418
+ indent:
419
+ {
420
+ title: '> ' + RLANG.indent,
421
+ exec: 'indent'
422
+ },
423
+ image:
424
+ {
425
+ title: RLANG.image,
426
+ func: 'showImage'
427
+ },
428
+ video:
429
+ {
430
+ title: RLANG.video,
431
+ func: 'showVideo'
432
+ },
433
+ file:
434
+ {
435
+ title: RLANG.file,
436
+ func: 'showFile'
437
+ },
438
+ table:
439
+ {
440
+ title: RLANG.table,
441
+ func: 'show',
442
+ dropdown:
443
+ {
444
+ insert_table:
445
+ {
446
+ title: RLANG.insert_table,
447
+ func: 'showTable'
448
+ },
449
+ separator_drop1:
450
+ {
451
+ name: 'separator'
452
+ },
453
+ insert_row_above:
454
+ {
455
+ title: RLANG.insert_row_above,
456
+ func: 'insertRowAbove'
457
+ },
458
+ insert_row_below:
459
+ {
460
+ title: RLANG.insert_row_below,
461
+ func: 'insertRowBelow'
462
+ },
463
+ insert_column_left:
464
+ {
465
+ title: RLANG.insert_column_left,
466
+ func: 'insertColumnLeft'
467
+ },
468
+ insert_column_right:
469
+ {
470
+ title: RLANG.insert_column_right,
471
+ func: 'insertColumnRight'
472
+ },
473
+ separator_drop2:
474
+ {
475
+ name: 'separator'
476
+ },
477
+ add_head:
478
+ {
479
+ title: RLANG.add_head,
480
+ func: 'addHead'
481
+ },
482
+ delete_head:
483
+ {
484
+ title: RLANG.delete_head,
485
+ func: 'deleteHead'
486
+ },
487
+ separator_drop3:
488
+ {
489
+ name: 'separator'
490
+ },
491
+ delete_column:
492
+ {
493
+ title: RLANG.delete_column,
494
+ func: 'deleteColumn'
495
+ },
496
+ delete_row:
497
+ {
498
+ title: RLANG.delete_row,
499
+ func: 'deleteRow'
500
+ },
501
+ delete_table:
502
+ {
503
+ title: RLANG.delete_table,
504
+ func: 'deleteTable'
505
+ }
506
+ }
507
+ },
508
+ link:
509
+ {
510
+ title: RLANG.link,
511
+ func: 'show',
512
+ dropdown:
513
+ {
514
+ link:
515
+ {
516
+ title: RLANG.link_insert,
517
+ func: 'showLink'
518
+ },
519
+ unlink:
520
+ {
521
+ title: RLANG.unlink,
522
+ exec: 'unlink'
523
+ }
524
+ }
525
+ },
526
+ fontcolor:
527
+ {
528
+ title: RLANG.fontcolor,
529
+ func: 'show'
530
+ },
531
+ backcolor:
532
+ {
533
+ title: RLANG.backcolor,
534
+ func: 'show'
535
+ },
536
+ alignment:
537
+ {
538
+ title: RLANG.alignment,
539
+ func: 'show',
540
+ dropdown:
541
+ {
542
+ alignleft:
543
+ {
544
+ title: RLANG.align_left,
545
+ exec: 'JustifyLeft'
546
+ },
547
+ aligncenter:
548
+ {
549
+ title: RLANG.align_center,
550
+ exec: 'JustifyCenter'
551
+ },
552
+ alignright:
553
+ {
554
+ title: RLANG.align_right,
555
+ exec: 'JustifyRight'
556
+ },
557
+ justify:
558
+ {
559
+ title: RLANG.align_justify,
560
+ exec: 'JustifyFull'
561
+ }
562
+ }
563
+ },
564
+ alignleft:
565
+ {
566
+ exec: 'JustifyLeft',
567
+ title: RLANG.align_left
568
+ },
569
+ aligncenter:
570
+ {
571
+ exec: 'JustifyCenter',
572
+ title: RLANG.align_center
573
+ },
574
+ alignright:
575
+ {
576
+ exec: 'JustifyRight',
577
+ title: RLANG.align_right
578
+ },
579
+ justify:
580
+ {
581
+ exec: 'JustifyFull',
582
+ title: RLANG.align_justify
583
+ },
584
+ horizontalrule:
585
+ {
586
+ exec: 'inserthorizontalrule',
587
+ title: RLANG.horizontalrule
588
+ }
589
+ }
590
+
591
+
592
+ }, options, this.$el.data());
593
+
594
+ this.dropdowns = [];
595
+
596
+ // Init
597
+ this.init();
598
+ };
599
+
600
+ // Functionality
601
+ Redactor.prototype = {
602
+
603
+
604
+ // Initialization
605
+ init: function()
606
+ {
607
+ // get dimensions
608
+ this.height = this.$el.css('height');
609
+ this.width = this.$el.css('width');
610
+
611
+ rdocument = this.document = document;
612
+ rwindow = this.window = window;
613
+
614
+ // mobile
615
+ if (this.opts.mobile === false && this.isMobile())
616
+ {
617
+ this.build(true);
618
+ return false;
619
+ }
620
+
621
+ // iframe
622
+ if (this.opts.iframe)
623
+ {
624
+ this.opts.autoresize = false;
625
+ }
626
+
627
+ // extend buttons
628
+ if (this.opts.air)
629
+ {
630
+ this.opts.buttons = this.opts.airButtons;
631
+ }
632
+ else if (this.opts.toolbar !== false)
633
+ {
634
+ if (this.opts.source === false)
635
+ {
636
+ var index = this.opts.buttons.indexOf('html');
637
+ var next = this.opts.buttons[index+1];
638
+ this.opts.buttons.splice(index, 1);
639
+ if (typeof next !== 'undefined' && next === '|')
640
+ {
641
+ this.opts.buttons.splice(index, 1);
642
+ }
643
+ }
644
+
645
+ $.extend(this.opts.toolbar, this.opts.buttonsCustom);
646
+ $.each(this.opts.buttonsAdd, $.proxy(function(i,s)
647
+ {
648
+ this.opts.buttons.push(s);
649
+
650
+ }, this));
651
+ }
652
+
653
+ // formatting tags
654
+ if (this.opts.toolbar !== false)
655
+ {
656
+ $.each(this.opts.toolbar.formatting.dropdown, $.proxy(function(i,s)
657
+ {
658
+ if ($.inArray(i, this.opts.formattingTags) == '-1')
659
+ {
660
+ delete this.opts.toolbar.formatting.dropdown[i];
661
+ }
662
+
663
+ }, this));
664
+ }
665
+
666
+ function afterBuild()
667
+ {
668
+ // air enable
669
+ this.enableAir();
670
+
671
+ // toolbar
672
+ this.buildToolbar();
673
+
674
+ // PLUGINS
675
+ if (typeof this.opts.plugins === 'object')
676
+ {
677
+ $.each(this.opts.plugins, $.proxy(function(i,s)
678
+ {
679
+ if (typeof RedactorPlugins[s] !== 'undefined')
680
+ {
681
+ $.extend(this, RedactorPlugins[s]);
682
+
683
+ if (typeof RedactorPlugins[s].init !== 'undefined')
684
+ {
685
+ this.init();
686
+ }
687
+ }
688
+
689
+ }, this));
690
+ }
691
+
692
+ // buttons response
693
+ if (this.opts.activeButtons !== false && this.opts.toolbar !== false)
694
+ {
695
+ var observeFormatting = $.proxy(function() { this.observeFormatting(); }, this);
696
+ this.$editor.click(observeFormatting).keyup(observeFormatting);
697
+ }
698
+
699
+ // paste
700
+ var oldsafari = false;
701
+ if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1)
702
+ {
703
+ var arr = this.browser('version').split('.');
704
+ if (arr[0] < 536) oldsafari = true;
705
+ }
706
+
707
+ if (this.isMobile(true) === false && oldsafari === false)
708
+ {
709
+ this.$editor.bind('paste', $.proxy(function(e)
710
+ {
711
+ if (this.opts.cleanup === false)
712
+ {
713
+ return true;
714
+ }
715
+
716
+ this.pasteRunning = true;
717
+
718
+ this.setBuffer();
719
+
720
+ if (this.opts.autoresize === true)
721
+ {
722
+ this.saveScroll = this.document.body.scrollTop;
723
+ }
724
+ else
725
+ {
726
+ this.saveScroll = this.$editor.scrollTop();
727
+ }
728
+
729
+ var frag = this.extractContent();
730
+
731
+ setTimeout($.proxy(function()
732
+ {
733
+ var pastedFrag = this.extractContent();
734
+ this.$editor.append(frag);
735
+
736
+ this.restoreSelection();
737
+
738
+ var html = this.getFragmentHtml(pastedFrag);
739
+ this.pasteCleanUp(html);
740
+ this.pasteRunning = false;
741
+
742
+ }, this), 1);
743
+
744
+ }, this));
745
+ }
746
+
747
+ // key handlers
748
+ this.keyup();
749
+ this.keydown();
750
+
751
+ // autosave
752
+ if (this.opts.autosave !== false)
753
+ {
754
+ this.autoSave();
755
+ }
756
+
757
+ // observers
758
+ setTimeout($.proxy(function()
759
+ {
760
+ this.observeImages();
761
+ this.observeTables();
762
+
763
+ }, this), 1);
764
+
765
+ // FF fix
766
+ if (this.browser('mozilla'))
767
+ {
768
+ this.$editor.click($.proxy(function()
769
+ {
770
+ this.saveSelection();
771
+ }, this));
772
+
773
+ try
774
+ {
775
+ this.document.execCommand('enableObjectResizing', false, false);
776
+ this.document.execCommand('enableInlineTableEditing', false, false);
777
+ }
778
+ catch (e) {}
779
+ }
780
+
781
+ // focus
782
+ if (this.opts.focus)
783
+ {
784
+ setTimeout($.proxy(function(){
785
+ this.$editor.focus();
786
+ }, this), 1);
787
+ }
788
+
789
+ // fixed
790
+ if (this.opts.fixed)
791
+ {
792
+ this.observeScroll();
793
+ $(document).scroll($.proxy(this.observeScroll, this));
794
+ }
795
+
796
+ // callback
797
+ if (typeof this.opts.callback === 'function')
798
+ {
799
+ this.opts.callback(this);
800
+ }
801
+
802
+ if (this.opts.toolbar !== false)
803
+ {
804
+ this.$toolbar.find('a').attr('tabindex', '-1');
805
+ }
806
+ }
807
+
808
+ // construct editor
809
+ this.build(false, afterBuild);
810
+
811
+ },
812
+ shortcuts: function(e, cmd)
813
+ {
814
+ e.preventDefault();
815
+ this.execCommand(cmd, false);
816
+ },
817
+ keyup: function()
818
+ {
819
+ this.$editor.keyup($.proxy(function(e)
820
+ {
821
+ var key = e.keyCode || e.which;
822
+
823
+ if (this.browser('mozilla') && !this.pasteRunning)
824
+ {
825
+ this.saveSelection();
826
+ }
827
+
828
+ // callback as you type
829
+ if (typeof this.opts.keyupCallback === 'function')
830
+ {
831
+ this.opts.keyupCallback(this, e);
832
+ }
833
+
834
+ // if empty
835
+ if (key === 8 || key === 46)
836
+ {
837
+ this.observeImages();
838
+ return this.formatEmpty(e);
839
+ }
840
+
841
+ // new line p
842
+ if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.metaKey)
843
+ {
844
+ if (this.browser('webkit'))
845
+ {
846
+ this.formatNewLine(e);
847
+ }
848
+
849
+ // convert links
850
+ if (this.opts.convertLinks)
851
+ {
852
+ this.$editor.linkify();
853
+ }
854
+ }
855
+
856
+ this.syncCode();
857
+
858
+ }, this));
859
+ },
860
+ keydown: function()
861
+ {
862
+ this.$editor.keydown($.proxy(function(e)
863
+ {
864
+ var key = e.keyCode || e.which;
865
+ var parent = this.getParentNode();
866
+ var current = this.getCurrentNode();
867
+ var pre = false;
868
+ var ctrl = e.ctrlKey || e.metaKey;
869
+
870
+ if ((parent || current) && ($(parent).get(0).tagName === 'PRE' || $(current).get(0).tagName === 'PRE'))
871
+ {
872
+ pre = true;
873
+ }
874
+
875
+ // callback keydown
876
+ if (typeof this.opts.keydownCallback === 'function')
877
+ {
878
+ this.opts.keydownCallback(this, e);
879
+ }
880
+
881
+ if (ctrl && this.opts.shortcuts)
882
+ {
883
+ if (key === 90)
884
+ {
885
+ if (this.opts.buffer !== false)
886
+ {
887
+ e.preventDefault();
888
+ this.getBuffer();
889
+ }
890
+ else if (e.shiftKey)
891
+ {
892
+ this.shortcuts(e, 'redo'); // Ctrl + Shift + z
893
+ }
894
+ else
895
+ {
896
+ this.shortcuts(e, 'undo'); // Ctrl + z
897
+ }
898
+ }
899
+ else if (key === 77)
900
+ {
901
+ this.shortcuts(e, 'removeFormat'); // Ctrl + m
902
+ }
903
+ else if (key === 66)
904
+ {
905
+ this.shortcuts(e, 'bold'); // Ctrl + b
906
+ }
907
+ else if (key === 73)
908
+ {
909
+ this.shortcuts(e, 'italic'); // Ctrl + i
910
+ }
911
+ else if (key === 74)
912
+ {
913
+ this.shortcuts(e, 'insertunorderedlist'); // Ctrl + j
914
+ }
915
+ else if (key === 75)
916
+ {
917
+ this.shortcuts(e, 'insertorderedlist'); // Ctrl + k
918
+ }
919
+ else if (key === 76)
920
+ {
921
+ this.shortcuts(e, 'superscript'); // Ctrl + l
922
+ }
923
+ else if (key === 72)
924
+ {
925
+ this.shortcuts(e, 'subscript'); // Ctrl + h
926
+ }
927
+ }
928
+
929
+ // clear undo buffer
930
+ if (!ctrl && key !== 90)
931
+ {
932
+ this.opts.buffer = false;
933
+ }
934
+
935
+ // enter
936
+ if (pre === true && key === 13)
937
+ {
938
+ e.preventDefault();
939
+
940
+ var html = $(current).parent().text();
941
+ this.insertNodeAtCaret(this.document.createTextNode('\r\n'));
942
+ if (html.search(/\s$/) == -1)
943
+ {
944
+ this.insertNodeAtCaret(this.document.createTextNode('\r\n'));
945
+ }
946
+ this.syncCode();
947
+
948
+ return false;
949
+ }
950
+
951
+ // tab
952
+ if (this.opts.shortcuts && !e.shiftKey && key === 9)
953
+ {
954
+ if (pre === false)
955
+ {
956
+ this.shortcuts(e, 'indent'); // Tab
957
+ }
958
+ else
959
+ {
960
+ e.preventDefault();
961
+ this.insertNodeAtCaret(this.document.createTextNode('\t'));
962
+ this.syncCode();
963
+ return false;
964
+ }
965
+ }
966
+ else if (this.opts.shortcuts && e.shiftKey && key === 9 )
967
+ {
968
+ this.shortcuts(e, 'outdent'); // Shift + tab
969
+ }
970
+
971
+ // safari shift key + enter
972
+ if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1)
973
+ {
974
+ return this.safariShiftKeyEnter(e, key);
975
+ }
976
+ }, this));
977
+ },
978
+ build: function(mobile, whendone)
979
+ {
980
+ if (mobile !== true)
981
+ {
982
+ // container
983
+ this.$box = $('<div class="redactor_box"></div>');
984
+
985
+ // air box
986
+ if (this.opts.air)
987
+ {
988
+ this.air = $('<div class="redactor_air" style="display: none;"></div>');
989
+ }
990
+
991
+ this.$content = null;
992
+
993
+ function initFrame()
994
+ {
995
+ this.$editor = this.$content.contents().find("body").attr('contenteditable', true).attr('dir', this.opts.direction);
996
+
997
+ rdocument = this.document = this.$editor[0].ownerDocument;
998
+ rwindow = this.window = this.document.defaultView || window;
999
+
1000
+ if (this.opts.css !== false)
1001
+ {
1002
+ this.$content.contents().find('head').append('<link rel="stylesheet" href="' + this.opts.css + '" />');
1003
+ }
1004
+
1005
+ this.$editor.html(html);
1006
+
1007
+ if (whendone)
1008
+ {
1009
+ whendone.call(this);
1010
+ whendone = null;
1011
+ }
1012
+ }
1013
+
1014
+ // editor
1015
+ this.textareamode = true;
1016
+ if (this.$el.get(0).tagName === 'TEXTAREA')
1017
+ {
1018
+ if(this.opts.iframe)
1019
+ {
1020
+ var me = this;
1021
+ this.$content = $('<iframe style="width: 100%;" frameborder="0"></iframe>').load(function()
1022
+ {
1023
+ initFrame.call(me);
1024
+ });
1025
+ }
1026
+ else
1027
+ {
1028
+ this.$content = this.$editor = $('<div></div>');
1029
+ }
1030
+
1031
+ var classlist = this.$el.get(0).className.split(/\s+/);
1032
+ $.each(classlist, $.proxy(function(i,s)
1033
+ {
1034
+ this.$content.addClass('redactor_' + s);
1035
+ }, this));
1036
+ }
1037
+ else
1038
+ {
1039
+ this.textareamode = false;
1040
+ this.$content = this.$editor = this.$el;
1041
+ this.$el = $('<textarea name="' + this.$editor.attr('id') + '"></textarea>').css('height', this.height);
1042
+ }
1043
+
1044
+ if (this.$editor)
1045
+ {
1046
+ this.$editor.addClass('redactor_editor').attr('contenteditable', true).attr('dir', this.opts.direction);
1047
+ }
1048
+
1049
+ if (this.opts.tabindex !== false)
1050
+ {
1051
+ this.$content.attr('tabindex', this.opts.tabindex);
1052
+ }
1053
+
1054
+ if (this.opts.minHeight !== false)
1055
+ {
1056
+ this.$content.css('min-height', this.opts.minHeight + 'px');
1057
+ }
1058
+
1059
+ if (this.opts.wym === true)
1060
+ {
1061
+ this.$content.addClass('redactor_editor_wym');
1062
+ }
1063
+
1064
+ if (this.opts.autoresize === false)
1065
+ {
1066
+ this.$content.css('height', this.height);
1067
+ }
1068
+
1069
+ // hide textarea
1070
+ this.$el.hide();
1071
+
1072
+ // append box and frame
1073
+ var html = '';
1074
+ if (this.textareamode)
1075
+ {
1076
+ // get html
1077
+ html = this.$el.val();
1078
+ html = this.savePreCode(html);
1079
+
1080
+ this.$box.insertAfter(this.$el).append(this.$content).append(this.$el);
1081
+ }
1082
+ else
1083
+ {
1084
+ // get html
1085
+ html = this.$editor.html();
1086
+ html = this.savePreCode(html);
1087
+
1088
+ this.$box.insertAfter(this.$content).append(this.$el).append(this.$editor);
1089
+
1090
+ }
1091
+
1092
+ // conver newlines to p
1093
+ html = this.paragraphy(html);
1094
+
1095
+ // enable
1096
+ if (this.$editor)
1097
+ {
1098
+ this.$editor.html(html);
1099
+ }
1100
+
1101
+ if (this.textareamode === false)
1102
+ {
1103
+ this.syncCode();
1104
+ }
1105
+ }
1106
+ else
1107
+ {
1108
+ if (this.$el.get(0).tagName !== 'TEXTAREA')
1109
+ {
1110
+ var html = this.$el.val();
1111
+ var textarea = $('<textarea name="' + this.$editor.attr('id') + '"></textarea>').css('height', this.height).val(html);
1112
+ this.$el.hide();
1113
+ this.$el.after(textarea);
1114
+ }
1115
+ }
1116
+
1117
+ if (whendone && this.$editor)
1118
+ {
1119
+ whendone.call(this);
1120
+ }
1121
+
1122
+ },
1123
+ enableAir: function()
1124
+ {
1125
+ if (this.opts.air === false)
1126
+ {
1127
+ return false;
1128
+ }
1129
+
1130
+ this.air.hide();
1131
+
1132
+ this.$editor.bind('textselect', $.proxy(function(e)
1133
+ {
1134
+ this.showAir(e);
1135
+
1136
+ }, this));
1137
+
1138
+ this.$editor.bind('textunselect', $.proxy(function()
1139
+ {
1140
+ this.air.hide();
1141
+
1142
+ }, this));
1143
+
1144
+ },
1145
+ showAir: function(e)
1146
+ {
1147
+ $('.redactor_air').hide();
1148
+
1149
+ var width = this.air.innerWidth();
1150
+ var left = e.clientX;
1151
+
1152
+ if ($(this.document).width() < (left + width))
1153
+ {
1154
+ left = left - width;
1155
+ }
1156
+
1157
+ var top = e.clientY + $(document).scrollTop() + 14;
1158
+ if (this.opts.iframe === true)
1159
+ {
1160
+ top = top + this.$box.position().top;
1161
+ left = left + this.$box.position().left;
1162
+ }
1163
+
1164
+ this.air.css({ left: left + 'px', top: top + 'px' }).show();
1165
+ },
1166
+ syncCode: function()
1167
+ {
1168
+ this.$el.val(this.$editor.html());
1169
+ },
1170
+
1171
+ // API functions
1172
+ setCode: function(html)
1173
+ {
1174
+ html = this.stripTags(html);
1175
+ this.$editor.html(html).focus();
1176
+
1177
+ this.syncCode();
1178
+ },
1179
+ getCode: function()
1180
+ {
1181
+ var html = '';
1182
+ if (this.opts.visual)
1183
+ {
1184
+ html = this.$editor.html()
1185
+ }
1186
+ else
1187
+ {
1188
+ html = this.$el.val();
1189
+ }
1190
+
1191
+ return this.stripTags(html);
1192
+ },
1193
+ insertHtml: function(html)
1194
+ {
1195
+ this.$editor.focus();
1196
+ this.pasteHtmlAtCaret(html);
1197
+ this.observeImages();
1198
+ this.syncCode();
1199
+ },
1200
+
1201
+ pasteHtmlAtCaret: function (html)
1202
+ {
1203
+ var sel, range;
1204
+ if (this.document.getSelection)
1205
+ {
1206
+ sel = this.window.getSelection();
1207
+ if (sel.getRangeAt && sel.rangeCount)
1208
+ {
1209
+ range = sel.getRangeAt(0);
1210
+ range.deleteContents();
1211
+ var el = this.document.createElement("div");
1212
+ el.innerHTML = html;
1213
+ var frag = this.document.createDocumentFragment(), node, lastNode;
1214
+ while (node = el.firstChild)
1215
+ {
1216
+ lastNode = frag.appendChild(node);
1217
+ }
1218
+ range.insertNode(frag);
1219
+
1220
+ if (lastNode)
1221
+ {
1222
+ range = range.cloneRange();
1223
+ range.setStartAfter(lastNode);
1224
+ range.collapse(true);
1225
+ sel.removeAllRanges();
1226
+ sel.addRange(range);
1227
+ }
1228
+ }
1229
+ }
1230
+ else if (this.document.selection && this.document.selection.type != "Control")
1231
+ {
1232
+ this.document.selection.createRange().pasteHTML(html);
1233
+ }
1234
+ },
1235
+
1236
+ destroy: function()
1237
+ {
1238
+ var html = this.getCode();
1239
+
1240
+ if (this.textareamode)
1241
+ {
1242
+ this.$box.after(this.$el);
1243
+ this.$box.remove();
1244
+ this.$el.height(this.height).val(html).show();
1245
+ }
1246
+ else
1247
+ {
1248
+ this.$box.after(this.$editor);
1249
+ this.$box.remove();
1250
+ this.$editor.removeClass('redactor_editor').removeClass('redactor_editor_wym').attr('contenteditable', false).html(html).show();
1251
+ }
1252
+
1253
+ if (this.opts.toolbarExternal)
1254
+ {
1255
+ $(this.opts.toolbarExternal).empty();
1256
+ }
1257
+
1258
+ $('.redactor_air').remove();
1259
+
1260
+ for (var i = 0; i < this.dropdowns.length; i++)
1261
+ {
1262
+ this.dropdowns[i].remove();
1263
+ delete(this.dropdowns[i]);
1264
+ }
1265
+
1266
+ if (this.opts.autosave !== false)
1267
+ {
1268
+ clearInterval(this.autosaveInterval);
1269
+ }
1270
+
1271
+ },
1272
+ // end API functions
1273
+
1274
+ // OBSERVERS
1275
+ observeFormatting: function()
1276
+ {
1277
+ var parent = this.getCurrentNode();
1278
+
1279
+ this.inactiveAllButtons();
1280
+
1281
+ $.each(this.opts.activeButtonsStates, $.proxy(function(i,s)
1282
+ {
1283
+ if ($(parent).closest(i,this.$editor.get()[0]).length != 0)
1284
+ {
1285
+ this.setBtnActive(s);
1286
+ }
1287
+
1288
+ }, this));
1289
+
1290
+ var tag = $(parent).closest(['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'td']);
1291
+
1292
+ if (typeof tag[0] !== 'undefined' && typeof tag[0].elem !== 'undefined' && $(tag[0].elem).size() != 0)
1293
+ {
1294
+ var align = $(tag[0].elem).css('text-align');
1295
+
1296
+ switch (align)
1297
+ {
1298
+ case 'right':
1299
+ this.setBtnActive('alignright');
1300
+ break;
1301
+ case 'center':
1302
+ this.setBtnActive('aligncenter');
1303
+ break;
1304
+ case 'justify':
1305
+ this.setBtnActive('justify');
1306
+ break;
1307
+ default:
1308
+ this.setBtnActive('alignleft');
1309
+ break;
1310
+ }
1311
+ }
1312
+ },
1313
+ observeImages: function()
1314
+ {
1315
+ if (this.opts.observeImages === false)
1316
+ {
1317
+ return false;
1318
+ }
1319
+
1320
+ this.$editor.find('img').each($.proxy(function(i,s)
1321
+ {
1322
+ if (this.browser('msie'))
1323
+ {
1324
+ $(s).attr('unselectable', 'on');
1325
+ }
1326
+
1327
+ this.resizeImage(s);
1328
+
1329
+ }, this));
1330
+
1331
+ },
1332
+ observeTables: function()
1333
+ {
1334
+ this.$editor.find('table').click($.proxy(this.tableObserver, this));
1335
+ },
1336
+ observeScroll: function()
1337
+ {
1338
+ var scrolltop = $(this.document).scrollTop();
1339
+ var boxtop = this.$box.offset().top;
1340
+ var left = 0;
1341
+
1342
+ if (scrolltop > boxtop)
1343
+ {
1344
+ var width = '100%';
1345
+ if (this.opts.fixedBox)
1346
+ {
1347
+ left = this.$box.offset().left;
1348
+ width = this.$box.innerWidth();
1349
+ }
1350
+
1351
+ this.fixed = true;
1352
+ this.$toolbar.css({ position: 'fixed', width: width, zIndex: 1005, top: this.opts.fixedTop + 'px', left: left });
1353
+ }
1354
+ else
1355
+ {
1356
+ this.fixed = false;
1357
+ this.$toolbar.css({ position: 'relative', width: 'auto', zIndex: 1, top: 0, left: left });
1358
+ }
1359
+ },
1360
+
1361
+ // BUFFER
1362
+ setBuffer: function()
1363
+ {
1364
+ this.saveSelection();
1365
+ this.opts.buffer = this.$editor.html();
1366
+ },
1367
+ getBuffer: function()
1368
+ {
1369
+ if (this.opts.buffer === false)
1370
+ {
1371
+ return false;
1372
+ }
1373
+
1374
+ this.$editor.html(this.opts.buffer);
1375
+
1376
+ if (!this.browser('msie'))
1377
+ {
1378
+ this.restoreSelection();
1379
+ }
1380
+
1381
+ this.opts.buffer = false;
1382
+ },
1383
+
1384
+
1385
+
1386
+ // EXECCOMMAND
1387
+ execCommand: function(cmd, param)
1388
+ {
1389
+ if (this.opts.visual == false)
1390
+ {
1391
+ this.$el.focus();
1392
+ return false;
1393
+ }
1394
+
1395
+ try
1396
+ {
1397
+
1398
+ var parent;
1399
+
1400
+ if (cmd === 'inserthtml')
1401
+ {
1402
+ if (this.browser('msie'))
1403
+ {
1404
+ this.$editor.focus();
1405
+ this.document.selection.createRange().pasteHTML(param);
1406
+ }
1407
+ else
1408
+ {
1409
+ this.pasteHtmlAtCaret(param);
1410
+ //this.execRun(cmd, param);
1411
+ }
1412
+
1413
+ this.observeImages();
1414
+ }
1415
+ else if (cmd === 'unlink')
1416
+ {
1417
+ parent = this.getParentNode();
1418
+ if ($(parent).get(0).tagName === 'A')
1419
+ {
1420
+ $(parent).replaceWith($(parent).text());
1421
+ }
1422
+ else
1423
+ {
1424
+ this.execRun(cmd, param);
1425
+ }
1426
+ }
1427
+ else if (cmd === 'JustifyLeft' || cmd === 'JustifyCenter' || cmd === 'JustifyRight' || cmd === 'JustifyFull')
1428
+ {
1429
+ parent = this.getCurrentNode();
1430
+ var tag = $(parent).get(0).tagName;
1431
+
1432
+ if (this.opts.iframe === false && $(parent).parents('.redactor_editor').size() == 0)
1433
+ {
1434
+ return false;
1435
+ }
1436
+
1437
+ var tagsArray = ['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'TD'];
1438
+ if ($.inArray(tag, tagsArray) != -1)
1439
+ {
1440
+ var align = false;
1441
+
1442
+ if (cmd === 'JustifyCenter')
1443
+ {
1444
+ align = 'center';
1445
+ }
1446
+ else if (cmd === 'JustifyRight')
1447
+ {
1448
+ align = 'right';
1449
+ }
1450
+ else if (cmd === 'JustifyFull')
1451
+ {
1452
+ align = 'justify';
1453
+ }
1454
+
1455
+ if (align === false)
1456
+ {
1457
+ $(parent).css('text-align', '');
1458
+ }
1459
+ else
1460
+ {
1461
+ $(parent).css('text-align', align);
1462
+ }
1463
+ }
1464
+ else
1465
+ {
1466
+ this.execRun(cmd, param);
1467
+ }
1468
+ }
1469
+ else if (cmd === 'formatblock' && param === 'blockquote')
1470
+ {
1471
+ parent = this.getCurrentNode();
1472
+ if ($(parent).get(0).tagName === 'BLOCKQUOTE')
1473
+ {
1474
+ if (this.browser('msie'))
1475
+ {
1476
+ var node = $('<p>' + $(parent).html() + '</p>');
1477
+ $(parent).replaceWith(node);
1478
+ }
1479
+ else
1480
+ {
1481
+ this.execRun(cmd, 'p');
1482
+ }
1483
+ }
1484
+ else if ($(parent).get(0).tagName === 'P')
1485
+ {
1486
+ var parent2 = $(parent).parent();
1487
+ if ($(parent2).get(0).tagName === 'BLOCKQUOTE')
1488
+ {
1489
+ var node = $('<p>' + $(parent).html() + '</p>');
1490
+ $(parent2).replaceWith(node);
1491
+ this.setSelection(node[0], 0, node[0], 0);
1492
+ }
1493
+ else
1494
+ {
1495
+ if (this.browser('msie'))
1496
+ {
1497
+ var node = $('<blockquote>' + $(parent).html() + '</blockquote>');
1498
+ $(parent).replaceWith(node);
1499
+ }
1500
+ else
1501
+ {
1502
+ this.execRun(cmd, param);
1503
+ }
1504
+ }
1505
+ }
1506
+ else
1507
+ {
1508
+ this.execRun(cmd, param);
1509
+ }
1510
+ }
1511
+ else if (cmd === 'formatblock' && (param === 'pre' || param === 'p'))
1512
+ {
1513
+ parent = this.getParentNode();
1514
+
1515
+ if ($(parent).get(0).tagName === 'PRE')
1516
+ {
1517
+ $(parent).replaceWith('<p>' + this.encodeEntities($(parent).text()) + '</p>');
1518
+ }
1519
+ else
1520
+ {
1521
+ this.execRun(cmd, param);
1522
+ }
1523
+ }
1524
+ else
1525
+ {
1526
+ if (cmd === 'inserthorizontalrule' && this.browser('msie'))
1527
+ {
1528
+ this.$editor.focus();
1529
+ }
1530
+
1531
+ if (cmd === 'formatblock' && this.browser('mozilla'))
1532
+ {
1533
+ this.$editor.focus();
1534
+ }
1535
+
1536
+ this.execRun(cmd, param);
1537
+ }
1538
+
1539
+ if (cmd === 'inserthorizontalrule')
1540
+ {
1541
+ this.$editor.find('hr').removeAttr('id');
1542
+ }
1543
+
1544
+ this.syncCode();
1545
+
1546
+ if (this.oldIE())
1547
+ {
1548
+ this.$editor.focus();
1549
+ }
1550
+
1551
+ if (typeof this.opts.execCommandCallback === 'function')
1552
+ {
1553
+ this.opts.execCommandCallback(this, cmd);
1554
+ }
1555
+
1556
+ if (this.opts.air)
1557
+ {
1558
+ this.air.hide();
1559
+ }
1560
+ }
1561
+ catch (e) { }
1562
+ },
1563
+ execRun: function(cmd, param)
1564
+ {
1565
+ if (cmd === 'formatblock' && this.browser('msie'))
1566
+ {
1567
+ param = '<' + param + '>';
1568
+ }
1569
+
1570
+ this.document.execCommand(cmd, false, param);
1571
+ },
1572
+
1573
+ // FORMAT NEW LINE
1574
+ formatNewLine: function(e)
1575
+ {
1576
+ var parent = this.getParentNode();
1577
+
1578
+ if (parent.nodeName === 'DIV' && parent.className === 'redactor_editor')
1579
+ {
1580
+ var element = $(this.getCurrentNode());
1581
+
1582
+ if (element.get(0).tagName === 'DIV' && (element.html() === '' || element.html() === '<br>'))
1583
+ {
1584
+ var newElement = $('<p>').append(element.clone().get(0).childNodes);
1585
+ element.replaceWith(newElement);
1586
+ newElement.html('<br />');
1587
+ this.setSelection(newElement[0], 0, newElement[0], 0);
1588
+ }
1589
+ }
1590
+ },
1591
+
1592
+ // SAFARI SHIFT KEY + ENTER
1593
+ safariShiftKeyEnter: function(e, key)
1594
+ {
1595
+ if (e.shiftKey && key === 13)
1596
+ {
1597
+ e.preventDefault();
1598
+ this.insertNodeAtCaret($('<span><br /></span>').get(0));
1599
+ this.syncCode();
1600
+ return false;
1601
+ }
1602
+ else
1603
+ {
1604
+ return true;
1605
+ }
1606
+ },
1607
+
1608
+ // FORMAT EMPTY
1609
+ formatEmpty: function(e)
1610
+ {
1611
+ var html = $.trim(this.$editor.html());
1612
+
1613
+ if (this.browser('mozilla'))
1614
+ {
1615
+ html = html.replace(/<br>/i, '');
1616
+ }
1617
+
1618
+ var thtml = html.replace(/<(?:.|\n)*?>/gm, '');
1619
+
1620
+ if (html === '' || thtml === '')
1621
+ {
1622
+ e.preventDefault();
1623
+
1624
+ var node = $(this.opts.emptyHtml).get(0);
1625
+ this.$editor.html(node);
1626
+ this.setSelection(node, 0, node, 0);
1627
+
1628
+ this.syncCode();
1629
+ return false;
1630
+ }
1631
+ else
1632
+ {
1633
+ this.syncCode();
1634
+ }
1635
+ },
1636
+
1637
+ // PARAGRAPHY
1638
+ paragraphy: function (str)
1639
+ {
1640
+ str = $.trim(str);
1641
+ if (str === '' || str === '<p></p>')
1642
+ {
1643
+ return this.opts.emptyHtml;
1644
+ }
1645
+
1646
+ // convert div to p
1647
+ if (this.opts.convertDivs)
1648
+ {
1649
+ str = str.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>');
1650
+ }
1651
+
1652
+ // inner functions
1653
+ var X = function(x, a, b) { return x.replace(new RegExp(a, 'g'), b); };
1654
+ var R = function(a, b) { return X(str, a, b); };
1655
+
1656
+ // block elements
1657
+ 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])';
1658
+
1659
+ //str = '<p>' + str;
1660
+ str += '\n';
1661
+
1662
+ R('<br />\\s*<br />', '\n\n');
1663
+ R('(<' + blocks + '[^>]*>)', '\n$1');
1664
+ R('(</' + blocks + '>)', '$1\n\n');
1665
+ R('\r\n|\r', '\n'); // newlines
1666
+ R('\n\n+', '\n\n'); // remove duplicates
1667
+ R('\n?((.|\n)+?)$', '<p>$1</p>\n'); // including one at the end
1668
+ R('<p>\\s*?</p>', ''); // remove empty p
1669
+ R('<p>(<div[^>]*>\\s*)', '$1<p>');
1670
+ R('<p>([^<]+)\\s*?(</(div|address|form)[^>]*>)', '<p>$1</p>$2');
1671
+ R('<p>\\s*(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
1672
+ R('<p>(<li.+?)</p>', '$1');
1673
+ R('<p>\\s*(</?' + blocks + '[^>]*>)', '$1');
1674
+ R('(</?' + blocks + '[^>]*>)\\s*</p>', '$1');
1675
+ R('(</?' + blocks + '[^>]*>)\\s*<br />', '$1');
1676
+ R('<br />(\\s*</?(p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', '$1');
1677
+
1678
+ // pre
1679
+ if (str.indexOf('<pre') != -1)
1680
+ {
1681
+ R('(<pre(.|\n)*?>)((.|\n)*?)</pre>', function(m0, m1, m2, m3)
1682
+ {
1683
+ return X(m1, '\\\\([\'\"\\\\])', '$1') + X(X(X(m3, '<p>', '\n'), '</p>|<br />', ''), '\\\\([\'\"\\\\])', '$1') + '</pre>';
1684
+ });
1685
+ }
1686
+
1687
+ return R('\n</p>$', '</p>');
1688
+ },
1689
+
1690
+ // REMOVE TAGS
1691
+ stripTags: function(html)
1692
+ {
1693
+ var allowed = this.opts.allowedTags;
1694
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
1695
+ return html.replace(tags, function ($0, $1)
1696
+ {
1697
+ return $.inArray($1.toLowerCase(), allowed) > '-1' ? $0 : '';
1698
+ });
1699
+ },
1700
+
1701
+
1702
+ savePreCode: function(html)
1703
+ {
1704
+ var pre = html.match(/<pre(.*?)>([\w\W]*?)<\/pre>/gi);
1705
+ if (pre !== null)
1706
+ {
1707
+ $.each(pre, $.proxy(function(i,s)
1708
+ {
1709
+ var arr = s.match(/<pre(.*?)>([\w\W]*?)<\/pre>/i);
1710
+ arr[2] = this.encodeEntities(arr[2]);
1711
+ html = html.replace(s, '<pre' + arr[1] + '>' + arr[2] + '</pre>');
1712
+ }, this));
1713
+ }
1714
+
1715
+ return html;
1716
+ },
1717
+ encodeEntities: function(str)
1718
+ {
1719
+ str = String(str).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
1720
+ return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1721
+ },
1722
+ cleanupPre: function(s)
1723
+ {
1724
+ s = s.replace(/<br>/gi, '\n');
1725
+ s = s.replace(/<\/p>/gi, '\n');
1726
+ s = s.replace(/<\/div>/gi, '\n');
1727
+
1728
+ var tmp = this.document.createElement("div");
1729
+ tmp.innerHTML = s;
1730
+ return tmp.textContent||tmp.innerText;
1731
+
1732
+ },
1733
+
1734
+
1735
+ // PASTE CLEANUP
1736
+ pasteCleanUp: function(html)
1737
+ {
1738
+ var parent = this.getParentNode();
1739
+
1740
+ // clean up pre
1741
+ if ($(parent).get(0).tagName === 'PRE')
1742
+ {
1743
+ html = this.cleanupPre(html);
1744
+ this.pasteCleanUpInsert(html);
1745
+ return true;
1746
+ }
1747
+
1748
+ // remove comments and php tags
1749
+ html = html.replace(/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi, '');
1750
+
1751
+ // remove nbsp
1752
+ html = html.replace(/(&nbsp;){2,}/gi, '&nbsp;');
1753
+
1754
+ // remove google docs marker
1755
+ html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2");
1756
+
1757
+ // strip tags
1758
+ html = this.stripTags(html);
1759
+
1760
+ // prevert
1761
+ html = html.replace(/<td><\/td>/gi, '[td]');
1762
+ html = html.replace(/<td>&nbsp;<\/td>/gi, '[td]');
1763
+ html = html.replace(/<td><br><\/td>/gi, '[td]');
1764
+ html = html.replace(/<a(.*?)href="(.*?)"(.*?)>([\w\W]*?)<\/a>/gi, '[a href="$2"]$4[/a]');
1765
+ html = html.replace(/<iframe(.*?)>([\w\W]*?)<\/iframe>/gi, '[iframe$1]$2[/iframe]');
1766
+ html = html.replace(/<video(.*?)>([\w\W]*?)<\/video>/gi, '[video$1]$2[/video]');
1767
+ html = html.replace(/<audio(.*?)>([\w\W]*?)<\/audio>/gi, '[audio$1]$2[/audio]');
1768
+ html = html.replace(/<embed(.*?)>([\w\W]*?)<\/embed>/gi, '[embed$1]$2[/embed]');
1769
+ html = html.replace(/<object(.*?)>([\w\W]*?)<\/object>/gi, '[object$1]$2[/object]');
1770
+ html = html.replace(/<param(.*?)>/gi, '[param$1]');
1771
+ html = html.replace(/<img(.*?)style="(.*?)"(.*?)>/gi, '[img$1$3]');
1772
+
1773
+ // remove attributes
1774
+ html = html.replace(/<(\w+)([\w\W]*?)>/gi, '<$1>');
1775
+
1776
+ // remove empty
1777
+ html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*|&nbsp;|<br>)<\/[^>]+>/gi, '');
1778
+ html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*|&nbsp;|<br>)<\/[^>]+>/gi, '');
1779
+
1780
+ // revert
1781
+ html = html.replace(/\[td\]/gi, '<td>&nbsp;</td>');
1782
+ html = html.replace(/\[a href="(.*?)"\]([\w\W]*?)\[\/a\]/gi, '<a href="$1">$2</a>');
1783
+ html = html.replace(/\[iframe(.*?)\]([\w\W]*?)\[\/iframe\]/gi, '<iframe$1>$2</iframe>');
1784
+ html = html.replace(/\[video(.*?)\]([\w\W]*?)\[\/video\]/gi, '<video$1>$2</video>');
1785
+ html = html.replace(/\[audio(.*?)\]([\w\W]*?)\[\/audio\]/gi, '<audio$1>$2</audio>');
1786
+ html = html.replace(/\[embed(.*?)\]([\w\W]*?)\[\/embed\]/gi, '<embed$1>$2</embed>');
1787
+ html = html.replace(/\[object(.*?)\]([\w\W]*?)\[\/object\]/gi, '<object$1>$2</object>');
1788
+ html = html.replace(/\[param(.*?)\]/gi, '<param$1>');
1789
+ html = html.replace(/\[img(.*?)\]/gi, '<img$1>');
1790
+
1791
+
1792
+ // convert div to p
1793
+ if (this.opts.convertDivs)
1794
+ {
1795
+ html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>');
1796
+ }
1797
+
1798
+ // remove span
1799
+ html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');
1800
+
1801
+ html = html.replace(/\n{3,}/gi, '\n');
1802
+
1803
+ // remove dirty p
1804
+ html = html.replace(/<p><p>/gi, '<p>');
1805
+ html = html.replace(/<\/p><\/p>/gi, '</p>');
1806
+
1807
+ // FF fix
1808
+ if (this.browser('mozilla'))
1809
+ {
1810
+ html = html.replace(/<br>$/gi, '');
1811
+ }
1812
+
1813
+ this.pasteCleanUpInsert(html);
1814
+
1815
+ },
1816
+
1817
+ pasteCleanUpInsert: function(html)
1818
+ {
1819
+ this.execCommand('inserthtml', html);
1820
+
1821
+ if (this.opts.autoresize === true)
1822
+ {
1823
+ $(this.document.body).scrollTop(this.saveScroll);
1824
+ }
1825
+ else
1826
+ {
1827
+ this.$editor.scrollTop(this.saveScroll);
1828
+ }
1829
+ },
1830
+
1831
+
1832
+ // TEXTAREA CODE FORMATTING
1833
+ formattingRemove: function(html)
1834
+ {
1835
+ // save pre
1836
+ var prebuffer = [];
1837
+ var pre = html.match(/<pre(.*?)>([\w\W]*?)<\/pre>/gi);
1838
+ if (pre !== null)
1839
+ {
1840
+ $.each(pre, function(i,s)
1841
+ {
1842
+ html = html.replace(s, 'prebuffer_' + i);
1843
+ prebuffer.push(s);
1844
+ });
1845
+ }
1846
+
1847
+ html = html.replace(/\s{2,}/g, ' ');
1848
+ html = html.replace(/\n/g, ' ');
1849
+ html = html.replace(/[\t]*/g, '');
1850
+ html = html.replace(/\n\s*\n/g, "\n");
1851
+ html = html.replace(/^[\s\n]*/g, '');
1852
+ html = html.replace(/[\s\n]*$/g, '');
1853
+ html = html.replace(/>\s+</g, '><');
1854
+
1855
+ if (prebuffer)
1856
+ {
1857
+ $.each(prebuffer, function(i,s)
1858
+ {
1859
+ html = html.replace('prebuffer_' + i, s);
1860
+ });
1861
+
1862
+ prebuffer = [];
1863
+ }
1864
+
1865
+ return html;
1866
+ },
1867
+ formattingIndenting: function(html)
1868
+ {
1869
+ html = html.replace(/<li/g, "\t<li");
1870
+ html = html.replace(/<tr/g, "\t<tr");
1871
+ html = html.replace(/<td/g, "\t\t<td");
1872
+ html = html.replace(/<\/tr>/g, "\t</tr>");
1873
+
1874
+ return html;
1875
+ },
1876
+ formattingEmptyTags: function(html)
1877
+ {
1878
+ 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>"];
1879
+ for (var i = 0; i < etags.length; ++i)
1880
+ {
1881
+ var bbb = etags[i];
1882
+ html = html.replace(new RegExp(bbb,'gi'), "");
1883
+ }
1884
+
1885
+ return html;
1886
+ },
1887
+ formattingAddBefore: function(html)
1888
+ {
1889
+ var lb = '\r\n';
1890
+ 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"];
1891
+ for (var i = 0; i < btags.length; ++i)
1892
+ {
1893
+ var eee = btags[i];
1894
+ html = html.replace(new RegExp(eee,'gi'),lb+eee);
1895
+ }
1896
+
1897
+ return html;
1898
+ },
1899
+ formattingAddAfter: function(html)
1900
+ {
1901
+ var lb = '\r\n';
1902
+ 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>'];
1903
+ for (var i = 0; i < atags.length; ++i)
1904
+ {
1905
+ var aaa = atags[i];
1906
+ html = html.replace(new RegExp(aaa,'gi'),aaa+lb);
1907
+ }
1908
+
1909
+ return html;
1910
+ },
1911
+ formatting: function(html)
1912
+ {
1913
+ html = this.formattingRemove(html);
1914
+
1915
+ // empty tags
1916
+ html = this.formattingEmptyTags(html);
1917
+
1918
+ // add formatting before
1919
+ html = this.formattingAddBefore(html);
1920
+
1921
+ // add formatting after
1922
+ html = this.formattingAddAfter(html);
1923
+
1924
+ // indenting
1925
+ html = this.formattingIndenting(html);
1926
+
1927
+ return html;
1928
+ },
1929
+
1930
+ // TOGGLE
1931
+ toggle: function()
1932
+ {
1933
+ var html;
1934
+
1935
+ if (this.opts.visual)
1936
+ {
1937
+ var height = this.$editor.innerHeight();
1938
+
1939
+ this.$editor.hide();
1940
+ this.$content.hide();
1941
+
1942
+ html = this.$editor.html();
1943
+ //html = $.trim(this.formatting(html));
1944
+
1945
+ this.$el.height(height).val(html).show().focus();
1946
+
1947
+ this.setBtnActive('html');
1948
+ this.opts.visual = false;
1949
+ }
1950
+ else
1951
+ {
1952
+ this.$el.hide();
1953
+ var html = this.$el.val();
1954
+
1955
+ //html = this.savePreCode(html);
1956
+
1957
+ // clean up
1958
+ //html = this.stripTags(html);
1959
+
1960
+ // set code
1961
+ this.$editor.html(html).show();
1962
+ this.$content.show();
1963
+
1964
+ if (this.$editor.html() === '')
1965
+ {
1966
+ this.setCode(this.opts.emptyHtml);
1967
+ }
1968
+
1969
+ this.$editor.focus();
1970
+
1971
+ this.setBtnInactive('html');
1972
+ this.opts.visual = true;
1973
+
1974
+ this.observeImages();
1975
+ this.observeTables();
1976
+ }
1977
+ },
1978
+
1979
+ // AUTOSAVE
1980
+ autoSave: function()
1981
+ {
1982
+ this.autosaveInterval = setInterval($.proxy(function()
1983
+ {
1984
+ $.ajax({
1985
+ url: this.opts.autosave,
1986
+ type: 'post',
1987
+ data: this.$el.attr('name') + '=' + escape(encodeURIComponent(this.getCode())),
1988
+ success: $.proxy(function(data)
1989
+ {
1990
+ // callback
1991
+ if (typeof this.opts.autosaveCallback === 'function')
1992
+ {
1993
+ this.opts.autosaveCallback(data, this);
1994
+ }
1995
+
1996
+ }, this)
1997
+ });
1998
+
1999
+
2000
+ }, this), this.opts.interval*1000);
2001
+ },
2002
+
2003
+ // TOOLBAR
2004
+ buildToolbar: function()
2005
+ {
2006
+ if (this.opts.toolbar === false)
2007
+ {
2008
+ return false;
2009
+ }
2010
+
2011
+ this.$toolbar = $('<ul>').addClass('redactor_toolbar');
2012
+
2013
+ if (this.opts.air)
2014
+ {
2015
+ $(this.air).append(this.$toolbar);
2016
+ $('body').append(this.air);
2017
+ }
2018
+ else
2019
+ {
2020
+ if (this.opts.toolbarExternal === false)
2021
+ {
2022
+ this.$box.prepend(this.$toolbar);
2023
+ }
2024
+ else
2025
+ {
2026
+ $(this.opts.toolbarExternal).html(this.$toolbar);
2027
+ }
2028
+ }
2029
+
2030
+ $.each(this.opts.buttons, $.proxy(function(i,key)
2031
+ {
2032
+
2033
+ if (key !== '|' && typeof this.opts.toolbar[key] !== 'undefined')
2034
+ {
2035
+ var s = this.opts.toolbar[key];
2036
+
2037
+ if (this.opts.fileUpload === false && key === 'file')
2038
+ {
2039
+ return true;
2040
+ }
2041
+
2042
+ this.$toolbar.append($('<li>').append(this.buildButton(key, s)));
2043
+ }
2044
+
2045
+
2046
+ if (key === '|')
2047
+ {
2048
+ this.$toolbar.append($('<li class="redactor_separator"></li>'));
2049
+ }
2050
+
2051
+ }, this));
2052
+
2053
+ },
2054
+ buildButton: function(key, s)
2055
+ {
2056
+ var button = $('<a href="javascript:void(null);" title="' + s.title + '" class="redactor_btn_' + key + '"></a>');
2057
+
2058
+ if (typeof s.func === 'undefined')
2059
+ {
2060
+ button.click($.proxy(function()
2061
+ {
2062
+ if ($.inArray(key, this.opts.activeButtons) != -1)
2063
+ {
2064
+ this.inactiveAllButtons();
2065
+ this.setBtnActive(key);
2066
+ }
2067
+
2068
+ if (this.browser('mozilla'))
2069
+ {
2070
+ this.$editor.focus();
2071
+ //this.restoreSelection();
2072
+ }
2073
+
2074
+ this.execCommand(s.exec, key);
2075
+
2076
+ }, this));
2077
+ }
2078
+ else if (s.func !== 'show')
2079
+ {
2080
+ button.click($.proxy(function(e) {
2081
+
2082
+ this[s.func](e);
2083
+
2084
+ }, this));
2085
+ }
2086
+
2087
+ if (typeof s.callback !== 'undefined' && s.callback !== false)
2088
+ {
2089
+ button.click($.proxy(function(e) { s.callback(this, e, key); }, this));
2090
+ }
2091
+
2092
+ // dropdown
2093
+ if (key === 'backcolor' || key === 'fontcolor' || typeof(s.dropdown) !== 'undefined')
2094
+ {
2095
+ var dropdown = $('<div class="redactor_dropdown" style="display: none;">');
2096
+
2097
+ if (key === 'backcolor' || key === 'fontcolor')
2098
+ {
2099
+ dropdown = this.buildColorPicker(dropdown, key);
2100
+ }
2101
+ else
2102
+ {
2103
+ dropdown = this.buildDropdown(dropdown, s.dropdown);
2104
+ }
2105
+
2106
+ this.dropdowns.push(dropdown.appendTo($(document.body)));
2107
+
2108
+ // observing dropdown
2109
+ this.hdlShowDropDown = $.proxy(function(e) { this.showDropDown(e, dropdown, key); }, this);
2110
+
2111
+ button.click(this.hdlShowDropDown);
2112
+ }
2113
+
2114
+ return button;
2115
+ },
2116
+ buildDropdown: function(dropdown, obj)
2117
+ {
2118
+ $.each(obj, $.proxy(
2119
+ function (x, d)
2120
+ {
2121
+ if (typeof(d.className) === 'undefined')
2122
+ {
2123
+ d.className = '';
2124
+ }
2125
+
2126
+ var drop_a;
2127
+ if (typeof d.name !== 'undefined' && d.name === 'separator')
2128
+ {
2129
+ drop_a = $('<a class="redactor_separator_drop">');
2130
+ }
2131
+ else
2132
+ {
2133
+ drop_a = $('<a href="javascript:void(null);" class="' + d.className + '">' + d.title + '</a>');
2134
+
2135
+ if (typeof(d.callback) === 'function')
2136
+ {
2137
+ $(drop_a).click($.proxy(function(e) { d.callback(this, e, x); }, this));
2138
+ }
2139
+ else if (typeof(d.func) === 'undefined')
2140
+ {
2141
+ $(drop_a).click($.proxy(function() { this.execCommand(d.exec, x); }, this));
2142
+ }
2143
+ else
2144
+ {
2145
+ $(drop_a).click($.proxy(function(e) { this[d.func](e); }, this));
2146
+ }
2147
+ }
2148
+
2149
+ $(dropdown).append(drop_a);
2150
+
2151
+ }, this)
2152
+ );
2153
+
2154
+ return dropdown;
2155
+
2156
+ },
2157
+ buildColorPicker: function(dropdown, key)
2158
+ {
2159
+ var mode;
2160
+ if (key === 'backcolor')
2161
+ {
2162
+ if (this.browser('msie'))
2163
+ {
2164
+ mode = 'BackColor';
2165
+ }
2166
+ else
2167
+ {
2168
+ mode = 'hilitecolor';
2169
+ }
2170
+ }
2171
+ else
2172
+ {
2173
+ mode = 'forecolor';
2174
+ }
2175
+
2176
+ $(dropdown).width(210);
2177
+
2178
+ var len = this.opts.colors.length;
2179
+ for (var i = 0; i < len; ++i)
2180
+ {
2181
+ var color = this.opts.colors[i];
2182
+
2183
+ var swatch = $('<a rel="' + color + '" href="javascript:void(null);" class="redactor_color_link"></a>').css({ 'backgroundColor': color });
2184
+ $(dropdown).append(swatch);
2185
+
2186
+ var _self = this;
2187
+ $(swatch).click(function()
2188
+ {
2189
+ _self.execCommand(mode, $(this).attr('rel'));
2190
+
2191
+ if (mode === 'forecolor')
2192
+ {
2193
+ _self.$editor.find('font').replaceWith(function() {
2194
+
2195
+ return $('<span style="color: ' + $(this).attr('color') + ';">' + $(this).html() + '</span>');
2196
+
2197
+ });
2198
+ }
2199
+
2200
+ if (_self.browser('msie') && mode === 'BackColor')
2201
+ {
2202
+ _self.$editor.find('font').replaceWith(function() {
2203
+
2204
+ return $('<span style="' + $(this).attr('style') + '">' + $(this).html() + '</span>');
2205
+
2206
+ });
2207
+ }
2208
+
2209
+ });
2210
+ }
2211
+
2212
+ var elnone = $('<a href="javascript:void(null);" class="redactor_color_none"></a>').html(RLANG.none);
2213
+
2214
+ if (key === 'backcolor')
2215
+ {
2216
+ elnone.click($.proxy(this.setBackgroundNone, this));
2217
+ }
2218
+ else
2219
+ {
2220
+ elnone.click($.proxy(this.setColorNone, this));
2221
+ }
2222
+
2223
+ $(dropdown).append(elnone);
2224
+
2225
+ return dropdown;
2226
+ },
2227
+ setBackgroundNone: function()
2228
+ {
2229
+ $(this.getParentNode()).css('background-color', 'transparent');
2230
+ this.syncCode();
2231
+ },
2232
+ setColorNone: function()
2233
+ {
2234
+ $(this.getParentNode()).attr('color', '').css('color', '');
2235
+ this.syncCode();
2236
+ },
2237
+
2238
+ // DROPDOWNS
2239
+ showDropDown: function(e, dropdown, key)
2240
+ {
2241
+ if (this.getBtn(key).hasClass('dropact'))
2242
+ {
2243
+ this.hideAllDropDown();
2244
+ }
2245
+ else
2246
+ {
2247
+ this.hideAllDropDown();
2248
+
2249
+ this.setBtnActive(key);
2250
+ this.getBtn(key).addClass('dropact');
2251
+
2252
+ var left = this.getBtn(key).offset().left;
2253
+
2254
+ if (this.opts.air)
2255
+ {
2256
+ var air_top = this.air.offset().top;
2257
+
2258
+ $(dropdown).css({ position: 'absolute', left: left + 'px', top: air_top+30 + 'px' }).show();
2259
+ }
2260
+ else if (this.opts.fixed && this.fixed)
2261
+ {
2262
+ $(dropdown).css({ position: 'fixed', left: left + 'px', top: '30px' }).show();
2263
+ }
2264
+ else
2265
+ {
2266
+ var top = this.$toolbar.offset().top + 30;
2267
+ $(dropdown).css({ position: 'absolute', left: left + 'px', top: top + 'px' }).show();
2268
+ }
2269
+ }
2270
+
2271
+ var hdlHideDropDown = $.proxy(function(e) { this.hideDropDown(e, dropdown, key); }, this);
2272
+
2273
+ $(document).one('click', hdlHideDropDown);
2274
+ this.$editor.one('click', hdlHideDropDown);
2275
+ this.$content.one('click', hdlHideDropDown);
2276
+
2277
+ e.stopPropagation();
2278
+
2279
+ },
2280
+ hideAllDropDown: function()
2281
+ {
2282
+ this.$toolbar.find('a.dropact').removeClass('redactor_act').removeClass('dropact');
2283
+ $('.redactor_dropdown').hide();
2284
+ },
2285
+ hideDropDown: function(e, dropdown, key)
2286
+ {
2287
+ if (!$(e.target).hasClass('dropact'))
2288
+ {
2289
+ $(dropdown).removeClass('dropact');
2290
+ this.showedDropDown = false;
2291
+ this.hideAllDropDown();
2292
+ }
2293
+ },
2294
+
2295
+ // BUTTONS MANIPULATIONS
2296
+ getBtn: function(key)
2297
+ {
2298
+ if (this.opts.toolbar === false)
2299
+ {
2300
+ return false;
2301
+ }
2302
+
2303
+ return $(this.$toolbar.find('a.redactor_btn_' + key));
2304
+ },
2305
+ setBtnActive: function(key)
2306
+ {
2307
+ this.getBtn(key).addClass('redactor_act');
2308
+ },
2309
+ setBtnInactive: function(key)
2310
+ {
2311
+ this.getBtn(key).removeClass('redactor_act');
2312
+ },
2313
+ inactiveAllButtons: function()
2314
+ {
2315
+ $.each(this.opts.activeButtons, $.proxy(function(i,s)
2316
+ {
2317
+ this.setBtnInactive(s);
2318
+
2319
+ }, this));
2320
+ },
2321
+ changeBtnIcon: function(key, classname)
2322
+ {
2323
+ this.getBtn(key).addClass('redactor_btn_' + classname);
2324
+ },
2325
+ removeBtnIcon: function(key, classname)
2326
+ {
2327
+ this.getBtn(key).removeClass('redactor_btn_' + classname);
2328
+ },
2329
+
2330
+ addBtnSeparator: function()
2331
+ {
2332
+ this.$toolbar.append($('<li class="redactor_separator"></li>'));
2333
+ },
2334
+ addBtnSeparatorAfter: function(key)
2335
+ {
2336
+ var $btn = this.getBtn(key);
2337
+ $btn.parent().after($('<li class="redactor_separator"></li>'));
2338
+ },
2339
+ addBtnSeparatorBefore: function(key)
2340
+ {
2341
+ var $btn = this.getBtn(key);
2342
+ $btn.parent().before($('<li class="redactor_separator"></li>'));
2343
+ },
2344
+ removeBtnSeparatorAfter: function(key)
2345
+ {
2346
+ var $btn = this.getBtn(key);
2347
+ $btn.parent().next().remove();
2348
+ },
2349
+ removeBtnSeparatorBefore: function(key)
2350
+ {
2351
+ var $btn = this.getBtn(key);
2352
+ $btn.parent().prev().remove();
2353
+ },
2354
+
2355
+ setBtnRight: function(key)
2356
+ {
2357
+ if (this.opts.toolbar === false)
2358
+ {
2359
+ return false;
2360
+ }
2361
+
2362
+ this.getBtn(key).parent().addClass('redactor_btn_right');
2363
+ },
2364
+ setBtnLeft: function(key)
2365
+ {
2366
+ if (this.opts.toolbar === false)
2367
+ {
2368
+ return false;
2369
+ }
2370
+
2371
+ this.getBtn(key).parent().removeClass('redactor_btn_right');
2372
+ },
2373
+ addBtn: function(key, title, callback, dropdown)
2374
+ {
2375
+ if (this.opts.toolbar === false)
2376
+ {
2377
+ return false;
2378
+ }
2379
+
2380
+ var btn = this.buildButton(key, { title: title, callback: callback, dropdown: dropdown });
2381
+ this.$toolbar.append($('<li>').append(btn));
2382
+ },
2383
+ addBtnFirst: function(key, title, callback, dropdown)
2384
+ {
2385
+ if (this.opts.toolbar === false)
2386
+ {
2387
+ return false;
2388
+ }
2389
+
2390
+ var btn = this.buildButton(key, { title: title, callback: callback, dropdown: dropdown });
2391
+ this.$toolbar.prepend($('<li>').append(btn));
2392
+ },
2393
+ addBtnAfter: function(afterkey, key, title, callback, dropdown)
2394
+ {
2395
+ if (this.opts.toolbar === false)
2396
+ {
2397
+ return false;
2398
+ }
2399
+
2400
+ var btn = this.buildButton(key, { title: title, callback: callback, dropdown: dropdown });
2401
+ var $btn = this.getBtn(afterkey);
2402
+ $btn.parent().after($('<li>').append(btn));
2403
+ },
2404
+ addBtnBefore: function(beforekey, key, title, callback, dropdown)
2405
+ {
2406
+ if (this.opts.toolbar === false)
2407
+ {
2408
+ return false;
2409
+ }
2410
+
2411
+ var btn = this.buildButton(key, { title: title, callback: callback, dropdown: dropdown });
2412
+ var $btn = this.getBtn(beforekey);
2413
+ $btn.parent().before($('<li>').append(btn));
2414
+ },
2415
+ removeBtn: function(key, separator)
2416
+ {
2417
+ var $btn = this.getBtn(key);
2418
+
2419
+ if (separator === true)
2420
+ {
2421
+ $btn.parent().next().remove();
2422
+ }
2423
+
2424
+ $btn.parent().removeClass('redactor_btn_right');
2425
+ $btn.remove();
2426
+ },
2427
+
2428
+
2429
+ // SELECTION AND NODE MANIPULATION
2430
+ getFragmentHtml: function (fragment)
2431
+ {
2432
+ var cloned = fragment.cloneNode(true);
2433
+ var div = this.document.createElement('div');
2434
+ div.appendChild(cloned);
2435
+ return div.innerHTML;
2436
+ },
2437
+ extractContent: function()
2438
+ {
2439
+ var node = this.$editor.get(0);
2440
+ var frag = this.document.createDocumentFragment(), child;
2441
+ while ((child = node.firstChild))
2442
+ {
2443
+ frag.appendChild(child);
2444
+ }
2445
+
2446
+ return frag;
2447
+ },
2448
+
2449
+ // Save and Restore Selection
2450
+ saveSelection: function()
2451
+ {
2452
+ this.$editor.focus();
2453
+
2454
+ this.savedSel = this.getOrigin();
2455
+ this.savedSelObj = this.getFocus();
2456
+ },
2457
+ restoreSelection: function()
2458
+ {
2459
+ if (typeof this.savedSel !== 'undefined' && this.savedSel !== null && this.savedSelObj !== null && this.savedSel[0].tagName !== 'BODY')
2460
+ {
2461
+ if (this.opts.iframe === false && $(this.savedSel[0]).closest('.redactor_editor').size() == 0)
2462
+ {
2463
+ this.$editor.focus();
2464
+ }
2465
+ else
2466
+ {
2467
+ if (this.browser('opera'))
2468
+ {
2469
+ this.$editor.focus();
2470
+ }
2471
+
2472
+ this.setSelection(this.savedSel[0], this.savedSel[1], this.savedSelObj[0], this.savedSelObj[1]);
2473
+
2474
+ if (this.browser('mozilla'))
2475
+ {
2476
+ this.$editor.focus();
2477
+ }
2478
+ }
2479
+ }
2480
+ else
2481
+ {
2482
+ this.$editor.focus();
2483
+ }
2484
+ },
2485
+
2486
+ // Selection
2487
+ getSelection: function()
2488
+ {
2489
+ var doc = this.document;
2490
+
2491
+ if (this.window.getSelection)
2492
+ {
2493
+ return this.window.getSelection();
2494
+ }
2495
+ else if (doc.getSelection)
2496
+ {
2497
+ return doc.getSelection();
2498
+ }
2499
+ else // IE
2500
+ {
2501
+ return doc.selection.createRange();
2502
+ }
2503
+
2504
+ return false;
2505
+ },
2506
+ hasSelection: function()
2507
+ {
2508
+ if (!this.oldIE())
2509
+ {
2510
+ var sel;
2511
+ return (sel = this.getSelection()) && (sel.focusNode != null) && (sel.anchorNode != null);
2512
+ }
2513
+ else // IE8
2514
+ {
2515
+ var node = this.$editor.get(0);
2516
+
2517
+ var range;
2518
+ node.focus();
2519
+ if (!node.document.selection)
2520
+ {
2521
+ return false;
2522
+ }
2523
+
2524
+ range = node.document.selection.createRange();
2525
+ return range && range.parentElement().document === node.document;
2526
+ }
2527
+ },
2528
+ getOrigin: function()
2529
+ {
2530
+ if (!this.oldIE())
2531
+ {
2532
+ var sel;
2533
+ if (!((sel = this.getSelection()) && (sel.anchorNode != null)))
2534
+ {
2535
+ return null;
2536
+ }
2537
+
2538
+ return [sel.anchorNode, sel.anchorOffset];
2539
+ }
2540
+ else
2541
+ {
2542
+ var node = this.$editor.get(0);
2543
+
2544
+ var range;
2545
+ node.focus();
2546
+ if (!this.hasSelection())
2547
+ {
2548
+ return null;
2549
+ }
2550
+
2551
+ range = node.document.selection.createRange();
2552
+ return this._getBoundary(node.document, range, true);
2553
+ }
2554
+ },
2555
+ getFocus: function()
2556
+ {
2557
+ if (!this.oldIE())
2558
+ {
2559
+ var sel;
2560
+ if (!((sel = this.getSelection()) && (sel.focusNode != null)))
2561
+ {
2562
+ return null;
2563
+ }
2564
+
2565
+ return [sel.focusNode, sel.focusOffset];
2566
+ }
2567
+ else
2568
+ {
2569
+ var node = this.$editor.get(0);
2570
+
2571
+ var range;
2572
+ node.focus();
2573
+ if (!this.hasSelection())
2574
+ {
2575
+ return null;
2576
+ }
2577
+
2578
+ range = node.document.selection.createRange();
2579
+ return this._getBoundary(node.document, range, false);
2580
+
2581
+ }
2582
+ },
2583
+ setSelection: function (orgn, orgo, focn, foco)
2584
+ {
2585
+ if (focn == null)
2586
+ {
2587
+ focn = orgn;
2588
+ }
2589
+
2590
+ if (foco == null)
2591
+ {
2592
+ foco = orgo;
2593
+ }
2594
+
2595
+ if (!this.oldIE())
2596
+ {
2597
+ var sel = this.getSelection();
2598
+ if (!sel)
2599
+ {
2600
+ return;
2601
+ }
2602
+
2603
+ if (sel.collapse && sel.extend)
2604
+ {
2605
+ sel.collapse(orgn, orgo);
2606
+ sel.extend(focn, foco);
2607
+ }
2608
+ else // IE9
2609
+ {
2610
+ r = this.document.createRange();
2611
+ r.setStart(orgn, orgo);
2612
+ r.setEnd(focn, foco);
2613
+
2614
+ try
2615
+ {
2616
+ sel.removeAllRanges();
2617
+ }
2618
+ catch (e) {}
2619
+
2620
+ sel.addRange(r);
2621
+ }
2622
+ }
2623
+ else
2624
+ {
2625
+ var node = this.$editor.get(0);
2626
+ var range = node.document.body.createTextRange();
2627
+
2628
+ this._moveBoundary(node.document, range, false, focn, foco);
2629
+ this._moveBoundary(node.document, range, true, orgn, orgo);
2630
+ return range.select();
2631
+ }
2632
+ },
2633
+
2634
+ // Get elements, html and text
2635
+ getCurrentNode: function()
2636
+ {
2637
+ if (typeof this.window.getSelection !== 'undefined')
2638
+ {
2639
+ return this.getSelectedNode().parentNode;
2640
+ }
2641
+ else if (typeof this.document.selection !== 'undefined')
2642
+ {
2643
+ return this.getSelection().parentElement();
2644
+ }
2645
+ },
2646
+ getParentNode: function()
2647
+ {
2648
+ return $(this.getCurrentNode()).parent()[0]
2649
+ },
2650
+ getSelectedNode: function()
2651
+ {
2652
+ if (this.oldIE())
2653
+ {
2654
+ return this.getSelection().parentElement();
2655
+ }
2656
+ else if (typeof this.window.getSelection !== 'undefined')
2657
+ {
2658
+ var s = this.window.getSelection();
2659
+ if (s.rangeCount > 0)
2660
+ {
2661
+ return this.getSelection().getRangeAt(0).commonAncestorContainer;
2662
+ }
2663
+ else
2664
+ {
2665
+ return false;
2666
+ }
2667
+ }
2668
+ else if (typeof this.document.selection !== 'undefined')
2669
+ {
2670
+ return this.getSelection();
2671
+ }
2672
+ },
2673
+
2674
+
2675
+ // IE8 specific selection
2676
+ _getBoundary: function(doc, textRange, bStart)
2677
+ {
2678
+ var cursor, cursorNode, node, offset, parent;
2679
+
2680
+ cursorNode = doc.createElement('a');
2681
+ cursor = textRange.duplicate();
2682
+ cursor.collapse(bStart);
2683
+ parent = cursor.parentElement();
2684
+ while (true)
2685
+ {
2686
+ parent.insertBefore(cursorNode, cursorNode.previousSibling);
2687
+ cursor.moveToElementText(cursorNode);
2688
+ if (!(cursor.compareEndPoints((bStart ? 'StartToStart' : 'StartToEnd'), textRange) > 0 && (cursorNode.previousSibling != null)))
2689
+ {
2690
+ break;
2691
+ }
2692
+ }
2693
+
2694
+ if (cursor.compareEndPoints((bStart ? 'StartToStart' : 'StartToEnd'), textRange) === -1 && cursorNode.nextSibling)
2695
+ {
2696
+ cursor.setEndPoint((bStart ? 'EndToStart' : 'EndToEnd'), textRange);
2697
+ node = cursorNode.nextSibling;
2698
+ offset = cursor.text.length;
2699
+ }
2700
+ else
2701
+ {
2702
+ node = cursorNode.parentNode;
2703
+ offset = this._getChildIndex(cursorNode);
2704
+ }
2705
+
2706
+ cursorNode.parentNode.removeChild(cursorNode);
2707
+ return [node, offset];
2708
+ },
2709
+ _moveBoundary: function(doc, textRange, bStart, node, offset)
2710
+ {
2711
+ var anchorNode, anchorParent, cursor, cursorNode, textOffset;
2712
+
2713
+ textOffset = 0;
2714
+ anchorNode = this._isText(node) ? node : node.childNodes[offset];
2715
+ anchorParent = this._isText(node) ? node.parentNode : node;
2716
+
2717
+ if (this._isText(node))
2718
+ {
2719
+ textOffset = offset;
2720
+ }
2721
+
2722
+ cursorNode = doc.createElement('a');
2723
+ anchorParent.insertBefore(cursorNode, anchorNode || null);
2724
+ cursor = doc.body.createTextRange();
2725
+ cursor.moveToElementText(cursorNode);
2726
+ cursorNode.parentNode.removeChild(cursorNode);
2727
+
2728
+ textRange.setEndPoint((bStart ? 'StartToStart' : 'EndToEnd'), cursor);
2729
+ return textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset);
2730
+ },
2731
+ _isText: function (d)
2732
+ {
2733
+ return (d != null ? d.nodeType == 3 : false);
2734
+ },
2735
+ _getChildIndex: function (e)
2736
+ {
2737
+ var k = 0;
2738
+ while (e = e.previousSibling) {
2739
+ k++;
2740
+ }
2741
+ return k;
2742
+ },
2743
+
2744
+ insertNodeAfterCaret: function(node)
2745
+ {
2746
+ this.saveSelection();
2747
+ this.insertNodeAtCaret(node);
2748
+ this.restoreSelection();
2749
+ },
2750
+
2751
+ insertNodeAtCaret: function(node)
2752
+ {
2753
+ if (this.window.getSelection)
2754
+ {
2755
+ var sel = this.getSelection();
2756
+ if (sel.rangeCount)
2757
+ {
2758
+ var range = sel.getRangeAt(0);
2759
+ range.collapse(false);
2760
+ range.insertNode(node);
2761
+ range = range.cloneRange();
2762
+ range.selectNodeContents(node);
2763
+ range.collapse(false);
2764
+ sel.removeAllRanges();
2765
+ sel.addRange(range);
2766
+ }
2767
+ }
2768
+ else if (this.document.selection)
2769
+ {
2770
+ var html = (node.nodeType === 1) ? node.outerHTML : node.data;
2771
+ var id = "marker_" + ("" + Math.random()).slice(2);
2772
+ html += '<span id="' + id + '"></span>';
2773
+ var textRange = this.getSelection();
2774
+ textRange.collapse(false);
2775
+ textRange.pasteHTML(html);
2776
+ var markerSpan = this.document.getElementById(id);
2777
+ textRange.moveToElementText(markerSpan);
2778
+ textRange.select();
2779
+ markerSpan.parentNode.removeChild(markerSpan);
2780
+ }
2781
+ },
2782
+ getSelectedHtml: function()
2783
+ {
2784
+ var html = '';
2785
+ if (this.window.getSelection)
2786
+ {
2787
+ var sel = this.window.getSelection();
2788
+ if (sel.rangeCount)
2789
+ {
2790
+ var container = this.document.createElement("div");
2791
+ for (var i = 0, len = sel.rangeCount; i < len; ++i)
2792
+ {
2793
+ container.appendChild(sel.getRangeAt(i).cloneContents());
2794
+ }
2795
+
2796
+ html = container.innerHTML;
2797
+
2798
+ }
2799
+ }
2800
+ else if (this.document.selection)
2801
+ {
2802
+ if (this.document.selection.type === "Text")
2803
+ {
2804
+ html = this.document.selection.createRange().htmlText;
2805
+ }
2806
+ }
2807
+
2808
+ return html;
2809
+ },
2810
+
2811
+ // RESIZE IMAGES
2812
+ resizeImage: function(resize)
2813
+ {
2814
+ var clicked = false;
2815
+ var clicker = false;
2816
+ var start_x;
2817
+ var start_y;
2818
+ var ratio = $(resize).width()/$(resize).height();
2819
+ var min_w = 10;
2820
+ var min_h = 10;
2821
+
2822
+ $(resize).off('hover mousedown mouseup click mousemove');
2823
+ $(resize).hover(function() { $(resize).css('cursor', 'nw-resize'); }, function() { $(resize).css('cursor',''); clicked = false; });
2824
+
2825
+ $(resize).mousedown(function(e)
2826
+ {
2827
+ e.preventDefault();
2828
+
2829
+ ratio = $(resize).width()/$(resize).height();
2830
+
2831
+ clicked = true;
2832
+ clicker = true;
2833
+
2834
+ start_x = Math.round(e.pageX - $(resize).eq(0).offset().left);
2835
+ start_y = Math.round(e.pageY - $(resize).eq(0).offset().top);
2836
+ });
2837
+
2838
+ $(resize).mouseup($.proxy(function(e)
2839
+ {
2840
+ clicked = false;
2841
+ $(resize).css('cursor','');
2842
+ this.syncCode();
2843
+
2844
+ }, this));
2845
+
2846
+ $(resize).click($.proxy(function(e)
2847
+ {
2848
+ if (clicker)
2849
+ {
2850
+ this.imageEdit(e);
2851
+ }
2852
+
2853
+ }, this));
2854
+
2855
+ $(resize).mousemove(function(e)
2856
+ {
2857
+ if (clicked)
2858
+ {
2859
+ clicker = false;
2860
+
2861
+ var mouse_x = Math.round(e.pageX - $(this).eq(0).offset().left) - start_x;
2862
+ var mouse_y = Math.round(e.pageY - $(this).eq(0).offset().top) - start_y;
2863
+
2864
+ var div_h = $(resize).height();
2865
+
2866
+ var new_h = parseInt(div_h, 10) + mouse_y;
2867
+ var new_w = new_h*ratio;
2868
+
2869
+ if (new_w > min_w)
2870
+ {
2871
+ $(resize).width(new_w);
2872
+ }
2873
+
2874
+ if (new_h > min_h)
2875
+ {
2876
+ $(resize).height(new_h);
2877
+ }
2878
+
2879
+ start_x = Math.round(e.pageX - $(this).eq(0).offset().left);
2880
+ start_y = Math.round(e.pageY - $(this).eq(0).offset().top);
2881
+ }
2882
+ });
2883
+ },
2884
+
2885
+ // TABLE
2886
+ showTable: function()
2887
+ {
2888
+ this.saveSelection();
2889
+
2890
+ this.modalInit(RLANG.table, this.opts.modal_table, 300, $.proxy(function()
2891
+ {
2892
+ $('#redactor_insert_table_btn').click($.proxy(this.insertTable, this));
2893
+
2894
+ setTimeout(function()
2895
+ {
2896
+ $('#redactor_table_rows').focus();
2897
+ }, 200);
2898
+
2899
+ }, this)
2900
+ );
2901
+ },
2902
+ insertTable: function()
2903
+ {
2904
+ var rows = $('#redactor_table_rows').val();
2905
+ var columns = $('#redactor_table_columns').val();
2906
+
2907
+ var table_box = $('<div></div>');
2908
+
2909
+ var tableid = Math.floor(Math.random() * 99999);
2910
+ var table = $('<table id="table' + tableid + '"><tbody></tbody></table>');
2911
+
2912
+ for (var i = 0; i < rows; i++)
2913
+ {
2914
+ var row = $('<tr></tr>');
2915
+ for (var z = 0; z < columns; z++)
2916
+ {
2917
+ var column = $('<td><br></td>');
2918
+ $(row).append(column);
2919
+ }
2920
+ $(table).append(row);
2921
+ }
2922
+
2923
+ $(table_box).append(table);
2924
+ var html = $(table_box).html() + '<p></p>';
2925
+
2926
+ this.restoreSelection();
2927
+ this.execCommand('inserthtml', html);
2928
+ this.modalClose();
2929
+ this.observeTables();
2930
+
2931
+ },
2932
+ tableObserver: function(e)
2933
+ {
2934
+ this.$table = $(e.target).closest('table');
2935
+
2936
+ this.$table_tr = this.$table.find('tr');
2937
+ this.$table_td = this.$table.find('td');
2938
+
2939
+ this.$tbody = $(e.target).closest('tbody');
2940
+ this.$thead = $(this.$table).find('thead');
2941
+
2942
+ this.$current_td = $(e.target);
2943
+ this.$current_tr = $(e.target).closest('tr');
2944
+ },
2945
+ deleteTable: function()
2946
+ {
2947
+ $(this.$table).remove();
2948
+ this.$table = false;
2949
+ this.syncCode();
2950
+ },
2951
+ deleteRow: function()
2952
+ {
2953
+ $(this.$current_tr).remove();
2954
+ this.syncCode();
2955
+ },
2956
+ deleteColumn: function()
2957
+ {
2958
+ var index = $(this.$current_td).get(0).cellIndex;
2959
+
2960
+ $(this.$table).find('tr').each(function()
2961
+ {
2962
+ $(this).find('td').eq(index).remove();
2963
+ });
2964
+
2965
+ this.syncCode();
2966
+ },
2967
+ addHead: function()
2968
+ {
2969
+ if ($(this.$table).find('thead').size() !== 0)
2970
+ {
2971
+ this.deleteHead();
2972
+ }
2973
+ else
2974
+ {
2975
+ var tr = $(this.$table).find('tr').first().clone();
2976
+ tr.find('td').html('&nbsp;');
2977
+ this.$thead = $('<thead></thead>');
2978
+ this.$thead.append(tr);
2979
+ $(this.$table).prepend(this.$thead);
2980
+ this.syncCode();
2981
+ }
2982
+ },
2983
+ deleteHead: function()
2984
+ {
2985
+ $(this.$thead).remove();
2986
+ this.$thead = false;
2987
+ this.syncCode();
2988
+ },
2989
+ insertRowAbove: function()
2990
+ {
2991
+ this.insertRow('before');
2992
+ },
2993
+ insertRowBelow: function()
2994
+ {
2995
+ this.insertRow('after');
2996
+ },
2997
+ insertColumnLeft: function()
2998
+ {
2999
+ this.insertColumn('before');
3000
+ },
3001
+ insertColumnRight: function()
3002
+ {
3003
+ this.insertColumn('after');
3004
+ },
3005
+ insertRow: function(type)
3006
+ {
3007
+ var new_tr = $(this.$current_tr).clone();
3008
+ new_tr.find('td').html('&nbsp;');
3009
+ if (type === 'after')
3010
+ {
3011
+ $(this.$current_tr).after(new_tr);
3012
+ }
3013
+ else
3014
+ {
3015
+ $(this.$current_tr).before(new_tr);
3016
+ }
3017
+
3018
+ this.syncCode();
3019
+ },
3020
+ insertColumn: function(type)
3021
+ {
3022
+ var index = 0;
3023
+
3024
+ this.$current_tr.find('td').each($.proxy(function(i,s)
3025
+ {
3026
+ if ($(s)[0] === this.$current_td[0])
3027
+ {
3028
+ index = i;
3029
+ }
3030
+ }, this));
3031
+
3032
+ this.$table_tr.each(function(i,s)
3033
+ {
3034
+ var current = $(s).find('td').eq(index);
3035
+
3036
+ var td = current.clone();
3037
+ td.html('&nbsp;');
3038
+
3039
+ if (type === 'after')
3040
+ {
3041
+ $(current).after(td);
3042
+ }
3043
+ else
3044
+ {
3045
+ $(current).before(td);
3046
+ }
3047
+
3048
+ });
3049
+
3050
+ this.syncCode();
3051
+ },
3052
+
3053
+ // INSERT VIDEO
3054
+ showVideo: function()
3055
+ {
3056
+ this.saveSelection();
3057
+ this.modalInit(RLANG.video, this.opts.modal_video, 600, $.proxy(function()
3058
+ {
3059
+ $('#redactor_insert_video_btn').click($.proxy(this.insertVideo, this));
3060
+
3061
+ setTimeout(function()
3062
+ {
3063
+ $('#redactor_insert_video_area').focus();
3064
+ }, 200);
3065
+
3066
+ }, this)
3067
+ );
3068
+ },
3069
+ insertVideo: function()
3070
+ {
3071
+ var data = $('#redactor_insert_video_area').val();
3072
+ data = this.stripTags(data);
3073
+
3074
+ this.restoreSelection();
3075
+ this.execCommand('inserthtml', data);
3076
+ this.modalClose();
3077
+ },
3078
+
3079
+ // INSERT IMAGE
3080
+ imageEdit: function(e)
3081
+ {
3082
+ var $el = $(e.target);
3083
+ var parent = $el.parent();
3084
+
3085
+ var callback = $.proxy(function()
3086
+ {
3087
+ $('#redactor_file_alt').val($el.attr('alt'));
3088
+ $('#redactor_image_edit_src').attr('href', $el.attr('src'));
3089
+ $('#redactor_form_image_align').val($el.css('float'));
3090
+
3091
+ if ($(parent).get(0).tagName === 'A')
3092
+ {
3093
+ $('#redactor_file_link').val($(parent).attr('href'));
3094
+ }
3095
+
3096
+ $('#redactor_image_delete_btn').click($.proxy(function() { this.imageDelete($el); }, this));
3097
+ $('#redactorSaveBtn').click($.proxy(function() { this.imageSave($el); }, this));
3098
+
3099
+ }, this);
3100
+
3101
+ this.modalInit(RLANG.image, this.opts.modal_image_edit, 380, callback);
3102
+
3103
+ },
3104
+ imageDelete: function(el)
3105
+ {
3106
+ $(el).remove();
3107
+ this.modalClose();
3108
+ this.syncCode();
3109
+ },
3110
+ imageSave: function(el)
3111
+ {
3112
+ var parent = $(el).parent();
3113
+
3114
+ $(el).attr('alt', $('#redactor_file_alt').val());
3115
+
3116
+ var floating = $('#redactor_form_image_align').val();
3117
+
3118
+ if (floating === 'left')
3119
+ {
3120
+ $(el).css({ 'float': 'left', margin: '0 10px 10px 0' });
3121
+ }
3122
+ else if (floating === 'right')
3123
+ {
3124
+ $(el).css({ 'float': 'right', margin: '0 0 10px 10px' });
3125
+ }
3126
+ else
3127
+ {
3128
+ $(el).css({ 'float': 'none', margin: '0' });
3129
+ }
3130
+
3131
+ // as link
3132
+ var link = $.trim($('#redactor_file_link').val());
3133
+ if (link !== '')
3134
+ {
3135
+ if ($(parent).get(0).tagName !== 'A')
3136
+ {
3137
+ $(el).replaceWith('<a href="' + link + '">' + this.outerHTML(el) + '</a>');
3138
+ }
3139
+ else
3140
+ {
3141
+ $(parent).attr('href', link);
3142
+ }
3143
+ }
3144
+ else
3145
+ {
3146
+ if ($(parent).get(0).tagName === 'A')
3147
+ {
3148
+ $(parent).replaceWith(this.outerHTML(el));
3149
+ }
3150
+ }
3151
+
3152
+ this.modalClose();
3153
+ this.observeImages();
3154
+ this.syncCode();
3155
+
3156
+ },
3157
+ showImage: function()
3158
+ {
3159
+ this.saveSelection();
3160
+
3161
+ var callback = $.proxy(function()
3162
+ {
3163
+ // json
3164
+ if (this.opts.imageGetJson !== false)
3165
+ {
3166
+ $.getJSON(this.opts.imageGetJson, $.proxy(function(data) {
3167
+
3168
+ var folders = {};
3169
+ var z = 0;
3170
+
3171
+ // folders
3172
+ $.each(data, $.proxy(function(key, val)
3173
+ {
3174
+ if (typeof val.folder !== 'undefined')
3175
+ {
3176
+ z++;
3177
+ folders[val.folder] = z;
3178
+ }
3179
+
3180
+ }, this));
3181
+
3182
+ var folderclass = false;
3183
+ $.each(data, $.proxy(function(key, val)
3184
+ {
3185
+ // title
3186
+ var thumbtitle = '';
3187
+ if (typeof val.title !== 'undefined')
3188
+ {
3189
+ thumbtitle = val.title;
3190
+ }
3191
+
3192
+ var folderkey = 0;
3193
+ if (!$.isEmptyObject(folders) && typeof val.folder !== 'undefined')
3194
+ {
3195
+ folderkey = folders[val.folder];
3196
+ if (folderclass === false)
3197
+ {
3198
+ folderclass = '.redactorfolder' + folderkey;
3199
+ }
3200
+ }
3201
+
3202
+ var img = $('<img src="' + val.thumb + '" class="redactorfolder redactorfolder' + folderkey + '" rel="' + val.image + '" title="' + thumbtitle + '" />');
3203
+ $('#redactor_image_box').append(img);
3204
+ $(img).click($.proxy(this.imageSetThumb, this));
3205
+
3206
+
3207
+ }, this));
3208
+
3209
+ // folders
3210
+ if (!$.isEmptyObject(folders))
3211
+ {
3212
+ $('.redactorfolder').hide();
3213
+ $(folderclass).show();
3214
+
3215
+ var onchangeFunc = function(e)
3216
+ {
3217
+ $('.redactorfolder').hide();
3218
+ $('.redactorfolder' + $(e.target).val()).show();
3219
+ }
3220
+
3221
+ var select = $('<select id="redactor_image_box_select">');
3222
+ $.each(folders, function(k,v)
3223
+ {
3224
+ select.append($('<option value="' + v + '">' + k + '</option>'));
3225
+ });
3226
+
3227
+ $('#redactor_image_box').before(select);
3228
+ select.change(onchangeFunc);
3229
+ }
3230
+
3231
+ }, this));
3232
+ }
3233
+ else
3234
+ {
3235
+ $('#redactor_tabs a').eq(1).remove();
3236
+ }
3237
+
3238
+ if (this.opts.imageUpload !== false)
3239
+ {
3240
+
3241
+ // dragupload
3242
+ if (this.opts.uploadCrossDomain === false && this.isMobile() === false)
3243
+ {
3244
+
3245
+ if ($('#redactor_file').size() !== 0)
3246
+ {
3247
+ $('#redactor_file').dragupload(
3248
+ {
3249
+ url: this.opts.imageUpload,
3250
+ uploadFields: this.opts.uploadFields,
3251
+ success: $.proxy(this.imageUploadCallback, this),
3252
+ error: $.proxy(this.opts.imageUploadErrorCallback, this)
3253
+ });
3254
+ }
3255
+ }
3256
+
3257
+ // ajax upload
3258
+ this.uploadInit('redactor_file',
3259
+ {
3260
+ auto: true,
3261
+ url: this.opts.imageUpload,
3262
+ success: $.proxy(this.imageUploadCallback, this),
3263
+ error: $.proxy(this.opts.imageUploadErrorCallback, this)
3264
+ });
3265
+ }
3266
+ else
3267
+ {
3268
+ $('.redactor_tab').hide();
3269
+ if (this.opts.imageGetJson === false)
3270
+ {
3271
+ $('#redactor_tabs').remove();
3272
+ $('#redactor_tab3').show();
3273
+ }
3274
+ else
3275
+ {
3276
+ var tabs = $('#redactor_tabs a');
3277
+ tabs.eq(0).remove();
3278
+ tabs.eq(1).addClass('redactor_tabs_act');
3279
+ $('#redactor_tab2').show();
3280
+ }
3281
+ }
3282
+
3283
+ $('#redactor_upload_btn').click($.proxy(this.imageUploadCallbackLink, this));
3284
+
3285
+ if (this.opts.imageUpload === false && this.opts.imageGetJson === false)
3286
+ {
3287
+ setTimeout(function()
3288
+ {
3289
+ $('#redactor_file_link').focus();
3290
+ }, 200);
3291
+
3292
+ }
3293
+
3294
+ }, this);
3295
+
3296
+ this.modalInit(RLANG.image, this.opts.modal_image, 610, callback);
3297
+
3298
+ },
3299
+ imageSetThumb: function(e)
3300
+ {
3301
+ this._imageSet('<img src="' + $(e.target).attr('rel') + '" alt="' + $(e.target).attr('title') + '" />', true);
3302
+ },
3303
+ imageUploadCallbackLink: function()
3304
+ {
3305
+ if ($('#redactor_file_link').val() !== '')
3306
+ {
3307
+ var data = '<img src="' + $('#redactor_file_link').val() + '" />';
3308
+ this._imageSet(data, true);
3309
+ }
3310
+ else
3311
+ {
3312
+ this.modalClose();
3313
+ }
3314
+ },
3315
+ imageUploadCallback: function(data)
3316
+ {
3317
+ this._imageSet(data);
3318
+ },
3319
+ _imageSet: function(json, link)
3320
+ {
3321
+ this.restoreSelection();
3322
+
3323
+ if (json !== false)
3324
+ {
3325
+ var html = '';
3326
+ if (link !== true)
3327
+ {
3328
+ html = '<p><img src="' + json.filelink + '" /></p>';
3329
+ }
3330
+ else
3331
+ {
3332
+ html = json;
3333
+ }
3334
+
3335
+ this.execCommand('inserthtml', html);
3336
+
3337
+ // upload image callback
3338
+ if (link !== true && typeof this.opts.imageUploadCallback === 'function')
3339
+ {
3340
+ this.opts.imageUploadCallback(this, json);
3341
+ }
3342
+ }
3343
+
3344
+ this.modalClose();
3345
+ this.observeImages();
3346
+ },
3347
+
3348
+ // INSERT LINK
3349
+ showLink: function()
3350
+ {
3351
+ this.saveSelection();
3352
+
3353
+ var callback = $.proxy(function()
3354
+ {
3355
+ this.insert_link_node = false;
3356
+ var sel = this.getSelection();
3357
+ var url = '', text = '', target = '';
3358
+
3359
+ if (this.browser('msie'))
3360
+ {
3361
+ var parent = this.getParentNode();
3362
+ if (parent.nodeName === 'A')
3363
+ {
3364
+ this.insert_link_node = $(parent);
3365
+ text = this.insert_link_node.text();
3366
+ url = this.insert_link_node.attr('href');
3367
+ target = this.insert_link_node.attr('target');
3368
+ }
3369
+ else
3370
+ {
3371
+ if (this.oldIE())
3372
+ {
3373
+ text = sel.text;
3374
+ }
3375
+ else
3376
+ {
3377
+ text = sel.toString();
3378
+ }
3379
+ }
3380
+ }
3381
+ else
3382
+ {
3383
+ if (sel && sel.anchorNode && sel.anchorNode.parentNode.tagName === 'A')
3384
+ {
3385
+ url = sel.anchorNode.parentNode.href;
3386
+ text = sel.anchorNode.parentNode.text;
3387
+ target = sel.anchorNode.parentNode.target;
3388
+
3389
+ if (sel.toString() === '')
3390
+ {
3391
+ this.insert_link_node = sel.anchorNode.parentNode;
3392
+ }
3393
+ }
3394
+ else
3395
+ {
3396
+ text = sel.toString();
3397
+ }
3398
+ }
3399
+
3400
+ $('.redactor_link_text').val(text);
3401
+
3402
+ var thref = self.location.href.replace(/\/$/i, '');
3403
+ var turl = url.replace(thref, '');
3404
+
3405
+ if (url.search('mailto:') === 0)
3406
+ {
3407
+ this.setModalTab(2);
3408
+
3409
+ $('#redactor_tab_selected').val(2);
3410
+ $('#redactor_link_mailto').val(url.replace('mailto:', ''));
3411
+ }
3412
+ else if (turl.search(/^#/gi) === 0)
3413
+ {
3414
+ this.setModalTab(3);
3415
+
3416
+ $('#redactor_tab_selected').val(3);
3417
+ $('#redactor_link_anchor').val(turl.replace(/^#/gi, ''));
3418
+ }
3419
+ else
3420
+ {
3421
+ $('#redactor_link_url').val(turl);
3422
+ }
3423
+
3424
+ if (target === '_blank')
3425
+ {
3426
+ $('#redactor_link_blank').attr('checked', true);
3427
+ }
3428
+
3429
+ $('#redactor_insert_link_btn').click($.proxy(this.insertLink, this));
3430
+
3431
+ setTimeout(function()
3432
+ {
3433
+ $('#redactor_link_url').focus();
3434
+ }, 200);
3435
+
3436
+ }, this);
3437
+
3438
+ this.modalInit(RLANG.link, this.opts.modal_link, 460, callback);
3439
+
3440
+ },
3441
+ insertLink: function()
3442
+ {
3443
+ var tab_selected = $('#redactor_tab_selected').val();
3444
+ var link = '', text = '', target = '';
3445
+
3446
+ if (tab_selected === '1') // url
3447
+ {
3448
+ link = $('#redactor_link_url').val();
3449
+ text = $('#redactor_link_url_text').val();
3450
+
3451
+ if ($('#redactor_link_blank').attr('checked'))
3452
+ {
3453
+ target = ' target="_blank"';
3454
+ }
3455
+
3456
+ // test url
3457
+ var pattern = '/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/';
3458
+ //var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}';
3459
+ var re = new RegExp('^(http|ftp|https)://' + pattern,'i');
3460
+ var re2 = new RegExp('^' + pattern,'i');
3461
+ if (link.search(re) == -1 && link.search(re2) == 0 && this.opts.protocol !== false)
3462
+ {
3463
+ link = this.opts.protocol + link;
3464
+ }
3465
+
3466
+ }
3467
+ else if (tab_selected === '2') // mailto
3468
+ {
3469
+ link = 'mailto:' + $('#redactor_link_mailto').val();
3470
+ text = $('#redactor_link_mailto_text').val();
3471
+ }
3472
+ else if (tab_selected === '3') // anchor
3473
+ {
3474
+ link = '#' + $('#redactor_link_anchor').val();
3475
+ text = $('#redactor_link_anchor_text').val();
3476
+ }
3477
+
3478
+ this._insertLink('<a href="' + link + '"' + target + '>' + text + '</a>', $.trim(text), link, target);
3479
+
3480
+ },
3481
+ _insertLink: function(a, text, link, target)
3482
+ {
3483
+ this.$editor.focus();
3484
+ this.restoreSelection();
3485
+
3486
+ if (text !== '')
3487
+ {
3488
+ if (this.insert_link_node)
3489
+ {
3490
+ $(this.insert_link_node).text(text);
3491
+ $(this.insert_link_node).attr('href', link);
3492
+ if (target !== '')
3493
+ {
3494
+ $(this.insert_link_node).attr('target', target);
3495
+ }
3496
+ else
3497
+ {
3498
+ $(this.insert_link_node).removeAttr('target');
3499
+ }
3500
+
3501
+ this.syncCode();
3502
+ }
3503
+ else
3504
+ {
3505
+ this.execCommand('inserthtml', a);
3506
+ }
3507
+ }
3508
+
3509
+ this.modalClose();
3510
+ },
3511
+
3512
+ // INSERT FILE
3513
+ showFile: function()
3514
+ {
3515
+ this.saveSelection();
3516
+
3517
+ var callback = $.proxy(function()
3518
+ {
3519
+ var sel = this.getSelection();
3520
+
3521
+ var text = '';
3522
+
3523
+ if (this.oldIE())
3524
+ {
3525
+ text = sel.text;
3526
+ }
3527
+ else
3528
+ {
3529
+ text = sel.toString();
3530
+ }
3531
+
3532
+ $('#redactor_filename').val(text);
3533
+
3534
+ // dragupload
3535
+ if (this.opts.uploadCrossDomain === false && this.isMobile() === false)
3536
+ {
3537
+ $('#redactor_file').dragupload(
3538
+ {
3539
+ url: this.opts.fileUpload,
3540
+ uploadFields: this.opts.uploadFields,
3541
+ success: $.proxy(this.fileUploadCallback, this),
3542
+ error: $.proxy(this.opts.fileUploadErrorCallback, this)
3543
+ });
3544
+ }
3545
+
3546
+ this.uploadInit('redactor_file',
3547
+ {
3548
+ auto: true,
3549
+ url: this.opts.fileUpload,
3550
+ success: $.proxy(this.fileUploadCallback, this),
3551
+ error: $.proxy(this.opts.fileUploadErrorCallback, this)
3552
+ });
3553
+
3554
+ }, this);
3555
+
3556
+ this.modalInit(RLANG.file, this.opts.modal_file, 500, callback);
3557
+ },
3558
+ fileUploadCallback: function(json)
3559
+ {
3560
+ this.restoreSelection();
3561
+
3562
+ if (json !== false)
3563
+ {
3564
+ var text = $('#redactor_filename').val();
3565
+
3566
+ if (text === '')
3567
+ {
3568
+ text = json.filename;
3569
+ }
3570
+
3571
+ var link = '<a href="' + json.filelink + '">' + text + '</a>';
3572
+
3573
+ // chrome fix
3574
+ if (this.browser('webkit') && !!this.window.chrome)
3575
+ {
3576
+ link = link + '&nbsp;';
3577
+ }
3578
+
3579
+ this.execCommand('inserthtml', link);
3580
+
3581
+ // file upload callback
3582
+ if (typeof this.opts.fileUploadCallback === 'function')
3583
+ {
3584
+ this.opts.fileUploadCallback(this, json);
3585
+ }
3586
+ }
3587
+
3588
+ this.modalClose();
3589
+ },
3590
+
3591
+
3592
+
3593
+ // MODAL
3594
+ modalInit: function(title, content, width, callback)
3595
+ {
3596
+ // modal overlay
3597
+ if ($('#redactor_modal_overlay').size() === 0)
3598
+ {
3599
+ this.overlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>');
3600
+ $('body').prepend(this.overlay);
3601
+ }
3602
+
3603
+ if (this.opts.overlay)
3604
+ {
3605
+ $('#redactor_modal_overlay').show();
3606
+ $('#redactor_modal_overlay').click($.proxy(this.modalClose, this));
3607
+ }
3608
+
3609
+ if ($('#redactor_modal').size() === 0)
3610
+ {
3611
+ 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>');
3612
+ $('body').append(this.modal);
3613
+ }
3614
+
3615
+ $('#redactor_modal_close').click($.proxy(this.modalClose, this));
3616
+
3617
+ this.hdlModalClose = $.proxy(function(e) { if ( e.keyCode === 27) { this.modalClose(); return false; } }, this);
3618
+
3619
+ $(document).keyup(this.hdlModalClose);
3620
+ this.$editor.keyup(this.hdlModalClose);
3621
+
3622
+ // set content
3623
+ if (content.indexOf('#') == 0)
3624
+ {
3625
+ $('#redactor_modal_inner').empty().append($(content).html());
3626
+ }
3627
+ else
3628
+ {
3629
+ $('#redactor_modal_inner').empty().append(content);
3630
+ }
3631
+
3632
+
3633
+ $('#redactor_modal_header').html(title);
3634
+
3635
+ // draggable
3636
+ if (typeof $.fn.draggable !== 'undefined')
3637
+ {
3638
+ $('#redactor_modal').draggable({ handle: '#redactor_modal_header' });
3639
+ $('#redactor_modal_header').css('cursor', 'move');
3640
+ }
3641
+
3642
+ // tabs
3643
+ if ($('#redactor_tabs').size() !== 0)
3644
+ {
3645
+ var that = this;
3646
+ $('#redactor_tabs a').each(function(i,s)
3647
+ {
3648
+ i++;
3649
+ $(s).click(function()
3650
+ {
3651
+ $('#redactor_tabs a').removeClass('redactor_tabs_act');
3652
+ $(this).addClass('redactor_tabs_act');
3653
+ $('.redactor_tab').hide();
3654
+ $('#redactor_tab' + i).show();
3655
+ $('#redactor_tab_selected').val(i);
3656
+
3657
+ if (that.isMobile() === false)
3658
+ {
3659
+ var height = $('#redactor_modal').outerHeight();
3660
+ $('#redactor_modal').css('margin-top', '-' + (height+10)/2 + 'px');
3661
+ }
3662
+ });
3663
+ });
3664
+ }
3665
+
3666
+ $('#redactor_modal .redactor_btn_modal_close').click($.proxy(this.modalClose, this));
3667
+
3668
+ if (this.isMobile() === false)
3669
+ {
3670
+ $('#redactor_modal').css({ position: 'fixed', top: '-2000px', left: '50%', width: width + 'px', marginLeft: '-' + (width+60)/2 + 'px' }).show();
3671
+
3672
+ this.modalSaveBodyOveflow = $(document.body).css('overflow');
3673
+ $(document.body).css('overflow', 'hidden');
3674
+ }
3675
+ else
3676
+ {
3677
+ $('#redactor_modal').css({ position: 'fixed', width: '100%', height: '100%', top: '0', left: '0', margin: '0', minHeight: '300px' }).show();
3678
+ }
3679
+
3680
+ // callback
3681
+ if (typeof callback === 'function')
3682
+ {
3683
+ callback();
3684
+ }
3685
+
3686
+ if (this.isMobile() === false)
3687
+ {
3688
+ setTimeout(function()
3689
+ {
3690
+ var height = $('#redactor_modal').outerHeight();
3691
+ $('#redactor_modal').css({ top: '50%', height: 'auto', minHeight: 'auto', marginTop: '-' + (height+10)/2 + 'px' });
3692
+
3693
+ }, 20);
3694
+ }
3695
+
3696
+ },
3697
+ modalClose: function()
3698
+ {
3699
+ $('#redactor_modal_close').unbind('click', this.modalClose);
3700
+ $('#redactor_modal').fadeOut('fast', $.proxy(function()
3701
+ {
3702
+ $('#redactor_modal_inner').html('');
3703
+
3704
+ if (this.opts.overlay)
3705
+ {
3706
+ $('#redactor_modal_overlay').hide();
3707
+ $('#redactor_modal_overlay').unbind('click', this.modalClose);
3708
+ }
3709
+
3710
+ $(document).unbind('keyup', this.hdlModalClose);
3711
+ this.$editor.unbind('keyup', this.hdlModalClose);
3712
+
3713
+ }, this));
3714
+
3715
+
3716
+ if (this.isMobile() === false)
3717
+ {
3718
+ $(document.body).css('overflow', this.modalSaveBodyOveflow ? this.modalSaveBodyOveflow : 'visible');
3719
+ }
3720
+
3721
+ return false;
3722
+
3723
+ },
3724
+ setModalTab: function(num)
3725
+ {
3726
+ $('.redactor_tab').hide();
3727
+ var tabs = $('#redactor_tabs a');
3728
+ tabs.removeClass('redactor_tabs_act');
3729
+ tabs.eq(num-1).addClass('redactor_tabs_act');
3730
+ $('#redactor_tab' + num).show();
3731
+ },
3732
+
3733
+ // UPLOAD
3734
+ uploadInit: function(element, options)
3735
+ {
3736
+ // Upload Options
3737
+ this.uploadOptions = {
3738
+ url: false,
3739
+ success: false,
3740
+ error: false,
3741
+ start: false,
3742
+ trigger: false,
3743
+ auto: false,
3744
+ input: false
3745
+ };
3746
+
3747
+ $.extend(this.uploadOptions, options);
3748
+
3749
+ // Test input or form
3750
+ if ($('#' + element).size() !== 0 && $('#' + element).get(0).tagName === 'INPUT')
3751
+ {
3752
+ this.uploadOptions.input = $('#' + element);
3753
+ this.element = $($('#' + element).get(0).form);
3754
+ }
3755
+ else
3756
+ {
3757
+ this.element = $('#' + element);
3758
+ }
3759
+
3760
+ this.element_action = this.element.attr('action');
3761
+
3762
+ // Auto or trigger
3763
+ if (this.uploadOptions.auto)
3764
+ {
3765
+ $(this.uploadOptions.input).change($.proxy(function()
3766
+ {
3767
+ this.element.submit(function(e) { return false; });
3768
+ this.uploadSubmit();
3769
+ }, this));
3770
+
3771
+ }
3772
+ else if (this.uploadOptions.trigger)
3773
+ {
3774
+ $('#' + this.uploadOptions.trigger).click($.proxy(this.uploadSubmit, this));
3775
+ }
3776
+ },
3777
+ uploadSubmit : function()
3778
+ {
3779
+ this.uploadForm(this.element, this.uploadFrame());
3780
+ },
3781
+ uploadFrame : function()
3782
+ {
3783
+ this.id = 'f' + Math.floor(Math.random() * 99999);
3784
+
3785
+ var d = this.document.createElement('div');
3786
+ var iframe = '<iframe style="display:none" id="'+this.id+'" name="'+this.id+'"></iframe>';
3787
+ d.innerHTML = iframe;
3788
+ $(d).appendTo("body");
3789
+
3790
+ // Start
3791
+ if (this.uploadOptions.start)
3792
+ {
3793
+ this.uploadOptions.start();
3794
+ }
3795
+
3796
+ $('#' + this.id).load($.proxy(this.uploadLoaded, this));
3797
+
3798
+ return this.id;
3799
+ },
3800
+ uploadForm : function(f, name)
3801
+ {
3802
+ if (this.uploadOptions.input)
3803
+ {
3804
+ var formId = 'redactorUploadForm' + this.id;
3805
+ var fileId = 'redactorUploadFile' + this.id;
3806
+ this.form = $('<form action="' + this.uploadOptions.url + '" method="POST" target="' + name + '" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
3807
+
3808
+ // append hidden fields
3809
+ if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object')
3810
+ {
3811
+ $.each(this.opts.uploadFields, $.proxy(function(k,v)
3812
+ {
3813
+ if (v.toString().indexOf('#') === 0)
3814
+ {
3815
+ v = $(v).val();
3816
+ }
3817
+
3818
+ var hidden = $('<input/>', {'type': "hidden", 'name': k, 'value': v});
3819
+ $(this.form).append(hidden);
3820
+
3821
+ }, this));
3822
+ }
3823
+
3824
+ var oldElement = this.uploadOptions.input;
3825
+ var newElement = $(oldElement).clone();
3826
+ $(oldElement).attr('id', fileId);
3827
+ $(oldElement).before(newElement);
3828
+ $(oldElement).appendTo(this.form);
3829
+ $(this.form).css('position', 'absolute');
3830
+ $(this.form).css('top', '-2000px');
3831
+ $(this.form).css('left', '-2000px');
3832
+ $(this.form).appendTo('body');
3833
+
3834
+ this.form.submit();
3835
+ }
3836
+ else
3837
+ {
3838
+ f.attr('target', name);
3839
+ f.attr('method', 'POST');
3840
+ f.attr('enctype', 'multipart/form-data');
3841
+ f.attr('action', this.uploadOptions.url);
3842
+
3843
+ this.element.submit();
3844
+ }
3845
+
3846
+ },
3847
+ uploadLoaded : function()
3848
+ {
3849
+ var i = $('#' + this.id)[0];
3850
+ var d;
3851
+
3852
+ if (i.contentDocument)
3853
+ {
3854
+ d = i.contentDocument;
3855
+ }
3856
+ else if (i.contentWindow)
3857
+ {
3858
+ d = i.contentWindow.document;
3859
+ }
3860
+ else
3861
+ {
3862
+ d = window.frames[this.id].document;
3863
+ }
3864
+
3865
+ // Success
3866
+ if (this.uploadOptions.success)
3867
+ {
3868
+ if (typeof d !== 'undefined')
3869
+ {
3870
+ // Remove bizarre <pre> tag wrappers around our json data:
3871
+ var rawString = d.body.innerHTML;
3872
+ var jsonString = rawString.match(/\{(.|\n)*\}/)[0];
3873
+ var json = $.parseJSON(jsonString);
3874
+
3875
+ if (typeof json.error == 'undefined')
3876
+ {
3877
+ this.uploadOptions.success(json);
3878
+ }
3879
+ else
3880
+ {
3881
+ this.uploadOptions.error(this, json);
3882
+ this.modalClose();
3883
+ }
3884
+ }
3885
+ else
3886
+ {
3887
+ alert('Upload failed!');
3888
+ this.modalClose();
3889
+ }
3890
+ }
3891
+
3892
+ this.element.attr('action', this.element_action);
3893
+ this.element.attr('target', '');
3894
+
3895
+ },
3896
+
3897
+ // UTILITY
3898
+ browser: function(browser)
3899
+ {
3900
+ var ua = navigator.userAgent.toLowerCase();
3901
+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
3902
+
3903
+ if (browser == 'version')
3904
+ {
3905
+ return match[2];
3906
+ }
3907
+
3908
+ if (browser == 'webkit')
3909
+ {
3910
+ return (match[1] == 'chrome' || match[1] == 'webkit');
3911
+ }
3912
+
3913
+ return match[1] == browser;
3914
+ },
3915
+ oldIE: function()
3916
+ {
3917
+ if (this.browser('msie') && parseInt(this.browser('version'), 10) < 9)
3918
+ {
3919
+ return true;
3920
+ }
3921
+
3922
+ return false;
3923
+ },
3924
+ outerHTML: function(s)
3925
+ {
3926
+ return $("<p>").append($(s).eq(0).clone()).html();
3927
+ },
3928
+ normalize: function(str)
3929
+ {
3930
+ return parseInt(str.replace('px',''), 10);
3931
+ },
3932
+ isMobile: function(ipad)
3933
+ {
3934
+ if (ipad === true && /(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent))
3935
+ {
3936
+ return true;
3937
+ }
3938
+ else if (/(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent))
3939
+ {
3940
+ return true;
3941
+ }
3942
+ else
3943
+ {
3944
+ return false;
3945
+ }
3946
+ }
3947
+
3948
+ };
3949
+
3950
+
3951
+ // API
3952
+ $.fn.getObject = function()
3953
+ {
3954
+ return this.data('redactor');
3955
+ };
3956
+
3957
+ $.fn.getEditor = function()
3958
+ {
3959
+ return this.data('redactor').$editor;
3960
+ };
3961
+
3962
+ $.fn.getCode = function()
3963
+ {
3964
+ return $.trim(this.data('redactor').getCode());
3965
+ };
3966
+
3967
+ $.fn.getText = function()
3968
+ {
3969
+ return this.data('redactor').$editor.text();
3970
+ };
3971
+
3972
+ $.fn.getSelected = function()
3973
+ {
3974
+ return this.data('redactor').getSelectedHtml();
3975
+ };
3976
+
3977
+ $.fn.setCode = function(html)
3978
+ {
3979
+ this.data('redactor').setCode(html);
3980
+ };
3981
+
3982
+ $.fn.insertHtml = function(html)
3983
+ {
3984
+ this.data('redactor').insertHtml(html);
3985
+ };
3986
+
3987
+ $.fn.destroyEditor = function()
3988
+ {
3989
+ this.each(function()
3990
+ {
3991
+ if (typeof $(this).data('redactor') != 'undefined')
3992
+ {
3993
+ $(this).data('redactor').destroy();
3994
+ $(this).removeData('redactor');
3995
+ }
3996
+ });
3997
+ };
3998
+
3999
+ $.fn.setFocus = function()
4000
+ {
4001
+ this.data('redactor').$editor.focus();
4002
+ };
4003
+
4004
+ $.fn.execCommand = function(cmd, param)
4005
+ {
4006
+ this.data('redactor').execCommand(cmd, param);
4007
+ };
4008
+
4009
+ })(jQuery);
4010
+
4011
+ /*
4012
+ Plugin Drag and drop Upload v1.0.2
4013
+ http://imperavi.com/
4014
+ Copyright 2012, Imperavi Inc.
4015
+ */
4016
+ (function($){
4017
+
4018
+ "use strict";
4019
+
4020
+ // Initialization
4021
+ $.fn.dragupload = function(options)
4022
+ {
4023
+ return this.each(function() {
4024
+ var obj = new Construct(this, options);
4025
+ obj.init();
4026
+ });
4027
+ };
4028
+
4029
+ // Options and variables
4030
+ function Construct(el, options) {
4031
+
4032
+ this.opts = $.extend({
4033
+
4034
+ url: false,
4035
+ success: false,
4036
+ error: false,
4037
+ preview: false,
4038
+ uploadFields: false,
4039
+
4040
+ text: RLANG.drop_file_here,
4041
+ atext: RLANG.or_choose
4042
+
4043
+ }, options);
4044
+
4045
+ this.$el = $(el);
4046
+ }
4047
+
4048
+ // Functionality
4049
+ Construct.prototype = {
4050
+ init: function()
4051
+ {
4052
+ if (navigator.userAgent.search("MSIE") === -1)
4053
+ {
4054
+ this.droparea = $('<div class="redactor_droparea"></div>');
4055
+ this.dropareabox = $('<div class="redactor_dropareabox">' + this.opts.text + '</div>');
4056
+ this.dropalternative = $('<div class="redactor_dropalternative">' + this.opts.atext + '</div>');
4057
+
4058
+ this.droparea.append(this.dropareabox);
4059
+
4060
+ this.$el.before(this.droparea);
4061
+ this.$el.before(this.dropalternative);
4062
+
4063
+ // drag over
4064
+ this.dropareabox.bind('dragover', $.proxy(function() { return this.ondrag(); }, this));
4065
+
4066
+ // drag leave
4067
+ this.dropareabox.bind('dragleave', $.proxy(function() { return this.ondragleave(); }, this));
4068
+
4069
+ var uploadProgress = $.proxy(function(e)
4070
+ {
4071
+ var percent = parseInt(e.loaded / e.total * 100, 10);
4072
+ this.dropareabox.text('Loading ' + percent + '%');
4073
+
4074
+ }, this);
4075
+
4076
+ var xhr = jQuery.ajaxSettings.xhr();
4077
+
4078
+ if (xhr.upload)
4079
+ {
4080
+ xhr.upload.addEventListener('progress', uploadProgress, false);
4081
+ }
4082
+
4083
+ var provider = function () { return xhr; };
4084
+
4085
+ // drop
4086
+ this.dropareabox.get(0).ondrop = $.proxy(function(event)
4087
+ {
4088
+ event.preventDefault();
4089
+
4090
+ this.dropareabox.removeClass('hover').addClass('drop');
4091
+
4092
+ var file = event.dataTransfer.files[0];
4093
+ var fd = new FormData();
4094
+
4095
+ // append hidden fields
4096
+ if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object')
4097
+ {
4098
+ $.each(this.opts.uploadFields, $.proxy(function(k,v)
4099
+ {
4100
+ if (v.toString().indexOf('#') === 0)
4101
+ {
4102
+ v = $(v).val();
4103
+ }
4104
+
4105
+ fd.append(k, v);
4106
+
4107
+ }, this));
4108
+ }
4109
+
4110
+ // append file data
4111
+ fd.append('file', file);
4112
+
4113
+ $.ajax({
4114
+ url: this.opts.url,
4115
+ dataType: 'html',
4116
+ data: fd,
4117
+ xhr: provider,
4118
+ cache: false,
4119
+ contentType: false,
4120
+ processData: false,
4121
+ type: 'POST',
4122
+ success: $.proxy(function(data)
4123
+ {
4124
+ var json = $.parseJSON(data);
4125
+
4126
+ if (typeof json.error == 'undefined')
4127
+ {
4128
+ this.opts.success(json);
4129
+ }
4130
+ else
4131
+ {
4132
+ this.opts.error(this, json);
4133
+ this.opts.success(false);
4134
+ }
4135
+
4136
+ }, this)
4137
+ });
4138
+
4139
+
4140
+ }, this);
4141
+ }
4142
+ },
4143
+ ondrag: function()
4144
+ {
4145
+ this.dropareabox.addClass('hover');
4146
+ return false;
4147
+ },
4148
+ ondragleave: function()
4149
+ {
4150
+ this.dropareabox.removeClass('hover');
4151
+ return false;
4152
+ }
4153
+ };
4154
+
4155
+ })(jQuery);
4156
+
4157
+
4158
+
4159
+ // Define: Linkify plugin from stackoverflow
4160
+ (function($){
4161
+
4162
+ "use strict";
4163
+
4164
+ var protocol = 'http://';
4165
+ var url1 = /(^|&lt;|\s)(www\..+?\..+?)(\s|&gt;|$)/g,
4166
+ url2 = /(^|&lt;|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|&gt;|$)/g,
4167
+
4168
+ linkifyThis = function ()
4169
+ {
4170
+ var childNodes = this.childNodes,
4171
+ i = childNodes.length;
4172
+ while(i--)
4173
+ {
4174
+ var n = childNodes[i];
4175
+ if (n.nodeType === 3)
4176
+ {
4177
+ var html = n.nodeValue;
4178
+ if (html)
4179
+ {
4180
+ html = html.replace(/&/g, '&amp;')
4181
+ .replace(/</g, '&lt;')
4182
+ .replace(/>/g, '&gt;')
4183
+ .replace(url1, '$1<a href="' + protocol + '$2">$2</a>$3')
4184
+ .replace(url2, '$1<a href="$2">$2</a>$5');
4185
+
4186
+ $(n).after(html).remove();
4187
+ }
4188
+ }
4189
+ else if (n.nodeType === 1 && !/^(a|button|textarea)$/i.test(n.tagName))
4190
+ {
4191
+ linkifyThis.call(n);
4192
+ }
4193
+ }
4194
+ };
4195
+
4196
+ $.fn.linkify = function ()
4197
+ {
4198
+ this.each(linkifyThis);
4199
+ };
4200
+
4201
+ })(jQuery);
4202
+
4203
+
4204
+ /* jQuery plugin textselect
4205
+ * version: 0.9
4206
+ * author: Josef Moravec, josef.moravec@gmail.com
4207
+ * updated: Imperavi Inc.
4208
+ *
4209
+ */
4210
+ eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('(5($){$.1.4.7={t:5(0,v){$(2).0("8",c);$(2).0("r",0);$(2).l(\'g\',$.1.4.7.b)},u:5(0){$(2).w(\'g\',$.1.4.7.b)},b:5(1){9 0=$(2).0("r");9 3=$.1.4.7.f(0).h();6(3!=\'\'){$(2).0("8",x);1.j="7";1.3=3;$.1.i.m(2,k)}},f:5(0){9 3=\'\';6(q.e){3=q.e()}o 6(d.e){3=d.e()}o 6(d.p){3=d.p.B().3}A 3}};$.1.4.a={t:5(0,v){$(2).0("n",0);$(2).0("8",c);$(2).l(\'g\',$.1.4.a.b);$(2).l(\'D\',$.1.4.a.s)},u:5(0){$(2).w(\'g\',$.1.4.a.b)},b:5(1){6($(2).0("8")){9 0=$(2).0("n");9 3=$.1.4.7.f(0).h();6(3==\'\'){$(2).0("8",c);1.j="a";$.1.i.m(2,k)}}},s:5(1){6($(2).0("8")){9 0=$(2).0("n");9 3=$.1.4.7.f(0).h();6((1.y=z)&&(3==\'\')){$(2).0("8",c);1.j="a";$.1.i.m(2,k)}}}}})(C);',40,40,'data|event|this|text|special|function|if|textselect|textselected|var|textunselect|handler|false|rdocument|getSelection|getSelectedText|mouseup|toString|handle|type|arguments|bind|apply|rttt|else|selection|rwindow|ttt|handlerKey|setup|teardown|namespaces|unbind|true|keyCode|27|return|createRange|jQuery|keyup'.split('|'),0,{}))