|
1 /** |
|
2 * plugin.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 */ |
|
10 |
|
11 /*global tinymce:true */ |
|
12 |
|
13 tinymce.PluginManager.add('visualchars', function(editor) { |
|
14 var self = this, state; |
|
15 |
|
16 function toggleVisualChars(addBookmark) { |
|
17 var node, nodeList, i, body = editor.getBody(), nodeValue, selection = editor.selection, div, bookmark; |
|
18 var charMap, visualCharsRegExp; |
|
19 |
|
20 charMap = { |
|
21 '\u00a0': 'nbsp', |
|
22 '\u00ad': 'shy' |
|
23 }; |
|
24 |
|
25 function wrapCharWithSpan(value) { |
|
26 return '<span data-mce-bogus="1" class="mce-' + charMap[value] + '">' + value + '</span>'; |
|
27 } |
|
28 |
|
29 function compileCharMapToRegExp() { |
|
30 var key, regExp = ''; |
|
31 |
|
32 for (key in charMap) { |
|
33 regExp += key; |
|
34 } |
|
35 |
|
36 return new RegExp('[' + regExp + ']', 'g'); |
|
37 } |
|
38 |
|
39 function compileCharMapToCssSelector() { |
|
40 var key, selector = ''; |
|
41 |
|
42 for (key in charMap) { |
|
43 if (selector) { |
|
44 selector += ','; |
|
45 } |
|
46 |
|
47 selector += 'span.mce-' + charMap[key]; |
|
48 } |
|
49 |
|
50 return selector; |
|
51 } |
|
52 |
|
53 state = !state; |
|
54 self.state = state; |
|
55 editor.fire('VisualChars', {state: state}); |
|
56 visualCharsRegExp = compileCharMapToRegExp(); |
|
57 |
|
58 if (addBookmark) { |
|
59 bookmark = selection.getBookmark(); |
|
60 } |
|
61 |
|
62 if (state) { |
|
63 nodeList = []; |
|
64 tinymce.walk(body, function(n) { |
|
65 if (n.nodeType == 3 && n.nodeValue && visualCharsRegExp.test(n.nodeValue)) { |
|
66 nodeList.push(n); |
|
67 } |
|
68 }, 'childNodes'); |
|
69 |
|
70 for (i = 0; i < nodeList.length; i++) { |
|
71 nodeValue = nodeList[i].nodeValue; |
|
72 nodeValue = nodeValue.replace(visualCharsRegExp, wrapCharWithSpan); |
|
73 |
|
74 div = editor.dom.create('div', null, nodeValue); |
|
75 while ((node = div.lastChild)) { |
|
76 editor.dom.insertAfter(node, nodeList[i]); |
|
77 } |
|
78 |
|
79 editor.dom.remove(nodeList[i]); |
|
80 } |
|
81 } else { |
|
82 nodeList = editor.dom.select(compileCharMapToCssSelector(), body); |
|
83 |
|
84 for (i = nodeList.length - 1; i >= 0; i--) { |
|
85 editor.dom.remove(nodeList[i], 1); |
|
86 } |
|
87 } |
|
88 |
|
89 selection.moveToBookmark(bookmark); |
|
90 } |
|
91 |
|
92 function toggleActiveState() { |
|
93 var self = this; |
|
94 |
|
95 editor.on('VisualChars', function(e) { |
|
96 self.active(e.state); |
|
97 }); |
|
98 } |
|
99 |
|
100 editor.addCommand('mceVisualChars', toggleVisualChars); |
|
101 |
|
102 editor.addButton('visualchars', { |
|
103 title: 'Show invisible characters', |
|
104 cmd: 'mceVisualChars', |
|
105 onPostRender: toggleActiveState |
|
106 }); |
|
107 |
|
108 editor.addMenuItem('visualchars', { |
|
109 text: 'Show invisible characters', |
|
110 cmd: 'mceVisualChars', |
|
111 onPostRender: toggleActiveState, |
|
112 selectable: true, |
|
113 context: 'view', |
|
114 prependToContext: true |
|
115 }); |
|
116 |
|
117 editor.on('beforegetcontent', function(e) { |
|
118 if (state && e.format != 'raw' && !e.draft) { |
|
119 state = true; |
|
120 toggleVisualChars(false); |
|
121 } |
|
122 }); |
|
123 }); |