| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- /*
- * TinyMCE Writing Improvement Tool Plugin
- * Author: Raphael Mudge (raffi@automattic.com)
- *
- * http://www.afterthedeadline.com
- *
- * Distributed under the LGPL
- *
- * Derived from:
- * $Id: editor_plugin_src.js 425 2007-11-21 15:17:39Z spocke $
- *
- * @author Moxiecode
- * @copyright Copyright (C) 2004-2008, Moxiecode Systems AB, All rights reserved.
- *
- * Moxiecode Spell Checker plugin released under the LGPL with TinyMCE
- */
- /* jshint onevar: false, sub: true, devel: true, loopfunc: true */
- /* global tinymce, AtDCore, AtD_proofread_click_count */
- (function()
- {
- var each = tinymce.each, DOM = tinymce.DOM, core;
- function getLang( key, defaultStr ) {
- return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultStr;
- }
- tinymce.create('tinymce.plugins.AfterTheDeadlinePlugin',
- {
- getInfo : function()
- {
- return {
- longname : 'After The Deadline',
- author : 'Raphael Mudge',
- authorurl : 'http://blog.afterthedeadline.com',
- infourl : 'http://www.afterthedeadline.com',
- version : tinymce.majorVersion + '.' + tinymce.minorVersion
- };
- },
- /* initializes the functions used by the AtD Core UI Module */
- initAtDCore : function(editor/*, plugin*/)
- {
- var core = new AtDCore();
- core.map = each;
- core.getAttrib = function(node, key)
- {
- return editor.dom.getAttrib(node, key);
- };
- core.findSpans = function(parent)
- {
- if (!parent) {
- return editor.dom.select('span');
- } else {
- return editor.dom.select('span', parent);
- }
- };
- core.hasClass = function(node, className)
- {
- return editor.dom.hasClass(node, className);
- };
- core.contents = function(node)
- {
- return node.childNodes;
- };
- core.replaceWith = function(old_node, new_node)
- {
- return editor.dom.replace(new_node, old_node);
- };
- core.create = function(node_html)
- {
- return editor.dom.create('span', { 'class': 'mceItemHidden' }, node_html);
- };
- core.removeParent = function(node)
- {
- editor.dom.remove(node, 1);
- return node;
- };
- core.remove = function(node)
- {
- editor.dom.remove(node);
- };
- core.setIgnoreStrings(editor.getParam('atd_ignore_strings', [] ).join(','));
- core.showTypes(editor.getParam('atd_show_types', ''));
- return core;
- },
- /* called when the plugin is initialized */
- init : function(ed, url)
- {
- if ( typeof(AtDCore) === 'undefined' ) {
- return;
- }
- var plugin = this;
- var editor = ed;
- this.url = url;
- this.editor = ed;
-
- core = ed.core = this.initAtDCore(editor, plugin);
- /* look at the atd_ignore variable and put that stuff into a hash */
- var ignore = tinymce.util.Cookie.getHash('atd_ignore');
- if (!ignore) {
- ignore = {};
- }
- /* add a command to request a document check and process the results. */
- editor.addCommand('mceWritingImprovementTool', function(callback)
- {
- /* checks if a global var for click stats exists and increments it if it does... */
- if (typeof AtD_proofread_click_count !== 'undefined') {
- AtD_proofread_click_count++;
- }
- /* create the nifty spinny thing that says "hizzo, I'm doing something fo realz" */
- plugin.editor.setProgressState(1);
- /* remove the previous errors */
- plugin._removeWords();
- /* send request to our service */
- plugin.sendRequest('checkDocument', ed.getContent({ format: 'raw' }), function(data, request/*, someObject*/)
- {
- /* turn off the spinning thingie */
- plugin.editor.setProgressState(0);
- /* if the server is not accepting requests, let the user know */
- if ( request.status !== 200 || request.responseText.substr(1, 4) === 'html' || !request.responseXML )
- {
- ed.windowManager.alert(
- getLang( 'message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.' ),
- callback ? function() { callback( 0 ); } : function() {}
- );
- return;
- }
- /* check to see if things are broken first and foremost */
- if (request.responseXML.getElementsByTagName('message').item(0) != null)
- {
- ed.windowManager.alert(
- request.responseXML.getElementsByTagName('message').item(0).firstChild.data,
- callback ? function() { callback( 0 ); } : function() {}
- );
- return;
- }
- var results = core.processXML(request.responseXML);
- var ecount = 0;
- if (results.count > 0)
- {
- ecount = plugin.markMyWords(results.errors);
- ed.suggestions = results.suggestions;
- }
- if (ecount === 0 && (!callback || callback === undefined)) {
- ed.windowManager.alert( getLang('message_no_errors_found', 'No writing errors were found.') );
- } else if (callback) {
- callback(ecount);
- }
- });
- });
- /* load cascading style sheet for this plugin */
- editor.onInit.add(function()
- {
- /* loading the content.css file, why? I have no clue */
- if (editor.settings.content_css !== false)
- {
- editor.dom.loadCSS(editor.getParam('atd_css_url', url + '/css/content.css'));
- }
- });
- /* again showing a menu, I have no clue what */
- editor.onClick.add(plugin._showMenu, plugin);
- /* we're showing some sort of menu, no idea what */
- editor.onContextMenu.add(plugin._showMenu, plugin);
- /* strip out the markup before the contents is serialized (and do it on a copy of the markup so we don't affect the user experience) */
- editor.onPreProcess.add(function(sender, object)
- {
- var dom = sender.dom;
- each(dom.select('span', object.node).reverse(), function(n)
- {
- if (n && (dom.hasClass(n, 'hiddenGrammarError') || dom.hasClass(n, 'hiddenSpellError') || dom.hasClass(n, 'hiddenSuggestion') || dom.hasClass(n, 'mceItemHidden') || (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style') && !dom.getAttrib(n, 'id') && !dom.hasClass(n, 'Apple-style-span') && !dom.getAttrib(n, 'mce_name'))))
- {
- dom.remove(n, 1);
- }
- });
- });
- /* cleanup the HTML before executing certain commands */
- editor.onBeforeExecCommand.add(function(editor, command)
- {
- if (command === 'mceCodeEditor')
- {
- plugin._removeWords();
- }
- else if (command === 'mceFullScreen')
- {
- plugin._done();
- }
- });
- ed.addButton('AtD', {
- title: getLang( 'button_proofread_tooltip', 'Proofread Writing' ),
- image: ed.getParam('atd_button_url', url + '/atdbuttontr.gif'),
- cmd: 'mceWritingImprovementTool'
- });
- },
- _removeWords : function(w)
- {
- var ed = this.editor, dom = ed.dom, se = ed.selection, b = se.getBookmark();
- ed.core.removeWords(undefined, w);
- /* force a rebuild of the DOM... even though the right elements are stripped, the DOM is still organized
- as if the span were there and this breaks my code */
- dom.setHTML(dom.getRoot(), dom.getRoot().innerHTML);
- se.moveToBookmark(b);
- },
- markMyWords : function(errors)
- {
- var ed = this.editor;
- var se = ed.selection, b = se.getBookmark();
- var ecount = ed.core.markMyWords(ed.core.contents(this.editor.getBody()), errors);
- se.moveToBookmark(b);
- return ecount;
- },
- _showMenu : function(ed, e)
- {
- var t = this;
- ed = t.editor; // not clear why this overwrites the function parameter
- var m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin());
- if (!m)
- {
- p1 = DOM.getPos(ed.getContentAreaContainer());
- //p2 = DOM.getPos(ed.getContainer());
- m = ed.controlManager.createDropMenu('spellcheckermenu',
- {
- offset_x : p1.x,
- offset_y : p1.y,
- 'class' : 'mceNoIcons'
- });
- t._menu = m;
- }
- if (ed.core.isMarkedNode(e.target))
- {
- /* remove these other lame-o elements */
- m.removeAll();
- /* find the correct suggestions object */
- var errorDescription = ed.core.findSuggestion(e.target);
- if (!errorDescription)
- {
- m.add({ title: getLang( 'menu_title_no_suggestions', 'No suggestions' ), 'class': 'mceMenuItemTitle' }).setDisabled(1);
- }
- else if (errorDescription['suggestions'].length === 0)
- {
- m.add({ title: errorDescription['description'], 'class' : 'mceMenuItemTitle' }).setDisabled(1);
- }
- else
- {
- m.add({ title : errorDescription['description'], 'class' : 'mceMenuItemTitle' }).setDisabled(1);
- for (var i = 0; i < errorDescription['suggestions'].length; i++)
- {
- (function(sugg)
- {
- m.add({
- title : sugg,
- onclick : function()
- {
- ed.core.applySuggestion(e.target, sugg);
- t._checkDone();
- }
- });
- })(errorDescription['suggestions'][i]); // jshint ignore:line
- }
- m.addSeparator();
- }
- if (errorDescription && errorDescription['moreinfo'])
- {
- (function(url)
- {
- m.add({
- title : getLang( 'menu_option_explain', 'Explain...' ),
- onclick : function()
- {
- ed.windowManager.open({
- url : url,
- width : 480,
- height : 380,
- inline : true
- }, { theme_url : this.url });
- }
- });
- })(errorDescription['moreinfo']);
- m.addSeparator();
- }
- m.add({
- title : getLang( 'menu_option_ignore_once', 'Ignore suggestion' ),
- onclick : function()
- {
- dom.remove(e.target, 1);
- t._checkDone();
- }
- });
- if (String(this.editor.getParam('atd_ignore_enable', 'false')) === 'true')
- {
- m.add({
- title : getLang( 'menu_option_ignore_always', 'Ignore always' ),
- onclick : function()
- {
- var url = t.editor.getParam('atd_ignore_rpc_url', '{backend}');
- if (url === '{backend}')
- {
- /* Default scheme is to save ignore preferences in a cookie */
- var ignore = tinymce.util.Cookie.getHash('atd_ignore');
- if (!ignore) { ignore = {}; }
- ignore[e.target.innerHTML] = 1;
- tinymce.util.Cookie.setHash('atd_ignore', ignore, new Date( (new Date().getTime()) + 157680000000) );
- }
- else
- {
- /* Plugin is configured to send ignore preferences to server, do that */
- var id = t.editor.getParam('atd_rpc_id', '12345678');
- tinymce.util.XHR.send({
- url : url + encodeURI(e.target.innerHTML).replace(/&/g, '%26') + '&key=' + id,
- content_type : 'text/xml',
- async : true,
- type : 'GET',
- success : function(/* type, req, o */)
- {
- /* do nothing */
- },
- error : function( type, req, o )
- {
- alert( 'Ignore preference save failed\n' + type + '\n' + req.status + '\nAt: ' + o.url );
- }
- });
- /* update atd_ignore_strings with the new value */
- t.editor.core.setIgnoreStrings(e.target.innerHTML); /* this does an update */
- }
- t._removeWords(e.target.innerHTML);
- t._checkDone();
- }
- });
- }
- else
- {
- m.add({
- title : getLang( 'menu_option_ignore_all', 'Ignore all' ),
- onclick : function()
- {
- t._removeWords(e.target.innerHTML);
- t._checkDone();
- }
- });
- }
- /* show the menu please */
- ed.selection.select(e.target);
- p1 = dom.getPos(e.target);
- m.showMenu(p1.x, p1.y + e.target.offsetHeight - vp.y);
- return tinymce.dom.Event.cancel(e);
- }
- else
- {
- m.hideMenu();
- }
- },
- /* loop through editor DOM, call _done if no mce tags exist. */
- _checkDone : function()
- {
- var t = this, ed = t.editor, dom = ed.dom, o;
- each(dom.select('span'), function(n)
- {
- if (n && dom.hasClass(n, 'mceItemHidden'))
- {
- o = true;
- return false;
- }
- });
- if (!o)
- {
- t._done();
- }
- },
- /* remove all tags, hide the menu, and fire a dom change event */
- _done : function()
- {
- var plugin = this;
- plugin._removeWords();
- if (plugin._menu)
- {
- plugin._menu.hideMenu();
- }
- plugin.editor.nodeChanged();
- },
- sendRequest : function(file, data, success)
- {
- var id = this.editor.getParam('atd_rpc_id', '12345678');
- var url = this.editor.getParam('atd_rpc_url', '{backend}');
- var plugin = this;
- if (url === '{backend}' || id === '12345678')
- {
- this.editor.setProgressState(0);
- alert('Please specify: atd_rpc_url and atd_rpc_id');
- return;
- }
- tinymce.util.XHR.send({
- url : url + '/' + file,
- content_type : 'text/xml',
- type : 'POST',
- data : 'data=' + encodeURI(data).replace(/&/g, '%26') + '&key=' + id,
- async : true,
- success : success,
- error : function( type, req, o )
- {
- plugin.editor.setProgressState(0);
- alert( type + '\n' + req.status + '\nAt: ' + o.url );
- }
- });
- }
- });
- // Register plugin
- tinymce.PluginManager.add('AtD', tinymce.plugins.AfterTheDeadlinePlugin);
- })();
|