Merge branch '2.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / 3rdParty / redactor / plugins / wutil.js
1 if (!RedactorPlugins) var RedactorPlugins = {};
2
3 /**
4 * Provides utility methods extending $.Redactor
5 *
6 * @author Alexander Ebert
7 * @copyright 2001-2014 WoltLab GmbH
8 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
9 */
10 RedactorPlugins.wutil = {
11 /**
12 * autosave worker process
13 * @var WCF.PeriodicalExecuter
14 */
15 _autosaveWorker: null,
16
17 /**
18 * Initializes the RedactorPlugins.wutil plugin.
19 */
20 init: function() {
21 // convert HTML to BBCode upon submit
22 this.$source.parents('form').submit($.proxy(this.submit, this));
23
24 if (this.getOption('wautosave').active) {
25 this.autosaveEnable();
26
27 if (this.getOption('wautosave').saveOnInit || this.$source.data('saveOnInit')) {
28 this._saveTextToStorage();
29 }
30 else {
31 this.autosaveRestore();
32 }
33 }
34
35 // prevent Redactor's own autosave
36 this.setOption('autosave', false);
37
38 // disable autosave on destroy
39 var $mpDestroy = this.destroy;
40 var self = this;
41 this.destroy = function() {
42 self.autosaveDisable();
43 $mpDestroy.call(self);
44 };
45 },
46
47 /**
48 * Allows inserting of text contents in Redactor's source area.
49 *
50 * @param string string
51 * @return boolean
52 */
53 insertAtCaret: function(string) {
54 if (this.opts.visual) {
55 console.debug("insertAtCaret() failed: Editor is in WYSIWYG-mode.");
56 return false;
57 }
58
59 this.$source.focus();
60 var $position = this.$source.getCaret();
61 if ($position == -1) {
62 console.debug("insertAtCaret() failed: Source is not input[type=text], input[type=password] or textarea.");
63 }
64
65 var $content = this.$source.val();
66 $content = $content.substr(0, $position) + string + $content.substr($position);
67 this.$source.val($content);
68
69 return true;
70 },
71
72 /**
73 * Inserts content into the editor depending if it is in wysiwyg or plain mode. If 'plainValue' is
74 * null or undefined, the value from 'html' will be taken instead.
75 *
76 * @param string html
77 * @param string plainValue
78 */
79 insertDynamic: function(html, plainValue) {
80 if (this.inWysiwygMode()) {
81 this.insertHtml(html);
82 }
83 else {
84 if (plainValue === undefined || plainValue === null) {
85 plainValue = html;
86 }
87
88 this.insertAtCaret(plainValue);
89 }
90 },
91
92 /**
93 * Sets an option value after initialization.
94 *
95 * @param string key
96 * @param mixed value
97 */
98 setOption: function(key, value) {
99 this.opts[key] = value;
100 },
101
102 /**
103 * Reads an option value, returns null if key is unknown.
104 *
105 * @param string key
106 * @return mixed
107 */
108 getOption: function(key) {
109 if (this.opts[key]) {
110 return this.opts[key];
111 }
112
113 return null;
114 },
115
116 /**
117 * Returns true if editor is in source mode.
118 *
119 * @return boolean
120 */
121 inPlainMode: function() {
122 return !this.opts.visual;
123 },
124
125 /**
126 * Returns true if editor is in WYSIWYG mode.
127 *
128 * @return boolean
129 */
130 inWysiwygMode: function() {
131 return (this.opts.visual);
132 },
133
134 /**
135 * Replaces all ranges from the current selection with the provided one.
136 *
137 * @param DOMRange range
138 */
139 replaceRangesWith: function(range) {
140 getSelection().removeAllRanges();
141 getSelection().addRange(range);
142 },
143
144 /**
145 * Returns text using BBCodes.
146 *
147 * @return string
148 */
149 getText: function() {
150 if (this.inWysiwygMode()) {
151 this.toggle();
152
153 var $content = this.$source.val();
154
155 this.toggle();
156 return $content;
157 }
158
159 return this.$source.val();
160 },
161
162 /**
163 * Converts HTML to BBCode upon submit.
164 */
165 submit: function() {
166 if (this.inWysiwygMode()) {
167 this.toggle();
168
169 var $content = this.$source.val();
170
171 this.toggle();
172
173 this.$source.val($content);
174 }
175
176 this.autosavePurge();
177 },
178
179 /**
180 * Resets the editor's contents.
181 */
182 reset: function() {
183 if (this.inWysiwygMode()) {
184 this.$editor.empty();
185 this.sync();
186 }
187 else {
188 this.$source.val('');
189 }
190 },
191
192 /**
193 * Enables automatic saving every minute.
194 *
195 * @param string key
196 */
197 autosaveEnable: function(key) {
198 if (!this.getOption('wautosave').active) {
199 this.setOption('wautosave', {
200 active: true,
201 key: key
202 });
203 }
204
205 if (this._autosaveWorker === null) {
206 var self = this;
207 this._autosaveWorker = new WCF.PeriodicalExecuter($.proxy(this._saveTextToStorage, this), 60 * 1000);
208 }
209
210 return true;
211 },
212
213 /**
214 * Saves current editor text to local browser storage.
215 */
216 _saveTextToStorage: function() {
217 localStorage.setItem(this.getOption('wautosave').key, this.getText());
218 },
219
220 /**
221 * Disables automatic saving.
222 */
223 autosaveDisable: function() {
224 if (!this.getOption('wautosave').active) {
225 return false;
226 }
227
228 this._autosaveWorker.stop();
229 this._autosaveWorker = null;
230
231 this.setOption('wautosave', {
232 active: false,
233 key: ''
234 });
235
236 return true;
237 },
238
239 /**
240 * Attempts to purge saved text.
241 *
242 * @param string key
243 */
244 autosavePurge: function() {
245 localStorage.removeItem(this.getOption('wautosave').key);
246 },
247
248 /**
249 * Attempts to restore a saved text.
250 */
251 autosaveRestore: function() {
252 var $options = this.getOption('wautosave');
253 var $text = localStorage.getItem($options.key);
254 if ($text !== null) {
255 if (this.inWysiwygMode()) {
256 this.toggle(false);
257 this.$source.val($text);
258 this.toggle(false);
259 this.focusEnd();
260 }
261 else {
262 this.$source.val($text);
263 }
264
265 return true;
266 }
267
268 return false;
269 },
270
271 /**
272 * Replaces one button with a new one.
273 *
274 * @param string target
275 * @param string key
276 * @param string title
277 * @param object callback
278 * @param object dropdown
279 * @return jQuery
280 */
281 buttonReplace: function(target, key, title, callback, dropdown) {
282 var $target = this.buttonGet(target);
283
284 var $button = this.buttonAddAfter(target, key, title, callback, dropdown);
285 if ($target.parent().hasClass('separator')) {
286 $button.parent().addClass('separator');
287 }
288
289 $target.parent().remove();
290
291 return $button;
292 },
293
294 /**
295 * Removes the unicode zero-width space (0x200B).
296 *
297 * @param string string
298 * @return string
299 */
300 removeZeroWidthSpace: function(string) {
301 var $string = '';
302
303 for (var $i = 0, $length = string.length; $i < $length; $i++) {
304 var $byte = string.charCodeAt($i).toString(16);
305 if ($byte != '200b') {
306 $string += string[$i];
307 }
308 }
309
310 return $string;
311 },
312 };