source: Dev/trunk/src/client/dojox/editor/plugins/PasteFromWord.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 7.8 KB
Line 
1define([
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
20var 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                                                                "&nbsp;",
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*(\&nbsp;|\u00A0)*\s*<\/p[^>]*>)|(<p[^>]*>\s*<font[^>]*>\s*(\&nbsp;|\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.
219dojo.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
230return PasteFromWord;
231});
Note: See TracBrowser for help on using the repository browser.