]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/debian/missing-sources/framework/Web/Javascripts/source/tinymce-405/plugins/paste/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 / paste / 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/paste/classes/Clipboard.js
84
85 /**
86  * Clipboard.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 contains logic for getting HTML contents out of the clipboard.
97  *
98  * @class tinymce.pasteplugin.Clipboard
99  * @private
100  */
101 define("tinymce/pasteplugin/Clipboard", [
102         "tinymce/Env",
103         "tinymce/util/Tools",
104         "tinymce/util/VK"
105 ], function(Env, Tools, VK) {
106         function hasClipboardData() {
107                 // Gecko is excluded until the fix: https://bugzilla.mozilla.org/show_bug.cgi?id=850663
108                 return !Env.gecko && (("ClipboardEvent" in window) || (Env.webkit && "FocusEvent" in window));
109         }
110
111         return function(editor) {
112                 var self = this, plainTextPasteTime;
113
114                 function now() {
115                         return new Date().getTime();
116                 }
117
118                 function isPasteKeyEvent(e) {
119                         // Ctrl+V or Shift+Insert
120                         return (VK.metaKeyPressed(e) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45);
121                 }
122
123                 function innerText(elm) {
124                         return elm.innerText || elm.textContent;
125                 }
126
127                 function shouldPasteAsPlainText() {
128                         return now() - plainTextPasteTime < 100 || self.pasteFormat == "text";
129                 }
130
131                 // TODO: Move this to a class?
132                 function process(content, items) {
133                         Tools.each(items, function(v) {
134                                 if (v.constructor == RegExp) {
135                                         content = content.replace(v, '');
136                                 } else {
137                                         content = content.replace(v[0], v[1]);
138                                 }
139                         });
140
141                         return content;
142                 }
143
144                 function processHtml(html) {
145                         var args = editor.fire('PastePreProcess', {content: html});
146
147                         html = args.content;
148
149                         // Remove all data images from paste for example from Gecko
150                         if (!editor.settings.paste_data_images) {
151                                 html = html.replace(/<img src=\"data:image[^>]+>/g, '');
152                         }
153
154                         if (editor.settings.paste_remove_styles || (editor.settings.paste_remove_styles_if_webkit !== false && Env.webkit)) {
155                                 html = html.replace(/ style=\"[^\"]+\"/g, '');
156                         }
157
158                         if (!args.isDefaultPrevented()) {
159                                 editor.insertContent(html);
160                         }
161                 }
162
163                 function processText(text) {
164                         text = editor.dom.encode(text).replace(/\r\n/g, '\n');
165
166                         var startBlock = editor.dom.getParent(editor.selection.getStart(), editor.dom.isBlock);
167
168                         if ((startBlock && /^(PRE|DIV)$/.test(startBlock.nodeName)) || !editor.settings.forced_root_block) {
169                                 text = process(text, [
170                                         [/\n/g, "<br>"]
171                                 ]);
172                         } else {
173                                 text = process(text, [
174                                         [/\n\n/g, "</p><p>"],
175                                         [/^(.*<\/p>)(<p>)$/, '<p>$1'],
176                                         [/\n/g, "<br />"]
177                                 ]);
178                         }
179
180                         var args = editor.fire('PastePreProcess', {content: text});
181
182                         if (!args.isDefaultPrevented()) {
183                                 editor.insertContent(args.content);
184                         }
185                 }
186
187                 function createPasteBin() {
188                         var scrollTop = editor.dom.getViewPort().y;
189
190                         // Create a pastebin and move the selection into the bin
191                         var pastebinElm = editor.dom.add(editor.getBody(), 'div', {
192                                 contentEditable: false,
193                                 "data-mce-bogus": "1",
194                                 style: 'position: absolute; top: ' + scrollTop + 'px; left: 0; width: 1px; height: 1px; overflow: hidden'
195                         }, '<div contentEditable="true" data-mce-bogus="1">X</div>');
196
197                         editor.dom.bind(pastebinElm, 'beforedeactivate focusin focusout', function(e) {
198                                 e.stopPropagation();
199                         });
200
201                         return pastebinElm;
202                 }
203
204                 function removePasteBin(pastebinElm) {
205                         editor.dom.unbind(pastebinElm);
206                         editor.dom.remove(pastebinElm);
207                 }
208
209                 editor.on('keydown', function(e) {
210                         // Shift+Ctrl+V
211                         if (VK.metaKeyPressed(e) && e.shiftKey && e.keyCode == 86) {
212                                 plainTextPasteTime = now();
213                         }
214                 });
215
216                 // Use Clipboard API if it's available
217                 if (hasClipboardData()) {
218                         editor.on('paste', function(e) {
219                                 var clipboardData = e.clipboardData;
220
221                                 function processByContentType(contentType, processFunc) {
222                                         for (var ti = 0; ti < clipboardData.types.length; ti++) {
223                                                 if (clipboardData.types[ti] == contentType) {
224                                                         processFunc(clipboardData.getData(contentType));
225                                                         //clipboardData.items[ti].getAsString(processFunc);
226                                                         return true;
227                                                 }
228                                         }
229                                 }
230
231                                 if (clipboardData) {
232                                         e.preventDefault();
233
234                                         if (shouldPasteAsPlainText()) {
235                                                 // First look for HTML then look for plain text
236                                                 if (!processByContentType('text/plain', processText)) {
237                                                         processByContentType('text/html', processHtml);
238                                                 }
239                                         } else {
240                                                 // First look for HTML then look for plain text
241                                                 if (!processByContentType('text/html', processHtml)) {
242                                                         processByContentType('text/plain', processText);
243                                                 }
244                                         }
245                                 }
246                         });
247                 } else {
248                         if (Env.ie) {
249                                 var keyPasteTime = 0;
250
251                                 editor.on('keydown', function(e) {
252                                         if (isPasteKeyEvent(e) && !e.isDefaultPrevented()) {
253                                                 // Prevent undoManager keydown handler from making an undo level with the pastebin in it
254                                                 e.stopImmediatePropagation();
255
256                                                 var pastebinElm = createPasteBin();
257                                                 keyPasteTime = now();
258
259                                                 editor.dom.bind(pastebinElm, 'paste', function() {
260                                                         setTimeout(function() {
261                                                                 editor.selection.setRng(lastRng);
262                                                                 removePasteBin(pastebinElm);
263
264                                                                 if (shouldPasteAsPlainText()) {
265                                                                         processText(innerText(pastebinElm.firstChild));
266                                                                 } else {
267                                                                         processHtml(pastebinElm.firstChild.innerHTML);
268                                                                 }
269                                                         }, 0);
270                                                 });
271
272                                                 var lastRng = editor.selection.getRng();
273                                                 pastebinElm.firstChild.focus();
274                                                 pastebinElm.firstChild.innerText = '';
275                                         }
276                                 });
277
278                                 // Explorer fallback
279                                 editor.on('init', function() {
280                                         var dom = editor.dom;
281
282                                         // Use a different method if the paste was made without using the keyboard
283                                         // for example using the browser menu items
284                                         editor.dom.bind(editor.getBody(), 'paste', function(e) {
285                                                 if (now() - keyPasteTime > 100) {
286                                                         var gotPasteEvent, pastebinElm = createPasteBin();
287
288                                                         e.preventDefault();
289
290                                                         dom.bind(pastebinElm, 'paste', function(e) {
291                                                                 e.stopPropagation();
292                                                                 gotPasteEvent = true;
293                                                         });
294
295                                                         var lastRng = editor.selection.getRng();
296
297                                                         // Select the container
298                                                         var rng = dom.doc.body.createTextRange();
299                                                         rng.moveToElementText(pastebinElm.firstChild);
300                                                         rng.execCommand('Paste');
301                                                         removePasteBin(pastebinElm);
302
303                                                         if (!gotPasteEvent) {
304                                                                 editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
305                                                                 return;
306                                                         }
307
308                                                         editor.selection.setRng(lastRng);
309
310                                                         if (shouldPasteAsPlainText()) {
311                                                                 processText(innerText(pastebinElm.firstChild));
312                                                         } else {
313                                                                 processHtml(pastebinElm.firstChild.innerHTML);
314                                                         }
315                                                 }
316                                         });
317                                 });
318                         } else {
319                                 editor.on('init', function() {
320                                         editor.dom.bind(editor.getBody(), 'paste', function(e) {
321                                                 e.preventDefault();
322                                                 editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
323                                         });
324                                 });
325
326                                 // Old Gecko/WebKit/Opera fallback
327                                 editor.on('keydown', function(e) {
328                                         if (isPasteKeyEvent(e) && !e.isDefaultPrevented()) {
329                                                 // Prevent undoManager keydown handler from making an undo level with the pastebin in it
330                                                 e.stopImmediatePropagation();
331
332                                                 var pastebinElm = createPasteBin();
333                                                 var lastRng = editor.selection.getRng();
334
335                                                 editor.selection.select(pastebinElm, true);
336
337                                                 editor.dom.bind(pastebinElm, 'paste', function(e) {
338                                                         e.stopPropagation();
339
340                                                         setTimeout(function() {
341                                                                 removePasteBin(pastebinElm);
342                                                                 editor.lastRng = lastRng;
343                                                                 editor.selection.setRng(lastRng);
344
345                                                                 var pastebinContents = pastebinElm.firstChild;
346
347                                                                 // Remove last BR Safari on Mac adds trailing BR
348                                                                 if (pastebinContents.lastChild && pastebinContents.lastChild.nodeName == 'BR') {
349                                                                         pastebinContents.removeChild(pastebinContents.lastChild);
350                                                                 }
351
352                                                                 if (shouldPasteAsPlainText()) {
353                                                                         processText(innerText(pastebinContents));
354                                                                 } else {
355                                                                         processHtml(pastebinContents.innerHTML);
356                                                                 }
357                                                         }, 0);
358                                                 });
359                                         }
360                                 });
361                         }
362
363                         // Prevent users from dropping data images on Gecko
364                         if (!editor.settings.paste_data_images) {
365                                 editor.on('drop', function(e) {
366                                         var dataTransfer = e.dataTransfer;
367
368                                         if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
369                                                 e.preventDefault();
370                                         }
371                                 });
372                         }
373                 }
374
375                 // Block all drag/drop events
376                 if (editor.paste_block_drop) {
377                         editor.on('dragend dragover draggesture dragdrop drop drag', function(e) {
378                                 e.preventDefault();
379                                 e.stopPropagation();
380                         });
381                 }
382
383                 this.paste = processHtml;
384                 this.pasteText = processText;
385         };
386 });
387
388 // Included from: js/tinymce/plugins/paste/classes/WordFilter.js
389
390 /**
391  * WordFilter.js
392  *
393  * Copyright, Moxiecode Systems AB
394  * Released under LGPL License.
395  *
396  * License: http://www.tinymce.com/license
397  * Contributing: http://www.tinymce.com/contributing
398  */
399
400 /**
401  * This class parses word HTML into proper TinyMCE markup.
402  *
403  * @class tinymce.pasteplugin.Quirks
404  * @private
405  */
406 define("tinymce/pasteplugin/WordFilter", [
407         "tinymce/util/Tools",
408         "tinymce/html/DomParser",
409         "tinymce/html/Schema",
410         "tinymce/html/Serializer",
411         "tinymce/html/Node"
412 ], function(Tools, DomParser, Schema, Serializer, Node) {
413         return function(editor) {
414                 var each = Tools.each;
415
416                 editor.on('PastePreProcess', function(e) {
417                         var content = e.content, retainStyleProperties, validStyles;
418
419                         retainStyleProperties = editor.settings.paste_retain_style_properties;
420                         if (retainStyleProperties) {
421                                 validStyles = Tools.makeMap(retainStyleProperties);
422                         }
423
424                         function process(items) {
425                                 each(items, function(v) {
426                                         if (v.constructor == RegExp) {
427                                                 content = content.replace(v, '');
428                                         } else {
429                                                 content = content.replace(v[0], v[1]);
430                                         }
431                                 });
432                         }
433
434                         /**
435                          * Converts fake bullet and numbered lists to real semantic OL/UL.
436                          *
437                          * @param {tinymce.html.Node} node Root node to convert children of.
438                          */
439                         function convertFakeListsToProperLists(node) {
440                                 var currentListNode, prevListNode, lastLevel = 1;
441
442                                 function convertParagraphToLi(paragraphNode, listStartTextNode, listName, start) {
443                                         var level = paragraphNode._listLevel || lastLevel;
444
445                                         // Handle list nesting
446                                         if (level != lastLevel) {
447                                                 if (level < lastLevel) {
448                                                         // Move to parent list
449                                                         if (currentListNode) {
450                                                                 currentListNode = currentListNode.parent.parent;
451                                                         }
452                                                 } else {
453                                                         // Create new list
454                                                         prevListNode = currentListNode;
455                                                         currentListNode = null;
456                                                 }
457                                         }
458
459                                         if (!currentListNode || currentListNode.name != listName) {
460                                                 prevListNode = prevListNode || currentListNode;
461                                                 currentListNode = new Node(listName, 1);
462
463                                                 if (start > 1) {
464                                                         currentListNode.attr('start', '' + start);
465                                                 }
466
467                                                 paragraphNode.wrap(currentListNode);
468                                         } else {
469                                                 currentListNode.append(paragraphNode);
470                                         }
471
472                                         paragraphNode.name = 'li';
473                                         listStartTextNode.value = '';
474
475                                         var nextNode = listStartTextNode.next;
476                                         if (nextNode && nextNode.type == 3) {
477                                                 nextNode.value = nextNode.value.replace(/^\u00a0+/, '');
478                                         }
479
480                                         // Append list to previous list if it exists
481                                         if (level > lastLevel && prevListNode) {
482                                                 prevListNode.lastChild.append(currentListNode);
483                                         }
484
485                                         lastLevel = level;
486                                 }
487
488                                 var paragraphs = node.getAll('p');
489
490                                 for (var i = 0; i < paragraphs.length; i++) {
491                                         node = paragraphs[i];
492
493                                         if (node.name == 'p' && node.firstChild) {
494                                                 // Find first text node in paragraph
495                                                 var nodeText = '';
496                                                 var listStartTextNode = node.firstChild;
497
498                                                 while (listStartTextNode) {
499                                                         nodeText = listStartTextNode.value;
500                                                         if (nodeText) {
501                                                                 break;
502                                                         }
503
504                                                         listStartTextNode = listStartTextNode.firstChild;
505                                                 }
506
507                                                 // Detect unordered lists look for bullets
508                                                 if (/^\s*[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*$/.test(nodeText)) {
509                                                         convertParagraphToLi(node, listStartTextNode, 'ul');
510                                                         continue;
511                                                 }
512
513                                                 // Detect ordered lists 1., a. or ixv.
514                                                 if (/^\s*\w+\./.test(nodeText)) {
515                                                         // Parse OL start number
516                                                         var matches = /([0-9])\./.exec(nodeText);
517                                                         var start = 1;
518                                                         if (matches) {
519                                                                 start = parseInt(matches[1], 10);
520                                                         }
521
522                                                         convertParagraphToLi(node, listStartTextNode, 'ol', start);
523                                                         continue;
524                                                 }
525
526                                                 currentListNode = null;
527                                         }
528                                 }
529                         }
530
531                         function filterStyles(node, styleValue) {
532                                 // Parse out list indent level for lists
533                                 if (node.name === 'p') {
534                                         var matches = /mso-list:\w+ \w+([0-9]+)/.exec(styleValue);
535
536                                         if (matches) {
537                                                 node._listLevel = parseInt(matches[1], 10);
538                                         }
539                                 }
540
541                                 if (editor.getParam("paste_retain_style_properties", "none")) {
542                                         var outputStyle = "";
543
544                                         Tools.each(editor.dom.parseStyle(styleValue), function(value, name) {
545                                                 // Convert various MS styles to W3C styles
546                                                 switch (name) {
547                                                         case "horiz-align":
548                                                                 name = "text-align";
549                                                                 return;
550
551                                                         case "vert-align":
552                                                                 name = "vertical-align";
553                                                                 return;
554
555                                                         case "font-color":
556                                                         case "mso-foreground":
557                                                                 name = "color";
558                                                                 return;
559
560                                                         case "mso-background":
561                                                         case "mso-highlight":
562                                                                 name = "background";
563                                                                 break;
564                                                 }
565
566                                                 // Output only valid styles
567                                                 if (retainStyleProperties == "all" || (validStyles && validStyles[name])) {
568                                                         outputStyle += name + ':' + value + ';';
569                                                 }
570                                         });
571
572                                         if (outputStyle) {
573                                                 return outputStyle;
574                                         }
575                                 }
576
577                                 return null;
578                         }
579
580                         if (editor.settings.paste_enable_default_filters === false) {
581                                 return;
582                         }
583
584                         // Detect is the contents is Word junk HTML
585                         if (/class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i.test(e.content)) {
586                                 e.wordContent = true; // Mark it for other processors
587
588                                 // Remove basic Word junk
589                                 process([
590                                         // Word comments like conditional comments etc
591                                         /<!--[\s\S]+?-->/gi,
592
593                                         // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content,
594                                         // MS Office namespaced tags, and a few other tags
595                                         /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
596
597                                         // Convert <s> into <strike> for line-though
598                                         [/<(\/?)s>/gi, "<$1strike>"],
599
600                                         // Replace nsbp entites to char since it's easier to handle
601                                         [/&nbsp;/gi, "\u00a0"],
602
603                                         // Convert <span style="mso-spacerun:yes">___</span> to string of alternating
604                                         // breaking/non-breaking spaces of same length
605                                         [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
606                                                 function(str, spaces) {
607                                                         return (spaces.length > 0) ?
608                                                                 spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : "";
609                                                 }
610                                         ]
611                                 ]);
612
613                                 // Setup strict schema
614                                 var schema = new Schema({
615                                         valid_elements: '@[style],-strong/b,-em/i,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-table,' +
616                                                                 '-tr,-td[colspan|rowspan],-th,-thead,-tfoot,-tbody,-a[!href],sub,sup,strike'
617                                 });
618
619                                 // Parse HTML into DOM structure
620                                 var domParser = new DomParser({}, schema);
621
622                                 // Filte element style attributes
623                                 domParser.addAttributeFilter('style', function(nodes) {
624                                         var i = nodes.length, node;
625
626                                         while (i--) {
627                                                 node = nodes[i];
628                                                 node.attr('style', filterStyles(node, node.attr('style')));
629
630                                                 // Remove pointess spans
631                                                 if (node.name == 'span' && !node.attributes.length) {
632                                                         node.unwrap();
633                                                 }
634                                         }
635                                 });
636
637                                 // Parse into DOM structure
638                                 var rootNode = domParser.parse(content);
639
640                                 // Process DOM
641                                 convertFakeListsToProperLists(rootNode);
642
643                                 // Serialize DOM back to HTML
644                                 e.content = new Serializer({}, schema).serialize(rootNode);
645                         }
646                 });
647         };
648 });
649
650 // Included from: js/tinymce/plugins/paste/classes/Quirks.js
651
652 /**
653  * Quirks.js
654  *
655  * Copyright, Moxiecode Systems AB
656  * Released under LGPL License.
657  *
658  * License: http://www.tinymce.com/license
659  * Contributing: http://www.tinymce.com/contributing
660  */
661
662 /**
663  * This class contains various fixes for browsers. These issues can not be feature
664  * detected since we have no direct control over the clipboard. However we might be able
665  * to remove some of these fixes once the browsers gets updated/fixed.
666  *
667  * @class tinymce.pasteplugin.Quirks
668  * @private
669  */
670 define("tinymce/pasteplugin/Quirks", [
671         "tinymce/Env",
672         "tinymce/util/Tools"
673 ], function(Env, Tools) {
674         "use strict";
675
676         return function(editor) {
677                 var explorerBlocksRegExp;
678
679                 function addPreProcessFilter(filterFunc) {
680                         editor.on('PastePreProcess', function(e) {
681                                 e.content = filterFunc(e.content);
682                         });
683                 }
684
685                 function process(content, items) {
686                         Tools.each(items, function(v) {
687                                 if (v.constructor == RegExp) {
688                                         content = content.replace(v, '');
689                                 } else {
690                                         content = content.replace(v[0], v[1]);
691                                 }
692                         });
693
694                         return content;
695                 }
696
697                 /**
698                  * Removes WebKit fragment comments and converted-space spans.
699                  *
700                  * This:
701                  *   <!--StartFragment-->a<span class="Apple-converted-space">&nbsp;</span>b<!--EndFragment-->
702                  *
703                  * Becomes:
704                  *   a&nbsp;b
705                  */
706                 function removeWebKitFragments(html) {
707                         html = process(html, [
708                                 /^[\s\S]*<!--StartFragment-->|<!--EndFragment-->[\s\S]*$/g,        // WebKit fragment
709                                 [/<span class="Apple-converted-space">\u00a0<\/span>/g, '\u00a0'], // WebKit &nbsp;
710                                 /<br>$/                                                                                                                    // Traling BR elements
711                         ]);
712
713                         return html;
714                 }
715
716                 /**
717                  * Removes BR elements after block elements. IE9 has a nasty bug where it puts a BR element after each
718                  * block element when pasting from word. This removes those elements.
719                  *
720                  * This:
721                  *  <p>a</p><br><p>b</p>
722                  *
723                  * Becomes:
724                  *  <p>a</p><p>b</p>
725                  */
726                 function removeExplorerBrElementsAfterBlocks(html) {
727                         // Produce block regexp based on the block elements in schema
728                         if (!explorerBlocksRegExp) {
729                                 var blockElements = [];
730
731                                 Tools.each(editor.schema.getBlockElements(), function(block, blockName) {
732                                         blockElements.push(blockName);
733                                 });
734
735                                 explorerBlocksRegExp = new RegExp(
736                                         '(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?(' + blockElements.join('|') + ')[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*',
737                                         'g'
738                                 );
739                         }
740
741                         // Remove BR:s from: <BLOCK>X</BLOCK><BR>
742                         html = process(html, [
743                                 [explorerBlocksRegExp, '$1']
744                         ]);
745
746                         // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
747                         html = process(html, [
748                                 [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
749                                 [/<br>/g, ' '],            // Replace single br elements with space since they are word wrap BR:s
750                                 [/<BR><BR>/g, '<br>']      // Replace back the double brs but into a single BR
751                         ]);
752
753                         return html;
754                 }
755
756                 // Sniff browsers and apply fixes since we can't feature detect
757                 if (Env.webkit) {
758                         addPreProcessFilter(removeWebKitFragments);
759                 }
760
761                 if (Env.ie) {
762                         addPreProcessFilter(removeExplorerBrElementsAfterBlocks);
763                 }
764         };
765 });
766
767 // Included from: js/tinymce/plugins/paste/classes/Plugin.js
768
769 /**
770  * Plugin.js
771  *
772  * Copyright, Moxiecode Systems AB
773  * Released under LGPL License.
774  *
775  * License: http://www.tinymce.com/license
776  * Contributing: http://www.tinymce.com/contributing
777  */
778
779 /**
780  * This class contains the tinymce plugin logic for the paste plugin.
781  *
782  * @class tinymce.pasteplugin.Plugin
783  * @private
784  */
785 define("tinymce/pasteplugin/Plugin", [
786         "tinymce/PluginManager",
787         "tinymce/pasteplugin/Clipboard",
788         "tinymce/pasteplugin/WordFilter",
789         "tinymce/pasteplugin/Quirks"
790 ], function(PluginManager, Clipboard, WordFilter, Quirks) {
791         var userIsInformed;
792
793         PluginManager.add('paste', function(editor) {
794                 var self = this, clipboard;
795
796                 function togglePlainTextPaste() {
797                         if (clipboard.pasteFormat == "text") {
798                                 this.active(false);
799                                 clipboard.pasteFormat = "html";
800                         } else {
801                                 clipboard.pasteFormat = "text";
802                                 this.active(true);
803
804                                 if (!userIsInformed) {
805                                         editor.windowManager.alert(
806                                                 'Paste is now in plain text mode. Contents will now ' +
807                                                 'be pasted as plain text until you toggle this option off.'
808                                         );
809
810                                         userIsInformed = true;
811                                 }
812                         }
813                 }
814
815                 self.clipboard = clipboard = new Clipboard(editor);
816                 self.quirks = new Quirks(editor);
817                 self.wordFilter = new WordFilter(editor);
818
819                 if (editor.settings.paste_as_text) {
820                         self.clipboard.pasteFormat = "text";
821                 }
822
823                 editor.addCommand('mceInsertClipboardContent', function(ui, value) {
824                         if (value.content) {
825                                 self.clipboard.paste(value.content);
826                         }
827
828                         if (value.text) {
829                                 self.clipboard.pasteText(value.text);
830                         }
831                 });
832
833                 editor.addButton('pastetext', {
834                         icon: 'pastetext',
835                         tooltip: 'Paste as text',
836                         onclick: togglePlainTextPaste,
837                         active: self.clipboard.pasteFormat == "text"
838                 });
839
840                 editor.addMenuItem('pastetext', {
841                         text: 'Paste as text',
842                         selectable: true,
843                         active: clipboard.pasteFormat,
844                         onclick: togglePlainTextPaste
845                 });
846         });
847 });
848
849 expose(["tinymce/pasteplugin/Clipboard","tinymce/pasteplugin/WordFilter","tinymce/pasteplugin/Quirks","tinymce/pasteplugin/Plugin"]);
850 })(this);