summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/after-the-deadline/atd.core.js')
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd.core.js640
1 files changed, 0 insertions, 640 deletions
diff --git a/plugins/jetpack/modules/after-the-deadline/atd.core.js b/plugins/jetpack/modules/after-the-deadline/atd.core.js
deleted file mode 100644
index f62f68e7..00000000
--- a/plugins/jetpack/modules/after-the-deadline/atd.core.js
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- * atd.core.js - A building block to create a front-end for AtD
- * Author : Raphael Mudge, Automattic
- * License : LGPL
- * Project : http://www.afterthedeadline.com/developers.slp
- * Contact : raffi@automattic.com
- */
-
-/* jshint sub: true, devel: true, onevar: false, smarttabs: true, loopfunc: true */
-/* exported EXPORTED_SYMBOLS, atd_sprintf */
-
-/* EXPORTED_SYMBOLS is set so this file can be a JavaScript Module */
-var EXPORTED_SYMBOLS = ['AtDCore'];
-
-function AtDCore() {
- /* these are the categories of errors AtD should ignore */
- this.ignore_types = ['Bias Language', 'Cliches', 'Complex Expression', 'Diacritical Marks', 'Double Negatives', 'Hidden Verbs', 'Jargon Language', 'Passive voice', 'Phrases to Avoid', 'Redundant Expression'];
-
- /* these are the phrases AtD should ignore */
- this.ignore_strings = {};
-
- /* Localized strings */
- // Back-compat, not used
- this.i18n = {};
-}
-
-/*
- * Internationalization Functions
- */
-
-AtDCore.prototype.getLang = function( key, defaultk ) {
- return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultk;
-};
-
-AtDCore.prototype.addI18n = function( obj ) {
- // Back-compat
- window.AtD_l10n_r0ar = obj;
-};
-
-/*
- * Setters
- */
-
-AtDCore.prototype.setIgnoreStrings = function(string) {
- var parent = this;
-
- this.map(string.split(/,\s*/g), function(string) {
- parent.ignore_strings[string] = 1;
- });
-};
-
-AtDCore.prototype.showTypes = function(string) {
- var show_types = string.split(/,\s*/g);
- var types = {};
-
- /* set some default types that we want to make optional */
-
- /* grammar checker options */
- types['Double Negatives'] = 1;
- types['Hidden Verbs'] = 1;
- types['Passive voice'] = 1;
- types['Bias Language'] = 1;
-
- /* style checker options */
- types['Cliches'] = 1;
- types['Complex Expression'] = 1;
- types['Diacritical Marks'] = 1;
- types['Jargon Language'] = 1;
- types['Phrases to Avoid'] = 1;
- types['Redundant Expression'] = 1;
-
- var ignore_types = [];
-
- this.map(show_types, function(string) {
- types[string] = undefined;
- });
-
- this.map(this.ignore_types, function(string) {
- if (types[string] !== undefined) {
- ignore_types.push(string);
- }
- });
-
- this.ignore_types = ignore_types;
-};
-
-/*
- * Error Parsing Code
- */
-
-AtDCore.prototype.makeError = function(error_s, tokens, type, seps/*, pre*/) {
- var struct = {};
- struct.type = type;
- struct.string = error_s;
- struct.tokens = tokens;
-
- if (new RegExp('\\b' + error_s + '\\b').test(error_s)) {
- struct.regexp = new RegExp('(?!'+error_s+'<)\\b' + error_s.replace(/\s+/g, seps) + '\\b');
- }
- else if (new RegExp(error_s + '\\b').test(error_s)) {
- struct.regexp = new RegExp('(?!'+error_s+'<)' + error_s.replace(/\s+/g, seps) + '\\b');
- }
- else if (new RegExp('\\b' + error_s).test(error_s)) {
- struct.regexp = new RegExp('(?!'+error_s+'<)\\b' + error_s.replace(/\s+/g, seps));
- }
- else {
- struct.regexp = new RegExp('(?!'+error_s+'<)' + error_s.replace(/\s+/g, seps));
- }
-
- struct.used = false; /* flag whether we've used this rule or not */
-
- return struct;
-};
-
-AtDCore.prototype.addToErrorStructure = function(errors, list, type, seps) {
- var parent = this;
-
- this.map(list, function(error) {
- var tokens = error['word'].split(/\s+/);
- var pre = error['pre'];
- var first = tokens[0];
-
- if (errors['__' + first] === undefined) {
- errors['__' + first] = {};
- errors['__' + first].pretoks = {};
- errors['__' + first].defaults = [];
- }
-
- if (pre === '') {
- errors['__' + first].defaults.push(parent.makeError(error['word'], tokens, type, seps, pre));
- } else {
- if (errors['__' + first].pretoks['__' + pre] === undefined) {
- errors['__' + first].pretoks['__' + pre] = [];
- }
-
- errors['__' + first].pretoks['__' + pre].push(parent.makeError(error['word'], tokens, type, seps, pre));
- }
- });
-};
-
-AtDCore.prototype.buildErrorStructure = function(spellingList, enrichmentList, grammarList) {
- var seps = this._getSeparators();
- var errors = {};
-
- this.addToErrorStructure(errors, spellingList, 'hiddenSpellError', seps);
- this.addToErrorStructure(errors, grammarList, 'hiddenGrammarError', seps);
- this.addToErrorStructure(errors, enrichmentList, 'hiddenSuggestion', seps);
- return errors;
-};
-
-AtDCore.prototype._getSeparators = function() {
- var re = '', i;
- var str = '"s!#$%&()*+,./:;<=>?@[\\]^_{|}';
-
- // Build word separator regexp
- for (i=0; i<str.length; i++) {
- re += '\\' + str.charAt(i);
- }
-
- return '(?:(?:[\xa0' + re + '])|(?:\\-\\-))+';
-};
-
-AtDCore.prototype.processXML = function(responseXML) {
-
- /* types of errors to ignore */
- var types = {};
-
- this.map(this.ignore_types, function(type) {
- types[type] = 1;
- });
-
- /* save suggestions in the editor object */
- this.suggestions = [];
-
- /* process through the errors */
- var errors = responseXML.getElementsByTagName('error');
-
- /* words to mark */
- var grammarErrors = [];
- var spellingErrors = [];
- var enrichment = [];
-
- for (var i = 0; i < errors.length; i++) {
- if (errors[i].getElementsByTagName('string').item(0).firstChild !== null) {
- var errorString = errors[i].getElementsByTagName('string').item(0).firstChild.data;
- var errorType = errors[i].getElementsByTagName('type').item(0).firstChild.data;
- var errorDescription = errors[i].getElementsByTagName('description').item(0).firstChild.data;
-
- var errorContext;
-
- if (errors[i].getElementsByTagName('precontext').item(0).firstChild !== null) {
- errorContext = errors[i].getElementsByTagName('precontext').item(0).firstChild.data;
- } else {
- errorContext = '';
- }
-
- /* create a hashtable with information about the error in the editor object, we will use this later
- to populate a popup menu with information and suggestions about the error */
-
- if (this.ignore_strings[errorString] === undefined) {
- var suggestion = {};
- suggestion['description'] = errorDescription;
- suggestion['suggestions'] = [];
-
- /* used to find suggestions when a highlighted error is clicked on */
- suggestion['matcher'] = new RegExp('^' + errorString.replace(/\s+/, this._getSeparators()) + '$');
-
- suggestion['context'] = errorContext;
- suggestion['string'] = errorString;
- suggestion['type'] = errorType;
-
- this.suggestions.push(suggestion);
-
- if (errors[i].getElementsByTagName('suggestions').item(0) !== null) {
- var suggestions = errors[i].getElementsByTagName('suggestions').item(0).getElementsByTagName('option');
- for (var j = 0; j < suggestions.length; j++) {
- suggestion['suggestions'].push(suggestions[j].firstChild.data);
- }
- }
-
- /* setup the more info url */
- if (errors[i].getElementsByTagName('url').item(0) !== null) {
- var errorUrl = errors[i].getElementsByTagName('url').item(0).firstChild.data;
- suggestion['moreinfo'] = errorUrl + '&theme=tinymce';
- }
-
- if (types[errorDescription] === undefined) {
- if (errorType === 'suggestion') {
- enrichment.push({ word: errorString, pre: errorContext });
- }
-
- if (errorType === 'grammar') {
- grammarErrors.push({ word: errorString, pre: errorContext });
- }
- }
-
- if (errorType === 'spelling' || errorDescription === 'Homophone') {
- spellingErrors.push({ word: errorString, pre: errorContext });
- }
-
- if (errorDescription === 'Cliches') {
- suggestion['description'] = 'Clichés'; /* done here for backwards compatability with current user settings */
- }
-
- if (errorDescription === 'Spelling') {
- suggestion['description'] = this.getLang('menu_title_spelling', 'Spelling');
- }
-
- if (errorDescription === 'Repeated Word') {
- suggestion['description'] = this.getLang('menu_title_repeated_word', 'Repeated Word');
- }
-
- if (errorDescription === 'Did you mean...') {
- suggestion['description'] = this.getLang('menu_title_confused_word', 'Did you mean...');
- }
- } // end if ignore[errorString] == undefined
- } // end if
- } // end for loop
-
- var errorStruct;
- var ecount = spellingErrors.length + grammarErrors.length + enrichment.length;
-
- if (ecount > 0) {
- errorStruct = this.buildErrorStructure(spellingErrors, enrichment, grammarErrors);
- } else {
- errorStruct = undefined;
- }
-
- /* save some state in this object, for retrieving suggestions later */
- return { errors: errorStruct, count: ecount, suggestions: this.suggestions };
-};
-
-AtDCore.prototype.findSuggestion = function(element) {
- var text = element.innerHTML;
- var context = ( this.getAttrib(element, 'pre') + '' ).replace(/[\\,!\\?\\."\s]/g, '');
- if (this.getAttrib(element, 'pre') === undefined) {
- alert(element.innerHTML);
- }
-
- var errorDescription;
- var len = this.suggestions.length;
-
- for (var i = 0; i < len; i++) {
- if ((context === '' || context === this.suggestions[i]['context']) && this.suggestions[i]['matcher'].test(text)) {
- errorDescription = this.suggestions[i];
- break;
- }
- }
- return errorDescription;
-};
-
-/*
- * TokenIterator class
- */
-
-function TokenIterator(tokens) {
- this.tokens = tokens;
- this.index = 0;
- this.count = 0;
- this.last = 0;
-}
-
-TokenIterator.prototype.next = function() {
- var current = this.tokens[this.index];
- this.count = this.last;
- this.last += current.length + 1;
- this.index++;
-
- /* strip single quotes from token, AtD does this when presenting errors */
- if (current !== '') {
- if (current[0] === '\'') {
- current = current.substring(1, current.length);
- }
-
- if (current[current.length - 1] === '\'') {
- current = current.substring(0, current.length - 1);
- }
- }
-
- return current;
-};
-
-TokenIterator.prototype.hasNext = function() {
- return this.index < this.tokens.length;
-};
-
-TokenIterator.prototype.hasNextN = function(n) {
- return (this.index + n) < this.tokens.length;
-};
-
-TokenIterator.prototype.skip = function(m, n) {
- this.index += m;
- this.last += n;
-
- if (this.index < this.tokens.length) {
- this.count = this.last - this.tokens[this.index].length;
- }
-};
-
-TokenIterator.prototype.getCount = function() {
- return this.count;
-};
-
-TokenIterator.prototype.peek = function(n) {
- var peepers = [];
- var end = this.index + n;
- for (var x = this.index; x < end; x++) {
- peepers.push(this.tokens[x]);
- }
- return peepers;
-};
-
-/*
- * code to manage highlighting of errors
- */
-AtDCore.prototype.markMyWords = function(container_nodes, errors) {
- var seps = new RegExp(this._getSeparators()),
- nl = [],
- ecount = 0, /* track number of highlighted errors */
- parent = this,
- bogus = this._isTinyMCE ? ' data-mce-bogus="1"' : '',
- emptySpan = '<span class="mceItemHidden"' + bogus + '>&nbsp;</span>',
- textOnlyMode;
-
- /**
- * Split a text node into an ordered list of siblings:
- * - text node to the left of the match
- * - the element replacing the match
- * - text node to the right of the match
- *
- * We have to leave the text to the left and right of the match alone
- * in order to prevent XSS
- *
- * @return array
- */
- function splitTextNode( textnode, regexp, replacement ) {
- var text = textnode.nodeValue,
- index = text.search( regexp ),
- match = text.match( regexp ),
- captured = [],
- cursor;
-
- if ( index < 0 || ! match.length ) {
- return [ textnode ];
- }
-
- if ( index > 0 ) {
- // capture left text node
- captured.push( document.createTextNode( text.substr( 0, index ) ) );
- }
-
- // capture the replacement of the matched string
- captured.push( parent.create( match[0].replace( regexp, replacement ) ) );
-
- cursor = index + match[0].length;
-
- if ( cursor < text.length ) {
- // capture right text node
- captured.push( document.createTextNode( text.substr( cursor ) ) );
- }
-
- return captured;
- }
-
- function _isInPre( node ) {
- if ( node ) {
- while ( node.parentNode ) {
- if ( node.nodeName === 'PRE' ) {
- return true;
- }
- node = node.parentNode;
- }
- }
-
- return false;
- }
-
- /* Collect all text nodes */
- /* Our goal--ignore nodes that are already wrapped */
-
- this._walk( container_nodes, function( n ) {
- if ( n.nodeType === 3 && ! parent.isMarkedNode( n ) && ! _isInPre( n ) ) {
- nl.push( n );
- }
- });
-
- /* walk through the relevant nodes */
-
- var iterator;
-
- this.map( nl, function( n ) {
- var v;
-
- if ( n.nodeType === 3 ) {
- v = n.nodeValue; /* we don't want to mangle the HTML so use the actual encoded string */
- var tokens = n.nodeValue.split( seps ); /* split on the unencoded string so we get access to quotes as " */
- var previous = '';
-
- var doReplaces = [];
-
- iterator = new TokenIterator(tokens);
-
- while ( iterator.hasNext() ) {
- var token = iterator.next();
- var current = errors['__' + token];
-
- var defaults;
-
- if ( current !== undefined && current.pretoks !== undefined ) {
- defaults = current.defaults;
- current = current.pretoks['__' + previous];
-
- var done = false;
- var prev, curr;
-
- prev = v.substr(0, iterator.getCount());
- curr = v.substr(prev.length, v.length);
-
- var checkErrors = function( error ) {
- if ( error !== undefined && ! error.used && foundStrings[ '__' + error.string ] === undefined && error.regexp.test( curr ) ) {
- foundStrings[ '__' + error.string ] = 1;
- doReplaces.push([ error.regexp, '<span class="'+error.type+'" pre="'+previous+'"' + bogus + '>$&</span>' ]);
-
- error.used = true;
- done = true;
- }
- }; // jshint ignore:line
-
- var foundStrings = {};
-
- if (current !== undefined) {
- previous = previous + ' ';
- parent.map(current, checkErrors);
- }
-
- if (!done) {
- previous = '';
- parent.map(defaults, checkErrors);
- }
- }
-
- previous = token;
- } // end while
-
- /* do the actual replacements on this span */
- if ( doReplaces.length > 0 ) {
- var newNode = n;
-
- for ( var x = 0; x < doReplaces.length; x++ ) {
- var regexp = doReplaces[x][0], result = doReplaces[x][1];
-
- /* it's assumed that this function is only being called on text nodes (nodeType == 3), the iterating is necessary
- because eventually the whole thing gets wrapped in an mceItemHidden span and from there it's necessary to
- handle each node individually. */
- var bringTheHurt = function( node ) {
- var span, splitNodes;
-
- if ( node.nodeType === 3 ) {
- ecount++;
-
- /* sometimes IE likes to ignore the space between two spans, solution is to insert a placeholder span with
- a non-breaking space. The markup removal code substitutes this span for a space later */
- if ( parent.isIE() && node.nodeValue.length > 0 && node.nodeValue.substr(0, 1) === ' ' ) {
- return parent.create( emptySpan + node.nodeValue.substr( 1, node.nodeValue.length - 1 ).replace( regexp, result ), false );
- } else {
- if ( textOnlyMode ) {
- return parent.create( node.nodeValue.replace( regexp, result ), false );
- }
-
- span = parent.create( '<span />' );
- if ( typeof textOnlyMode === 'undefined' ) {
- // cache this to avoid adding / removing nodes unnecessarily
- textOnlyMode = typeof span.appendChild !== 'function';
- if ( textOnlyMode ) {
- parent.remove( span );
- return parent.create( node.nodeValue.replace( regexp, result ), false );
- }
- }
-
- // "Visual" mode
- splitNodes = splitTextNode( node, regexp, result );
- for ( var i = 0; i < splitNodes.length; i++ ) {
- span.appendChild( splitNodes[i] );
- }
-
- node = span;
- return node;
- }
- }
- else {
- var contents = parent.contents(node);
-
- for ( var y = 0; y < contents.length; y++ ) {
- if ( contents[y].nodeType === 3 && regexp.test( contents[y].nodeValue ) ) {
- var nnode;
-
- if ( parent.isIE() && contents[y].nodeValue.length > 0 && contents[y].nodeValue.substr(0, 1) === ' ') {
- nnode = parent.create( emptySpan + contents[y].nodeValue.substr( 1, contents[y].nodeValue.length - 1 ).replace( regexp, result ), true );
- } else {
- nnode = parent.create( contents[y].nodeValue.replace( regexp, result ), true );
- }
-
- parent.replaceWith( contents[y], nnode );
- parent.removeParent( nnode );
-
- ecount++;
-
- return node; /* we did a replacement so we can call it quits, errors only get used once */
- }
- }
-
- return node;
- }
- }; // jshint ignore:line
-
- newNode = bringTheHurt(newNode);
- }
-
- parent.replaceWith(n, newNode);
- }
- }
- });
-
- return ecount;
-};
-
-AtDCore.prototype._walk = function(elements, f) {
- var i;
- for (i = 0; i < elements.length; i++) {
- f.call(f, elements[i]);
- this._walk(this.contents(elements[i]), f);
- }
-};
-
-AtDCore.prototype.removeWords = function(node, w) {
- var count = 0;
- var parent = this;
-
- this.map(this.findSpans(node).reverse(), function(n) {
- if (n && (parent.isMarkedNode(n) || parent.hasClass(n, 'mceItemHidden') || parent.isEmptySpan(n)) ) {
- if (n.innerHTML === '&nbsp;') {
- var nnode = document.createTextNode(' '); /* hax0r */
- parent.replaceWith(n, nnode);
- } else if (!w || n.innerHTML === w) {
- parent.removeParent(n);
- count++;
- }
- }
- });
-
- return count;
-};
-
-AtDCore.prototype.isEmptySpan = function(node) {
- return (this.getAttrib(node, 'class') === '' && this.getAttrib(node, 'style') === '' && this.getAttrib(node, 'id') === '' && !this.hasClass(node, 'Apple-style-span') && this.getAttrib(node, 'mce_name') === '');
-};
-
-AtDCore.prototype.isMarkedNode = function(node) {
- return (this.hasClass(node, 'hiddenGrammarError') || this.hasClass(node, 'hiddenSpellError') || this.hasClass(node, 'hiddenSuggestion'));
-};
-
-/*
- * Context Menu Helpers
- */
-AtDCore.prototype.applySuggestion = function(element, suggestion) {
- if (suggestion === '(omit)') {
- this.remove(element);
- }
- else {
- var node = this.create(suggestion);
- this.replaceWith(element, node);
- this.removeParent(node);
- }
-};
-
-/*
- * Check for an error
- */
-AtDCore.prototype.hasErrorMessage = function(xmlr) {
- return (xmlr !== undefined && xmlr.getElementsByTagName('message').item(0) !== null);
-};
-
-AtDCore.prototype.getErrorMessage = function(xmlr) {
- return xmlr.getElementsByTagName('message').item(0);
-};
-
-/* this should always be an error, alas... not practical */
-AtDCore.prototype.isIE = function() {
- return navigator.appName === 'Microsoft Internet Explorer';
-};
-
-// TODO: this doesn't seem used anywhere in AtD, moved here from install_atd_l10n.js for eventual back-compat
-/* a quick poor man's sprintf */
-function atd_sprintf(format, values) {
- var result = format;
- for (var x = 0; x < values.length; x++) {
- result = result.replace(new RegExp('%' + (x + 1) + '\\$', 'g'), values[x]);
- }
- return result;
-}