UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

232 lines (203 loc) 7.97 kB
define([ "dojo", "dijit", "dojox", "dijit/_editor/_Plugin", "dijit/_base/manager", "dijit/_editor/RichText", "dijit/form/Button", "dijit/Dialog", "dojox/html/format", "dojo/_base/connect", "dojo/_base/declare", "dojo/i18n", "dojo/string", "dojo/i18n!dojox/editor/plugins/nls/PasteFromWord", "dojo/i18n!dijit/nls/common", "dojo/i18n!dijit/_editor/nls/commands" ], function(dojo, dijit, dojox, _Plugin) { var PasteFromWord = dojo.declare("dojox.editor.plugins.PasteFromWord", _Plugin, { // summary: // This plugin provides PasteFromWord capability to the editor. When // clicked, a dialog opens with a spartan RichText instance to paste // word content into via the keyboard commands. The contents are // then filtered to remove word style classes and other meta-junk // that tends to cause issues. // iconClassPrefix: [const] String // The CSS class name for the button node is formed from `iconClassPrefix` // and `command` iconClassPrefix: "dijitAdditionalEditorIcon", // width: [public] String // The width to use for the rich text area in the copy/pate dialog, in px. Default is 400px. width: "400px", // height: [public] String // The height to use for the rich text area in the copy/pate dialog, in px. Default is 300px. height: "300px", _template: ["<div class='dijitPasteFromWordEmbeddedRTE'>", "<div style='width: ${width}; padding-top: 5px; padding-bottom: 5px;'>${instructions}</div>", "<div id='${uId}_rte' style='width: ${width}; height: ${height}'></div>", "<table style='width: ${width}' tabindex='-1'>", "<tbody>", "<tr>", "<td align='center'>", "<button type='button' dojoType='dijit.form.Button' id='${uId}_paste'>${paste}</button>", "&nbsp;", "<button type='button' dojoType='dijit.form.Button' id='${uId}_cancel'>${buttonCancel}</button>", "</td>", "</tr>", "</tbody>", "</table>", "</div>"].join(""), // _filters: [protected] Array // The filters is an array of regular expressions to try and strip out a lot // of style data MS Word likes to insert when pasting into a contentEditable. // Prettymuch all of it is junk and not good html. The hander is a place to put a function // for match handling. In most cases, it just handles it as empty string. But the option is // there for more complex handling. _filters: [ // Meta tags, link tags, and prefixed tags {regexp: /(<meta\s*[^>]*\s*>)|(<\s*link\s* href="file:[^>]*\s*>)|(<\/?\s*\w+:[^>]*\s*>)/gi, handler: ""}, // Style tags {regexp: /(?:<style([^>]*)>([\s\S]*?)<\/style>|<link\s+(?=[^>]*rel=['"]?stylesheet)([^>]*?href=(['"])([^>]*?)\4[^>\/]*)\/?>)/gi, handler: ""}, // MS class tags and comment tags. {regexp: /(class="Mso[^"]*")|(<!--(.|\s){1,}?-->)/gi, handler: ""}, // blank p tags {regexp: /(<p[^>]*>\s*(\&nbsp;|\u00A0)*\s*<\/p[^>]*>)|(<p[^>]*>\s*<font[^>]*>\s*(\&nbsp;|\u00A0)*\s*<\/\s*font\s*>\s<\/p[^>]*>)/ig, handler: ""}, // Strip out styles containing mso defs and margins, as likely added in IE and are not good to have as it mangles presentation. {regexp: /(style="[^"]*mso-[^;][^"]*")|(style="margin:\s*[^;"]*;")/gi, handler: ""}, // Scripts (if any) {regexp: /(<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>)|(<\s*script\b([^<>]|\s)*>?)|(<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>)/ig, handler: ""}, // Word 10 odd o:p tags. {regexp: /<(\/?)o\:p[^>]*>/gi, handler: ""} ], _initButton: function(){ // summary: // Over-ride for creation of the save button. this._filters = this._filters.slice(0); var strings = dojo.i18n.getLocalization("dojox.editor.plugins", "PasteFromWord"); dojo.mixin(strings, dojo.i18n.getLocalization("dijit", "common")); dojo.mixin(strings, dojo.i18n.getLocalization("dijit._editor", "commands")); this.button = new dijit.form.Button({ label: strings["pasteFromWord"], showLabel: false, iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "PasteFromWord", tabIndex: "-1", onClick: dojo.hitch(this, "_openDialog") }); this._uId = dijit.getUniqueId(this.editor.id); strings.uId = this._uId; strings.width = this.width || "400px"; strings.height = this.height || "300px"; this._dialog = new dijit.Dialog({title: strings["pasteFromWord"]}).placeAt(dojo.body()); this._dialog.set("content", dojo.string.substitute(this._template, strings)); // Make it translucent so we can fade in the window when the RTE is created. // the RTE has to be created 'visible, and this is a nice trick to make the creation // 'pretty'. dojo.style(dojo.byId(this._uId + "_rte"), "opacity", 0.001); // Link up the action buttons to perform the insert or cleanup. this.connect(dijit.byId(this._uId + "_paste"), "onClick", "_paste"); this.connect(dijit.byId(this._uId + "_cancel"), "onClick", "_cancel"); this.connect(this._dialog, "onHide", "_clearDialog"); }, updateState: function(){ // summary: // Over-ride for button state control for disabled to work. this.button.set("disabled", this.get("disabled")); }, setEditor: function(editor){ // summary: // Over-ride for the setting of the editor. // editor: Object // The editor to configure for this plugin to use. this.editor = editor; this._initButton(); }, _openDialog: function(){ // summary: // Function to trigger opening the copy dialog. // tags: // private this._dialog.show(); if(!this._rte){ // RTE hasn't been created yet, so we need to create it now that the // dialog is showing up. setTimeout(dojo.hitch(this, function() { this._rte = new dijit._editor.RichText({height: this.height || "300px"}, this._uId + "_rte"); this._rte.startup(); this._rte.onLoadDeferred.addCallback(dojo.hitch(this, function() { dojo.animateProperty({ node: this._rte.domNode, properties: { opacity: { start: 0.001, end: 1.0 } } }).play(); })); }), 100); } }, _paste: function(){ // summary: // Function to handle setting the contents of the copy from dialog // into the editor. // tags: // private // Gather the content and try to format it a bit (makes regexp cleanup simpler). // It also normalizes tag names and styles, so regexps are the same across browsers. var content = dojox.html.format.prettyPrint(this._rte.get("value")); //Close up the dialog and clear old content. this._dialog.hide(); // Apply all the filters to remove MS specific injected text. var i; for(i = 0; i < this._filters.length; i++){ var filter = this._filters[i]; content = content.replace(filter.regexp, filter.handler); } // Format it again to make sure it is reasonably formatted as // the regexp applies will have likely chewed up the formatting. content = dojox.html.format.prettyPrint(content); // Paste it in. this.editor.focus(); this.editor.execCommand("inserthtml", content); }, _cancel: function(){ // summary: // Function to handle cancelling setting the contents of the // copy from dialog into the editor. // tags: // private this._dialog.hide(); }, _clearDialog: function(){ // summary: // simple function to cleat the contents when hide is calledon dialog // copy from dialog into the editor. // tags: // private this._rte.set("value", ""); }, destroy: function(){ // sunnary: // Cleanup function // tags: // public if(this._rte){ this._rte.destroy(); } if(this._dialog){ this._dialog.destroyRecursive(); } delete this._dialog; delete this._rte; this.inherited(arguments); } }); // Register this plugin. dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ if(o.plugin){ return; } var name = o.args.name.toLowerCase(); if(name === "pastefromword"){ o.plugin = new PasteFromWord({ width: ("width" in o.args)?o.args.width:"400px", height: ("height" in o.args)?o.args.width:"300px" }); } }); return PasteFromWord; });