1 | define([ |
---|
2 | "dojo", |
---|
3 | "dijit", |
---|
4 | "dojox", |
---|
5 | "dijit/_editor/_Plugin", |
---|
6 | "dijit/_base/manager", |
---|
7 | "dijit/_editor/RichText", |
---|
8 | "dijit/form/Button", |
---|
9 | "dijit/Dialog", |
---|
10 | "dojox/html/format", |
---|
11 | "dojo/_base/connect", |
---|
12 | "dojo/_base/declare", |
---|
13 | "dojo/i18n", |
---|
14 | "dojo/string", |
---|
15 | "dojo/i18n!dojox/editor/plugins/nls/PasteFromWord", |
---|
16 | "dojo/i18n!dijit/nls/common", |
---|
17 | "dojo/i18n!dijit/_editor/nls/commands" |
---|
18 | ], function(dojo, dijit, dojox, _Plugin) { |
---|
19 | |
---|
20 | var PasteFromWord = dojo.declare("dojox.editor.plugins.PasteFromWord", _Plugin, { |
---|
21 | // summary: |
---|
22 | // This plugin provides PasteFromWord capability to the editor. When |
---|
23 | // clicked, a dialog opens with a spartan RichText instance to paste |
---|
24 | // word content into via the keyboard commands. The contents are |
---|
25 | // then filtered to remove word style classes and other meta-junk |
---|
26 | // that tends to cause issues. |
---|
27 | |
---|
28 | // iconClassPrefix: [const] String |
---|
29 | // The CSS class name for the button node is formed from `iconClassPrefix` |
---|
30 | // and `command` |
---|
31 | iconClassPrefix: "dijitAdditionalEditorIcon", |
---|
32 | |
---|
33 | // width: [public] String |
---|
34 | // The width to use for the rich text area in the copy/pate dialog, in px. Default is 400px. |
---|
35 | width: "400px", |
---|
36 | |
---|
37 | // height: [public] String |
---|
38 | // The height to use for the rich text area in the copy/pate dialog, in px. Default is 300px. |
---|
39 | height: "300px", |
---|
40 | |
---|
41 | _template: ["<div class='dijitPasteFromWordEmbeddedRTE'>", |
---|
42 | "<div style='width: ${width}; padding-top: 5px; padding-bottom: 5px;'>${instructions}</div>", |
---|
43 | "<div id='${uId}_rte' style='width: ${width}; height: ${height}'></div>", |
---|
44 | "<table style='width: ${width}' tabindex='-1'>", |
---|
45 | "<tbody>", |
---|
46 | "<tr>", |
---|
47 | "<td align='center'>", |
---|
48 | "<button type='button' dojoType='dijit.form.Button' id='${uId}_paste'>${paste}</button>", |
---|
49 | " ", |
---|
50 | "<button type='button' dojoType='dijit.form.Button' id='${uId}_cancel'>${buttonCancel}</button>", |
---|
51 | "</td>", |
---|
52 | "</tr>", |
---|
53 | "</tbody>", |
---|
54 | "</table>", |
---|
55 | "</div>"].join(""), |
---|
56 | |
---|
57 | // _filters: [protected] Array |
---|
58 | // The filters is an array of regular expressions to try and strip out a lot |
---|
59 | // of style data MS Word likes to insert when pasting into a contentEditable. |
---|
60 | // Prettymuch all of it is junk and not good html. The hander is a place to put a function |
---|
61 | // for match handling. In most cases, it just handles it as empty string. But the option is |
---|
62 | // there for more complex handling. |
---|
63 | _filters: [ |
---|
64 | // Meta tags, link tags, and prefixed tags |
---|
65 | {regexp: /(<meta\s*[^>]*\s*>)|(<\s*link\s* href="file:[^>]*\s*>)|(<\/?\s*\w+:[^>]*\s*>)/gi, handler: ""}, |
---|
66 | // Style tags |
---|
67 | {regexp: /(?:<style([^>]*)>([\s\S]*?)<\/style>|<link\s+(?=[^>]*rel=['"]?stylesheet)([^>]*?href=(['"])([^>]*?)\4[^>\/]*)\/?>)/gi, handler: ""}, |
---|
68 | // MS class tags and comment tags. |
---|
69 | {regexp: /(class="Mso[^"]*")|(<!--(.|\s){1,}?-->)/gi, handler: ""}, |
---|
70 | // blank p tags |
---|
71 | {regexp: /(<p[^>]*>\s*(\ |\u00A0)*\s*<\/p[^>]*>)|(<p[^>]*>\s*<font[^>]*>\s*(\ |\u00A0)*\s*<\/\s*font\s*>\s<\/p[^>]*>)/ig, handler: ""}, |
---|
72 | // Strip out styles containing mso defs and margins, as likely added in IE and are not good to have as it mangles presentation. |
---|
73 | {regexp: /(style="[^"]*mso-[^;][^"]*")|(style="margin:\s*[^;"]*;")/gi, handler: ""}, |
---|
74 | // Scripts (if any) |
---|
75 | {regexp: /(<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>)|(<\s*script\b([^<>]|\s)*>?)|(<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>)/ig, handler: ""}, |
---|
76 | // Word 10 odd o:p tags. |
---|
77 | {regexp: /<(\/?)o\:p[^>]*>/gi, handler: ""} |
---|
78 | ], |
---|
79 | |
---|
80 | _initButton: function(){ |
---|
81 | // summary: |
---|
82 | // Over-ride for creation of the save button. |
---|
83 | this._filters = this._filters.slice(0); |
---|
84 | |
---|
85 | var strings = dojo.i18n.getLocalization("dojox.editor.plugins", "PasteFromWord"); |
---|
86 | dojo.mixin(strings, dojo.i18n.getLocalization("dijit", "common")); |
---|
87 | dojo.mixin(strings, dojo.i18n.getLocalization("dijit._editor", "commands")); |
---|
88 | this.button = new dijit.form.Button({ |
---|
89 | label: strings["pasteFromWord"], |
---|
90 | showLabel: false, |
---|
91 | iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "PasteFromWord", |
---|
92 | tabIndex: "-1", |
---|
93 | onClick: dojo.hitch(this, "_openDialog") |
---|
94 | }); |
---|
95 | |
---|
96 | this._uId = dijit.getUniqueId(this.editor.id); |
---|
97 | |
---|
98 | strings.uId = this._uId; |
---|
99 | strings.width = this.width || "400px"; |
---|
100 | strings.height = this.height || "300px"; |
---|
101 | |
---|
102 | this._dialog = new dijit.Dialog({title: strings["pasteFromWord"]}).placeAt(dojo.body()); |
---|
103 | this._dialog.set("content", dojo.string.substitute(this._template, strings)); |
---|
104 | |
---|
105 | // Make it translucent so we can fade in the window when the RTE is created. |
---|
106 | // the RTE has to be created 'visible, and this is a nice trick to make the creation |
---|
107 | // 'pretty'. |
---|
108 | dojo.style(dojo.byId(this._uId + "_rte"), "opacity", 0.001); |
---|
109 | |
---|
110 | // Link up the action buttons to perform the insert or cleanup. |
---|
111 | this.connect(dijit.byId(this._uId + "_paste"), "onClick", "_paste"); |
---|
112 | this.connect(dijit.byId(this._uId + "_cancel"), "onClick", "_cancel"); |
---|
113 | this.connect(this._dialog, "onHide", "_clearDialog"); |
---|
114 | }, |
---|
115 | |
---|
116 | updateState: function(){ |
---|
117 | // summary: |
---|
118 | // Over-ride for button state control for disabled to work. |
---|
119 | this.button.set("disabled", this.get("disabled")); |
---|
120 | }, |
---|
121 | |
---|
122 | setEditor: function(editor){ |
---|
123 | // summary: |
---|
124 | // Over-ride for the setting of the editor. |
---|
125 | // editor: Object |
---|
126 | // The editor to configure for this plugin to use. |
---|
127 | this.editor = editor; |
---|
128 | this._initButton(); |
---|
129 | }, |
---|
130 | |
---|
131 | _openDialog: function(){ |
---|
132 | // summary: |
---|
133 | // Function to trigger opening the copy dialog. |
---|
134 | // tags: |
---|
135 | // private |
---|
136 | this._dialog.show(); |
---|
137 | if(!this._rte){ |
---|
138 | // RTE hasn't been created yet, so we need to create it now that the |
---|
139 | // dialog is showing up. |
---|
140 | setTimeout(dojo.hitch(this, function() { |
---|
141 | this._rte = new dijit._editor.RichText({height: this.height || "300px"}, this._uId + "_rte"); |
---|
142 | this._rte.startup(); |
---|
143 | this._rte.onLoadDeferred.addCallback(dojo.hitch(this, function() { |
---|
144 | dojo.animateProperty({ |
---|
145 | node: this._rte.domNode, properties: { opacity: { start: 0.001, end: 1.0 } } |
---|
146 | }).play(); |
---|
147 | })); |
---|
148 | }), 100); |
---|
149 | } |
---|
150 | }, |
---|
151 | |
---|
152 | _paste: function(){ |
---|
153 | // summary: |
---|
154 | // Function to handle setting the contents of the copy from dialog |
---|
155 | // into the editor. |
---|
156 | // tags: |
---|
157 | // private |
---|
158 | |
---|
159 | // Gather the content and try to format it a bit (makes regexp cleanup simpler). |
---|
160 | // It also normalizes tag names and styles, so regexps are the same across browsers. |
---|
161 | var content = dojox.html.format.prettyPrint(this._rte.get("value")); |
---|
162 | |
---|
163 | //Close up the dialog and clear old content. |
---|
164 | this._dialog.hide(); |
---|
165 | |
---|
166 | // Apply all the filters to remove MS specific injected text. |
---|
167 | var i; |
---|
168 | for(i = 0; i < this._filters.length; i++){ |
---|
169 | var filter = this._filters[i]; |
---|
170 | content = content.replace(filter.regexp, filter.handler); |
---|
171 | } |
---|
172 | |
---|
173 | // Format it again to make sure it is reasonably formatted as |
---|
174 | // the regexp applies will have likely chewed up the formatting. |
---|
175 | content = dojox.html.format.prettyPrint(content); |
---|
176 | |
---|
177 | // Paste it in. |
---|
178 | this.editor.focus(); |
---|
179 | this.editor.execCommand("inserthtml", content); |
---|
180 | }, |
---|
181 | |
---|
182 | _cancel: function(){ |
---|
183 | // summary: |
---|
184 | // Function to handle cancelling setting the contents of the |
---|
185 | // copy from dialog into the editor. |
---|
186 | // tags: |
---|
187 | // private |
---|
188 | this._dialog.hide(); |
---|
189 | }, |
---|
190 | |
---|
191 | _clearDialog: function(){ |
---|
192 | // summary: |
---|
193 | // simple function to cleat the contents when hide is calledon dialog |
---|
194 | // copy from dialog into the editor. |
---|
195 | // tags: |
---|
196 | // private |
---|
197 | this._rte.set("value", ""); |
---|
198 | }, |
---|
199 | |
---|
200 | destroy: function(){ |
---|
201 | // sunnary: |
---|
202 | // Cleanup function |
---|
203 | // tags: |
---|
204 | // public |
---|
205 | if(this._rte){ |
---|
206 | this._rte.destroy(); |
---|
207 | } |
---|
208 | if(this._dialog){ |
---|
209 | this._dialog.destroyRecursive(); |
---|
210 | } |
---|
211 | delete this._dialog; |
---|
212 | delete this._rte; |
---|
213 | this.inherited(arguments); |
---|
214 | } |
---|
215 | |
---|
216 | }); |
---|
217 | |
---|
218 | // Register this plugin. |
---|
219 | dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ |
---|
220 | if(o.plugin){ return; } |
---|
221 | var name = o.args.name.toLowerCase(); |
---|
222 | if(name === "pastefromword"){ |
---|
223 | o.plugin = new PasteFromWord({ |
---|
224 | width: ("width" in o.args)?o.args.width:"400px", |
---|
225 | height: ("height" in o.args)?o.args.width:"300px" |
---|
226 | }); |
---|
227 | } |
---|
228 | }); |
---|
229 | |
---|
230 | return PasteFromWord; |
---|
231 | }); |
---|