/wp-content/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js
JavaScript | 427 lines | 310 code | 71 blank | 46 comment | 46 complexity | e670dfa659516e3b35231ae5b501697e MD5 | raw file
- /* 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;
- }
- });
- });