]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/debian/missing-sources/framework/Web/Javascripts/source/tinymce-405/plugins/spellchecker/plugin.js
baculum: Add missing-sources directory in debian metadata structure
[bacula/bacula] / gui / baculum / debian / missing-sources / framework / Web / Javascripts / source / tinymce-405 / plugins / spellchecker / plugin.js
1 /**
2  * Compiled inline version. (Library mode)
3  */
4
5 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
6 /*globals $code */
7
8 (function(exports, undefined) {
9         "use strict";
10
11         var modules = {};
12
13         function require(ids, callback) {
14                 var module, defs = [];
15
16                 for (var i = 0; i < ids.length; ++i) {
17                         module = modules[ids[i]] || resolve(ids[i]);
18                         if (!module) {
19                                 throw 'module definition dependecy not found: ' + ids[i];
20                         }
21
22                         defs.push(module);
23                 }
24
25                 callback.apply(null, defs);
26         }
27
28         function define(id, dependencies, definition) {
29                 if (typeof id !== 'string') {
30                         throw 'invalid module definition, module id must be defined and be a string';
31                 }
32
33                 if (dependencies === undefined) {
34                         throw 'invalid module definition, dependencies must be specified';
35                 }
36
37                 if (definition === undefined) {
38                         throw 'invalid module definition, definition function must be specified';
39                 }
40
41                 require(dependencies, function() {
42                         modules[id] = definition.apply(null, arguments);
43                 });
44         }
45
46         function defined(id) {
47                 return !!modules[id];
48         }
49
50         function resolve(id) {
51                 var target = exports;
52                 var fragments = id.split(/[.\/]/);
53
54                 for (var fi = 0; fi < fragments.length; ++fi) {
55                         if (!target[fragments[fi]]) {
56                                 return;
57                         }
58
59                         target = target[fragments[fi]];
60                 }
61
62                 return target;
63         }
64
65         function expose(ids) {
66                 for (var i = 0; i < ids.length; i++) {
67                         var target = exports;
68                         var id = ids[i];
69                         var fragments = id.split(/[.\/]/);
70
71                         for (var fi = 0; fi < fragments.length - 1; ++fi) {
72                                 if (target[fragments[fi]] === undefined) {
73                                         target[fragments[fi]] = {};
74                                 }
75
76                                 target = target[fragments[fi]];
77                         }
78
79                         target[fragments[fragments.length - 1]] = modules[id];
80                 }
81         }
82
83 // Included from: js/tinymce/plugins/spellchecker/classes/DomTextMatcher.js
84
85 /**
86  * DomTextMatcher.js
87  *
88  * Copyright, Moxiecode Systems AB
89  * Released under LGPL License.
90  *
91  * License: http://www.tinymce.com/license
92  * Contributing: http://www.tinymce.com/contributing
93  */
94
95 /**
96  * This class logic for filtering text and matching words.
97  *
98  * @class tinymce.spellcheckerplugin.TextFilter
99  * @private
100  */
101 define("tinymce/spellcheckerplugin/DomTextMatcher", [], function() {
102         // Based on work developed by: James Padolsey http://james.padolsey.com
103         // released under UNLICENSE that is compatible with LGPL
104         // TODO: Handle contentEditable edgecase:
105         // <p>text<span contentEditable="false">text<span contentEditable="true">text</span>text</span>text</p>
106         return function(regex, node, schema) {
107                 var m, matches = [], text, count = 0, doc;
108                 var blockElementsMap, hiddenTextElementsMap, shortEndedElementsMap;
109
110                 doc = node.ownerDocument;
111                 blockElementsMap = schema.getBlockElements(); // H1-H6, P, TD etc
112                 hiddenTextElementsMap = schema.getWhiteSpaceElements(); // TEXTAREA, PRE, STYLE, SCRIPT
113                 shortEndedElementsMap = schema.getShortEndedElements(); // BR, IMG, INPUT
114
115                 function getMatchIndexes(m) {
116                         if (!m[0]) {
117                                 throw 'findAndReplaceDOMText cannot handle zero-length matches';
118                         }
119
120                         var index = m.index;
121
122                         return [index, index + m[0].length, [m[0]]];
123                 }
124
125                 function getText(node) {
126                         var txt;
127
128                         if (node.nodeType === 3) {
129                                 return node.data;
130                         }
131
132                         if (hiddenTextElementsMap[node.nodeName]) {
133                                 return '';
134                         }
135
136                         txt = '';
137
138                         if (blockElementsMap[node.nodeName] || shortEndedElementsMap[node.nodeName]) {
139                                 txt += '\n';
140                         }
141
142                         if ((node = node.firstChild)) {
143                                 do {
144                                         txt += getText(node);
145                                 } while ((node = node.nextSibling));
146                         }
147
148                         return txt;
149                 }
150
151                 function stepThroughMatches(node, matches, replaceFn) {
152                         var startNode, endNode, startNodeIndex,
153                                 endNodeIndex, innerNodes = [], atIndex = 0, curNode = node,
154                                 matchLocation = matches.shift(), matchIndex = 0;
155
156                         out: while (true) {
157                                 if (blockElementsMap[curNode.nodeName] || shortEndedElementsMap[curNode.nodeName]) {
158                                         atIndex++;
159                                 }
160
161                                 if (curNode.nodeType === 3) {
162                                         if (!endNode && curNode.length + atIndex >= matchLocation[1]) {
163                                                 // We've found the ending
164                                                 endNode = curNode;
165                                                 endNodeIndex = matchLocation[1] - atIndex;
166                                         } else if (startNode) {
167                                                 // Intersecting node
168                                                 innerNodes.push(curNode);
169                                         }
170
171                                         if (!startNode && curNode.length + atIndex > matchLocation[0]) {
172                                                 // We've found the match start
173                                                 startNode = curNode;
174                                                 startNodeIndex = matchLocation[0] - atIndex;
175                                         }
176
177                                         atIndex += curNode.length;
178                                 }
179
180                                 if (startNode && endNode) {
181                                         curNode = replaceFn({
182                                                 startNode: startNode,
183                                                 startNodeIndex: startNodeIndex,
184                                                 endNode: endNode,
185                                                 endNodeIndex: endNodeIndex,
186                                                 innerNodes: innerNodes,
187                                                 match: matchLocation[2],
188                                                 matchIndex: matchIndex
189                                         });
190
191                                         // replaceFn has to return the node that replaced the endNode
192                                         // and then we step back so we can continue from the end of the
193                                         // match:
194                                         atIndex -= (endNode.length - endNodeIndex);
195                                         startNode = null;
196                                         endNode = null;
197                                         innerNodes = [];
198                                         matchLocation = matches.shift();
199                                         matchIndex++;
200
201                                         if (!matchLocation) {
202                                                 break; // no more matches
203                                         }
204                                 } else if (!hiddenTextElementsMap[curNode.nodeName] && curNode.firstChild) {
205                                         // Move down
206                                         curNode = curNode.firstChild;
207                                         continue;
208                                 } else if (curNode.nextSibling) {
209                                         // Move forward:
210                                         curNode = curNode.nextSibling;
211                                         continue;
212                                 }
213
214                                 // Move forward or up:
215                                 while (true) {
216                                         if (curNode.nextSibling) {
217                                                 curNode = curNode.nextSibling;
218                                                 break;
219                                         } else if (curNode.parentNode !== node) {
220                                                 curNode = curNode.parentNode;
221                                         } else {
222                                                 break out;
223                                         }
224                                 }
225                         }
226                 }
227
228                 /**
229                 * Generates the actual replaceFn which splits up text nodes
230                 * and inserts the replacement element.
231                 */
232                 function genReplacer(nodeName) {
233                         var makeReplacementNode;
234
235                         if (typeof nodeName != 'function') {
236                                 var stencilNode = nodeName.nodeType ? nodeName : doc.createElement(nodeName);
237
238                                 makeReplacementNode = function(fill, matchIndex) {
239                                         var clone = stencilNode.cloneNode(false);
240
241                                         clone.setAttribute('data-mce-index', matchIndex);
242
243                                         if (fill) {
244                                                 clone.appendChild(doc.createTextNode(fill));
245                                         }
246
247                                         return clone;
248                                 };
249                         } else {
250                                 makeReplacementNode = nodeName;
251                         }
252
253                         return function replace(range) {
254                                 var before, after, parentNode, startNode = range.startNode,
255                                         endNode = range.endNode, matchIndex = range.matchIndex;
256
257                                 if (startNode === endNode) {
258                                         var node = startNode;
259
260                                         parentNode = node.parentNode;
261                                         if (range.startNodeIndex > 0) {
262                                                 // Add `before` text node (before the match)
263                                                 before = doc.createTextNode(node.data.substring(0, range.startNodeIndex));
264                                                 parentNode.insertBefore(before, node);
265                                         }
266
267                                         // Create the replacement node:
268                                         var el = makeReplacementNode(range.match[0], matchIndex);
269                                         parentNode.insertBefore(el, node);
270                                         if (range.endNodeIndex < node.length) {
271                                                 // Add `after` text node (after the match)
272                                                 after = doc.createTextNode(node.data.substring(range.endNodeIndex));
273                                                 parentNode.insertBefore(after, node);
274                                         }
275
276                                         node.parentNode.removeChild(node);
277
278                                         return el;
279                                 } else {
280                                         // Replace startNode -> [innerNodes...] -> endNode (in that order)
281                                         before = doc.createTextNode(startNode.data.substring(0, range.startNodeIndex));
282                                         after = doc.createTextNode(endNode.data.substring(range.endNodeIndex));
283                                         var elA = makeReplacementNode(startNode.data.substring(range.startNodeIndex), matchIndex);
284                                         var innerEls = [];
285
286                                         for (var i = 0, l = range.innerNodes.length; i < l; ++i) {
287                                                 var innerNode = range.innerNodes[i];
288                                                 var innerEl = makeReplacementNode(innerNode.data, matchIndex);
289                                                 innerNode.parentNode.replaceChild(innerEl, innerNode);
290                                                 innerEls.push(innerEl);
291                                         }
292
293                                         var elB = makeReplacementNode(endNode.data.substring(0, range.endNodeIndex), matchIndex);
294
295                                         parentNode = startNode.parentNode;
296                                         parentNode.insertBefore(before, startNode);
297                                         parentNode.insertBefore(elA, startNode);
298                                         parentNode.removeChild(startNode);
299
300                                         parentNode = endNode.parentNode;
301                                         parentNode.insertBefore(elB, endNode);
302                                         parentNode.insertBefore(after, endNode);
303                                         parentNode.removeChild(endNode);
304
305                                         return elB;
306                                 }
307                         };
308                 }
309
310                 text = getText(node);
311                 if (text && regex.global) {
312                         while ((m = regex.exec(text))) {
313                                 matches.push(getMatchIndexes(m));
314                         }
315                 }
316
317                 function filter(callback) {
318                         var filteredMatches = [];
319
320                         each(function(match, i) {
321                                 if (callback(match, i)) {
322                                         filteredMatches.push(match);
323                                 }
324                         });
325
326                         matches = filteredMatches;
327
328                         /*jshint validthis:true*/
329                         return this;
330                 }
331
332                 function each(callback) {
333                         for (var i = 0, l = matches.length; i < l; i++) {
334                                 if (callback(matches[i], i) === false) {
335                                         break;
336                                 }
337                         }
338
339                         /*jshint validthis:true*/
340                         return this;
341                 }
342
343                 function mark(replacementNode) {
344                         if (matches.length) {
345                                 count = matches.length;
346                                 stepThroughMatches(node, matches, genReplacer(replacementNode));
347                         }
348
349                         /*jshint validthis:true*/
350                         return this;
351                 }
352
353                 return {
354                         text: text,
355                         count: count,
356                         matches: matches,
357                         each: each,
358                         filter: filter,
359                         mark: mark
360                 };
361         };
362 });
363
364 // Included from: js/tinymce/plugins/spellchecker/classes/Plugin.js
365
366 /**
367  * Plugin.js
368  *
369  * Copyright, Moxiecode Systems AB
370  * Released under LGPL License.
371  *
372  * License: http://www.tinymce.com/license
373  * Contributing: http://www.tinymce.com/contributing
374  */
375
376 /*jshint camelcase:false */
377
378 /**
379  * This class contains all core logic for the spellchecker plugin.
380  *
381  * @class tinymce.spellcheckerplugin.Plugin
382  * @private
383  */
384 define("tinymce/spellcheckerplugin/Plugin", [
385         "tinymce/spellcheckerplugin/DomTextMatcher",
386         "tinymce/PluginManager",
387         "tinymce/util/Tools",
388         "tinymce/ui/Menu",
389         "tinymce/dom/DOMUtils",
390         "tinymce/util/JSONRequest",
391         "tinymce/util/URI"
392 ], function(DomTextMatcher, PluginManager, Tools, Menu, DOMUtils, JSONRequest, URI) {
393         PluginManager.add('spellchecker', function(editor, url) {
394                 var lastSuggestions, started, suggestionsMenu, settings = editor.settings;
395
396                 function isEmpty(obj) {
397                         /*jshint unused:false*/
398                         for (var name in obj) {
399                                 return false;
400                         }
401
402                         return true;
403                 }
404
405                 function showSuggestions(target, word) {
406                         var items = [], suggestions = lastSuggestions[word];
407
408                         Tools.each(suggestions, function(suggestion) {
409                                 items.push({
410                                         text: suggestion,
411                                         onclick: function() {
412                                                 editor.insertContent(suggestion);
413                                                 checkIfFinished();
414                                         }
415                                 });
416                         });
417
418                         items.push.apply(items, [
419                                 {text: '-'},
420
421                                 {text: 'Ignore', onclick: function() {
422                                         ignoreWord(target, word);
423                                 }},
424
425                                 {text: 'Ignore all', onclick: function() {
426                                         ignoreWord(target, word, true);
427                                 }},
428
429                                 {text: 'Finish', onclick: finish}
430                         ]);
431
432                         // Render menu
433                         suggestionsMenu = new Menu({
434                                 items: items,
435                                 context: 'contextmenu',
436                                 onautohide: function(e) {
437                                         if (e.target.className.indexOf('spellchecker') != -1) {
438                                                 e.preventDefault();
439                                         }
440                                 },
441                                 onhide: function() {
442                                         suggestionsMenu.remove();
443                                         suggestionsMenu = null;
444                                 }
445                         });
446
447                         suggestionsMenu.renderTo(document.body);
448
449                         // Position menu
450                         var pos = DOMUtils.DOM.getPos(editor.getContentAreaContainer());
451                         var targetPos = editor.dom.getPos(target);
452
453                         pos.x += targetPos.x;
454                         pos.y += targetPos.y;
455
456                         suggestionsMenu.moveTo(pos.x, pos.y + target.offsetHeight);
457                 }
458
459                 function spellcheck() {
460                         var textFilter, words = [], uniqueWords = {};
461
462                         if (started) {
463                                 finish();
464                                 return;
465                         }
466
467                         started = true;
468
469                         function doneCallback(suggestions) {
470                                 editor.setProgressState(false);
471
472                                 if (isEmpty(suggestions)) {
473                                         editor.windowManager.alert('No misspellings found');
474                                         started = false;
475                                         return;
476                                 }
477
478                                 lastSuggestions = suggestions;
479
480                                 textFilter.filter(function(match) {
481                                         return !!suggestions[match[2][0]];
482                                 }).mark(editor.dom.create('span', {
483                                         "class": 'mce-spellchecker-word',
484                                         "data-mce-bogus": 1
485                                 }));
486
487                                 textFilter = null;
488                                 editor.fire('SpellcheckStart');
489                         }
490
491                         // Regexp for finding word specific characters this will split words by
492                         // spaces, quotes, copy right characters etc. It's escaped with unicode characters
493                         // to make it easier to output scripts on servers using different encodings
494                         // so if you add any characters outside the 128 byte range make sure to escape it
495                         var nonWordSeparatorCharacters = editor.getParam('spellchecker_wordchar_pattern') || new RegExp("[^" +
496                                 "\\s!\"#$%&()*+,-./:;<=>?@[\\]^_{|}`" +
497                                 "\u00a7\u00a9\u00ab\u00ae\u00b1\u00b6\u00b7\u00b8\u00bb" +
498                                 "\u00bc\u00bd\u00be\u00bf\u00d7\u00f7\u00a4\u201d\u201c\u201e" +
499                         "]+", "g");
500
501                         // Find all words and make an unique words array
502                         textFilter = new DomTextMatcher(nonWordSeparatorCharacters, editor.getBody(), editor.schema).each(function(match) {
503                                 var word = match[2][0];
504
505                                 // TODO: Fix so it remembers correctly spelled words
506                                 if (!uniqueWords[word]) {
507                                         // Ignore numbers and single character words
508                                         if (/^\d+$/.test(word) || word.length == 1) {
509                                                 return;
510                                         }
511
512                                         words.push(word);
513                                         uniqueWords[word] = true;
514                                 }
515                         });
516
517                         function defaultSpellcheckCallback(method, words, doneCallback) {
518                                 JSONRequest.sendRPC({
519                                         url: new URI(url).toAbsolute(settings.spellchecker_rpc_url),
520                                         method: method,
521                                         params: {
522                                                 lang: settings.spellchecker_language || "en",
523                                                 words: words
524                                         },
525                                         success: function(result) {
526                                                 doneCallback(result);
527                                         },
528                                         error: function(error, xhr) {
529                                                 if (error == "JSON Parse error.") {
530                                                         error = "Non JSON response:" + xhr.responseText;
531                                                 } else {
532                                                         error = "Error: " + error;
533                                                 }
534
535                                                 editor.windowManager.alert(error);
536                                                 editor.setProgressState(false);
537                                                 textFilter = null;
538                                                 started = false;
539                                         }
540                                 });
541                         }
542
543                         editor.setProgressState(true);
544
545                         var spellCheckCallback = settings.spellchecker_callback || defaultSpellcheckCallback;
546                         spellCheckCallback("spellcheck", words, doneCallback);
547                 }
548
549                 function checkIfFinished() {
550                         if (!editor.dom.select('span.mce-spellchecker-word').length) {
551                                 finish();
552                         }
553                 }
554
555                 function unwrap(node) {
556                         var parentNode = node.parentNode;
557                         parentNode.insertBefore(node.firstChild, node);
558                         node.parentNode.removeChild(node);
559                 }
560
561                 function ignoreWord(target, word, all) {
562                         if (all) {
563                                 Tools.each(editor.dom.select('span.mce-spellchecker-word'), function(item) {
564                                         var text = item.innerText || item.textContent;
565
566                                         if (text == word) {
567                                                 unwrap(item);
568                                         }
569                                 });
570                         } else {
571                                 unwrap(target);
572                         }
573
574                         checkIfFinished();
575                 }
576
577                 function finish() {
578                         var i, nodes, node;
579
580                         started = false;
581                         node = editor.getBody();
582                         nodes = node.getElementsByTagName('span');
583                         i = nodes.length;
584                         while (i--) {
585                                 node = nodes[i];
586                                 if (node.getAttribute('data-mce-index')) {
587                                         unwrap(node);
588                                 }
589                         }
590
591                         editor.fire('SpellcheckEnd');
592                 }
593
594                 function selectMatch(index) {
595                         var nodes, i, spanElm, spanIndex = -1, startContainer, endContainer;
596
597                         index = "" + index;
598                         nodes = editor.getBody().getElementsByTagName("span");
599                         for (i = 0; i < nodes.length; i++) {
600                                 spanElm = nodes[i];
601                                 if (spanElm.className == "mce-spellchecker-word") {
602                                         spanIndex = spanElm.getAttribute('data-mce-index');
603                                         if (spanIndex === index) {
604                                                 spanIndex = index;
605
606                                                 if (!startContainer) {
607                                                         startContainer = spanElm.firstChild;
608                                                 }
609
610                                                 endContainer = spanElm.firstChild;
611                                         }
612
613                                         if (spanIndex !== index && endContainer) {
614                                                 break;
615                                         }
616                                 }
617                         }
618
619                         var rng = editor.dom.createRng();
620                         rng.setStart(startContainer, 0);
621                         rng.setEnd(endContainer, endContainer.length);
622                         editor.selection.setRng(rng);
623
624                         return rng;
625                 }
626
627                 editor.on('click', function(e) {
628                         if (e.target.className == "mce-spellchecker-word") {
629                                 e.preventDefault();
630
631                                 var rng = selectMatch(e.target.getAttribute('data-mce-index'));
632                                 showSuggestions(e.target, rng.toString());
633                         }
634                 });
635
636                 editor.addMenuItem('spellchecker', {
637                         text: 'Spellcheck',
638                         context: 'tools',
639                         onclick: spellcheck,
640                         selectable: true,
641                         onPostRender: function() {
642                                 var self = this;
643
644                                 editor.on('SpellcheckStart SpellcheckEnd', function() {
645                                         self.active(started);
646                                 });
647                         }
648                 });
649
650                 editor.addButton('spellchecker', {
651                         tooltip: 'Spellcheck',
652                         onclick: spellcheck,
653                         onPostRender: function() {
654                                 var self = this;
655
656                                 editor.on('SpellcheckStart SpellcheckEnd', function() {
657                                         self.active(started);
658                                 });
659                         }
660                 });
661
662                 editor.on('remove', function() {
663                         if (suggestionsMenu) {
664                                 suggestionsMenu.remove();
665                                 suggestionsMenu = null;
666                         }
667                 });
668         });
669 });
670
671 expose(["tinymce/spellcheckerplugin/DomTextMatcher","tinymce/spellcheckerplugin/Plugin"]);
672 })(this);