diff options
Diffstat (limited to 'plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js')
-rw-r--r-- | plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js b/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js new file mode 100644 index 00000000..1a71ce8b --- /dev/null +++ b/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js @@ -0,0 +1,427 @@ +/* global tinymce */ +/* + * TinyMCE Writing Improvement Tool Plugin + * Author: Raphael Mudge (raffi@automattic.com) + * + * Updated for TinyMCE 4.0 + * + * 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 + */ +tinymce.PluginManager.add( 'AtD', function( editor ) { + var suggestionsMenu, started, atdCore, dom, + each = tinymce.each; + + /* initializes the functions used by the AtD Core UI Module */ + function initAtDCore() { + + atdCore = new window.AtDCore(); + atdCore.map = each; + atdCore._isTinyMCE = true; + + atdCore.getAttrib = function( node, key ) { + return dom.getAttrib( node, key ); + }; + + atdCore.findSpans = function( parent ) { + if ( parent === undefined ) { + return dom.select('span'); + } else { + return dom.select( 'span', parent ); + } + }; + + atdCore.hasClass = function( node, className ) { + return dom.hasClass( node, className ); + }; + + atdCore.contents = function( node ) { + return node.childNodes; + }; + + atdCore.replaceWith = function( old_node, new_node ) { + return dom.replace( new_node, old_node ); + }; + + atdCore.create = function( node_html ) { + return dom.create( 'span', { 'class': 'mceItemHidden', 'data-mce-bogus': 1 }, node_html ); + }; + + atdCore.removeParent = function( node ) { + dom.remove( node, true ); + return node; + }; + + atdCore.remove = function( node ) { + dom.remove( node ); + }; + + atdCore.setIgnoreStrings( editor.getParam( 'atd_ignore_strings', [] ).join(',') ); + atdCore.showTypes( editor.getParam( 'atd_show_types', '' ) ); + } + + function getLang( key, defaultStr ) { + return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultStr; + } + + function isMarkedNode( node ) { + return ( node.className && /\bhidden(GrammarError|SpellError|Suggestion)\b/.test( node.className ) ); + } + + function markMyWords( errors ) { + return atdCore.markMyWords( atdCore.contents( editor.getBody() ), errors ); + } + + // If no more suggestions, finish. + function checkIfFinished() { + if ( ! editor.dom.select('span.hiddenSpellError, span.hiddenGrammarError, span.hiddenSuggestion').length ) { + if ( suggestionsMenu ) { + suggestionsMenu.hideMenu(); + } + + finish(); + } + } + + function ignoreWord( target, word, all ) { + var dom = editor.dom; + + if ( all ) { + each( editor.dom.select( 'span.hiddenSpellError, span.hiddenGrammarError, span.hiddenSuggestion' ), function( node ) { + var text = node.innerText || node.textContent; + + if ( text === word ) { + dom.remove( node, true ); + } + }); + } else { + dom.remove( target, true ); + } + + checkIfFinished(); + } + + // Called when the user clicks "Finish" or when no more suggestions left. + // Removes all remaining spans and fires custom event. + function finish() { + var node, + dom = editor.dom, + regex = new RegExp( 'mceItemHidden|hidden(((Grammar|Spell)Error)|Suggestion)' ), + nodes = dom.select('span'), + i = nodes.length; + + while ( i-- ) { // reversed + node = nodes[i]; + + if ( node.className && regex.test( node.className ) ) { + dom.remove( node, true ); + } + } + + // Rebuild the DOM so AtD core can find the text nodes + editor.setContent( editor.getContent({ format: 'raw' }), { format: 'raw' } ); + + started = false; + editor.nodeChanged(); + editor.fire('SpellcheckEnd'); + } + + function sendRequest( file, data, success ) { + var id = editor.getParam( 'atd_rpc_id', '12345678' ), + url = editor.getParam( 'atd_rpc_url', '{backend}' ); + + if ( url === '{backend}' || id === '12345678' ) { + window.alert( 'Please specify: atd_rpc_url and atd_rpc_id' ); + return; + } + + // create the nifty spinny thing that says "hizzo, I'm doing something fo realz" + editor.setProgressState( true ); + + tinymce.util.XHR.send({ + url: url + '/' + file, + content_type: 'text/xml', + type: 'POST', + data: 'data=' + encodeURI( data ).replace( /&/g, '%26' ) + '&key=' + id, + success: success, + error: function( type, req, o ) { + editor.setProgressState(); + window.alert( type + '\n' + req.status + '\nAt: ' + o.url ); + } + }); + } + + function storeIgnoredStrings( /*text*/ ) { + // Store in sessionStorage? + } + + function setAlwaysIgnore( text ) { + var url = editor.getParam( 'atd_ignore_rpc_url' ); + + if ( ! url || url === '{backend}' ) { + // Store ignored words for this session only + storeIgnoredStrings( text ); + } else { + // Plugin is configured to send ignore preferences to server, do that + tinymce.util.XHR.send({ + url: url + encodeURIComponent( text ) + '&key=' + editor.getParam( 'atd_rpc_id', '12345678' ), + content_type: 'text/xml', + type: 'GET', + error: function() { + storeIgnoredStrings( text ); + } + }); + } + + // Update atd_ignore_strings with the new value + atdCore.setIgnoreStrings( text ); + } + + // Create the suggestions menu + function showSuggestions( target ) { + var pos, root, targetPos, + items = [], + text = target.innerText || target.textContent, + errorDescription = atdCore.findSuggestion( target ); + + if ( ! errorDescription ) { + items.push({ + text: getLang( 'menu_title_no_suggestions', 'No suggestions' ), + classes: 'atd-menu-title', + disabled: true + }); + } else { + items.push({ + text: errorDescription.description, + classes: 'atd-menu-title', + disabled: true + }); + + if ( errorDescription.suggestions.length ) { + items.push({ text: '-' }); // separator + + each( errorDescription.suggestions, function( suggestion ) { + items.push({ + text: suggestion, + onclick: function() { + atdCore.applySuggestion( target, suggestion ); + checkIfFinished(); + } + }); + }); + } + } + + if ( errorDescription && errorDescription.moreinfo ) { + items.push({ text: '-' }); // separator + + items.push({ + text: getLang( 'menu_option_explain', 'Explain...' ), + onclick : function() { + editor.windowManager.open({ + title: getLang( 'menu_option_explain', 'Explain...' ), + url: errorDescription.moreinfo, + width: 480, + height: 380, + inline: true + }); + } + }); + } + + items.push.apply( items, [ + { text: '-' }, // separator + + { text: getLang( 'menu_option_ignore_once', 'Ignore suggestion' ), onclick: function() { + ignoreWord( target, text ); + }} + ]); + + if ( editor.getParam( 'atd_ignore_enable' ) ) { + items.push({ + text: getLang( 'menu_option_ignore_always', 'Ignore always' ), + onclick: function() { + setAlwaysIgnore( text ); + ignoreWord( target, text, true ); + } + }); + } else { + items.push({ + text: getLang( 'menu_option_ignore_all', 'Ignore all' ), + onclick: function() { + ignoreWord( target, text, true ); + } + }); + } + + // Render menu + suggestionsMenu = new tinymce.ui.Menu({ + items: items, + context: 'contextmenu', + onautohide: function( event ) { + if ( isMarkedNode( event.target ) ) { + event.preventDefault(); + } + }, + onhide: function() { + suggestionsMenu.remove(); + suggestionsMenu = null; + } + }); + + suggestionsMenu.renderTo( document.body ); + + // Position menu + pos = tinymce.DOM.getPos( editor.getContentAreaContainer() ); + targetPos = editor.dom.getPos( target ); + root = editor.dom.getRoot(); + + // Adjust targetPos for scrolling in the editor + if ( root.nodeName === 'BODY' ) { + targetPos.x -= root.ownerDocument.documentElement.scrollLeft || root.scrollLeft; + targetPos.y -= root.ownerDocument.documentElement.scrollTop || root.scrollTop; + } else { + targetPos.x -= root.scrollLeft; + targetPos.y -= root.scrollTop; + } + + pos.x += targetPos.x; + pos.y += targetPos.y; + + suggestionsMenu.moveTo( pos.x, pos.y + target.offsetHeight ); + } + + // Init everything + editor.on( 'init', function() { + if ( typeof window.AtDCore === 'undefined' ) { + return; + } + + // Set dom and atdCore + dom = editor.dom; + initAtDCore(); + + // add a command to request a document check and process the results. + editor.addCommand( 'mceWritingImprovementTool', function( callback ) { + var results, + errorCount = 0; + + if ( typeof callback !== 'function' ) { + callback = function(){}; + } + + // checks if a global var for click stats exists and increments it if it does... + if ( typeof window.AtD_proofread_click_count !== 'undefined' ) { + window.AtD_proofread_click_count++; + } + + // remove the previous errors + if ( started ) { + finish(); + return; + } + + // send request to our service + sendRequest( 'checkDocument', editor.getContent({ format: 'raw' }), function( data, request ) { + // turn off the spinning thingie + editor.setProgressState(); + + // if the server is not accepting requests, let the user know + if ( request.status !== 200 || request.responseText.substr( 1, 4 ) === 'html' || ! request.responseXML ) { + editor.windowManager.alert( + getLang( 'message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.' ), + callback(0) + ); + + return; + } + + // check to see if things are broken first and foremost + if ( request.responseXML.getElementsByTagName('message').item(0) !== null ) { + editor.windowManager.alert( + request.responseXML.getElementsByTagName('message').item(0).firstChild.data, + callback(0) + ); + + return; + } + + results = atdCore.processXML( request.responseXML ); + + if ( results.count > 0 ) { + errorCount = markMyWords( results.errors ); + } + + if ( ! errorCount ) { + editor.windowManager.alert( getLang( 'message_no_errors_found', 'No writing errors were found.' ) ); + } else { + started = true; + editor.fire('SpellcheckStart'); + } + + callback( errorCount ); + }); + }); + + if ( editor.settings.content_css !== false ) { + // CSS for underlining suggestions + dom.addStyle( '.hiddenSpellError{border-bottom:2px solid red;cursor:default;}' + + '.hiddenGrammarError{border-bottom:2px solid green;cursor:default;}' + + '.hiddenSuggestion{border-bottom:2px solid blue;cursor:default;}' ); + } + + // Menu z-index > DFW + tinymce.DOM.addStyle( 'div.mce-floatpanel{z-index:150100 !important;}' ); + + // Click on misspelled word + editor.on( 'click', function( event ) { + if ( isMarkedNode( event.target ) ) { + event.preventDefault(); + editor.selection.select( event.target ); + // Create the suggestions menu + showSuggestions( event.target ); + } + }); + }); + + editor.addMenuItem( 'spellchecker', { + text: getLang( 'button_proofread_tooltip', 'Proofread Writing' ), + context: 'tools', + cmd: 'mceWritingImprovementTool', + onPostRender: function() { + var self = this; + + editor.on('SpellcheckStart SpellcheckEnd', function() { + self.active( started ); + }); + } + }); + + editor.addButton( 'spellchecker', { + tooltip: getLang( 'button_proofread_tooltip', 'Proofread Writing' ), + cmd: 'mceWritingImprovementTool', + onPostRender: function() { + var self = this; + + editor.on( 'SpellcheckStart SpellcheckEnd', function() { + self.active( started ); + }); + } + }); + + editor.on( 'remove', function() { + if ( suggestionsMenu ) { + suggestionsMenu.remove(); + suggestionsMenu = null; + } + }); +}); |