summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js')
-rw-r--r--plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js427
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;
+ }
+ });
+});