redde 0.1.13 → 0.1.14

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