PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/blog.old/wp-content/plugins/jetpack/modules/after-the-deadline/jquery.atd.js

https://github.com/chopsuei3/oscc
JavaScript | 417 lines | 289 code | 88 blank | 40 comment | 125 complexity | 3efd1501fb33b8e5ce294b4f9a7c80ac MD5 | raw file
  1. /*
  2. * jquery.atd.js - jQuery powered writing check with After the Deadline
  3. * Author : Raphael Mudge, Automattic Inc.
  4. * License : LGPL or MIT License (take your pick)
  5. * Project : http://www.afterthedeadline.com/development.slp
  6. * Contact : raffi@automattic.com
  7. *
  8. * Derived from:
  9. *
  10. * jquery.spellchecker.js - a simple jQuery Spell Checker
  11. * Copyright (c) 2008 Richard Willis
  12. * MIT license : http://www.opensource.org/licenses/mit-license.php
  13. * Project : http://jquery-spellchecker.googlecode.com
  14. * Contact : willis.rh@gmail.com
  15. */
  16. var AtD =
  17. {
  18. rpc : '', /* see the proxy.php that came with the AtD/TinyMCE plugin */
  19. rpc_css : 'http://www.polishmywriting.com/atd-jquery/server/proxycss.php?data=', /* you may use this, but be nice! */
  20. rpc_css_lang : 'en',
  21. api_key : '',
  22. i18n : {},
  23. listener : {}
  24. };
  25. AtD.getLang = function(key, defaultk) {
  26. if (AtD.i18n[key] == undefined)
  27. return defaultk;
  28. return AtD.i18n[key];
  29. };
  30. AtD.addI18n = function(localizations) {
  31. AtD.i18n = localizations;
  32. AtD.core.addI18n(localizations);
  33. };
  34. AtD.setIgnoreStrings = function(string) {
  35. AtD.core.setIgnoreStrings(string);
  36. };
  37. AtD.showTypes = function(string) {
  38. AtD.core.showTypes(string);
  39. };
  40. AtD.checkCrossAJAX = function(container_id, callback_f) {
  41. /* checks if a global var for click stats exists and increments it if it does... */
  42. if (typeof AtD_proofread_click_count != "undefined")
  43. AtD_proofread_click_count++;
  44. AtD.callback_f = callback_f; /* remember the callback for later */
  45. AtD.remove(container_id);
  46. var container = jQuery('#' + container_id);
  47. var html = container.html();
  48. text = jQuery.trim(container.html());
  49. text = text.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>').replace(/\&amp;/g, '&');
  50. text = encodeURIComponent( text.replace( /\%/g, '%25' ) ); /* % not being escaped here creates problems, I don't know why. */
  51. /* do some sanity checks based on the browser */
  52. if ((text.length > 2000 && navigator.appName == 'Microsoft Internet Explorer') || text.length > 7800) {
  53. if (callback_f != undefined && callback_f.error != undefined)
  54. callback_f.error("Maximum text length for this browser exceeded");
  55. return;
  56. }
  57. /* do some cross-domain AJAX action with CSSHttpRequest */
  58. CSSHttpRequest.get(AtD.rpc_css + text + "&lang=" + AtD.rpc_css_lang + "&nocache=" + (new Date().getTime()), function(response) {
  59. /* do some magic to convert the response into an XML document */
  60. var xml;
  61. if (navigator.appName == 'Microsoft Internet Explorer') {
  62. xml = new ActiveXObject("Microsoft.XMLDOM");
  63. xml.async = false;
  64. xml.loadXML(response);
  65. }
  66. else {
  67. xml = (new DOMParser()).parseFromString(response, 'text/xml');
  68. }
  69. /* check for and display error messages from the server */
  70. if (AtD.core.hasErrorMessage(xml)) {
  71. if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
  72. AtD.callback_f.error(AtD.core.getErrorMessage(xml));
  73. return;
  74. }
  75. /* highlight the errors */
  76. AtD.container = container_id;
  77. var count = AtD.processXML(container_id, xml);
  78. if (AtD.callback_f != undefined && AtD.callback_f.ready != undefined)
  79. AtD.callback_f.ready(count);
  80. if (count == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  81. AtD.callback_f.success(count);
  82. AtD.counter = count;
  83. AtD.count = count;
  84. });
  85. };
  86. /* check a div for any incorrectly spelled words */
  87. AtD.check = function(container_id, callback_f) {
  88. /* checks if a global var for click stats exists and increments it if it does... */
  89. if (typeof AtD_proofread_click_count != "undefined")
  90. AtD_proofread_click_count++;
  91. AtD.callback_f = callback_f; /* remember the callback for later */
  92. AtD.remove(container_id);
  93. var container = jQuery('#' + container_id);
  94. var html = container.html();
  95. text = jQuery.trim(container.html());
  96. text = text.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>').replace(/\&amp;/g, '&');
  97. text = encodeURIComponent( text ); /* re-escaping % is not necessary here. don't do it */
  98. jQuery.ajax({
  99. type : "POST",
  100. url : AtD.rpc + '/checkDocument',
  101. data : 'key=' + AtD.api_key + '&data=' + text,
  102. format : 'raw',
  103. dataType : (jQuery.browser.msie) ? "text" : "xml",
  104. error : function(XHR, status, error) {
  105. if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
  106. AtD.callback_f.error(status + ": " + error);
  107. },
  108. success : function(data) {
  109. /* apparently IE likes to return XML as plain text-- work around from:
  110. http://docs.jquery.com/Specifying_the_Data_Type_for_AJAX_Requests */
  111. var xml;
  112. if (typeof data == "string") {
  113. xml = new ActiveXObject("Microsoft.XMLDOM");
  114. xml.async = false;
  115. xml.loadXML(data);
  116. }
  117. else {
  118. xml = data;
  119. }
  120. if (AtD.core.hasErrorMessage(xml)) {
  121. if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
  122. AtD.callback_f.error(AtD.core.getErrorMessage(xml));
  123. return;
  124. }
  125. /* on with the task of processing and highlighting errors */
  126. AtD.container = container_id;
  127. var count = AtD.processXML(container_id, xml);
  128. if (AtD.callback_f != undefined && AtD.callback_f.ready != undefined)
  129. AtD.callback_f.ready(count);
  130. if (count == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  131. AtD.callback_f.success(count);
  132. AtD.counter = count;
  133. AtD.count = count;
  134. }
  135. });
  136. };
  137. AtD.remove = function(container_id) {
  138. AtD._removeWords(container_id, null);
  139. };
  140. AtD.clickListener = function(event) {
  141. if (AtD.core.isMarkedNode(event.target))
  142. AtD.suggest(event.target);
  143. };
  144. AtD.processXML = function(container_id, responseXML) {
  145. var results = AtD.core.processXML(responseXML);
  146. if (results.count > 0)
  147. results.count = AtD.core.markMyWords(jQuery('#' + container_id).contents(), results.errors);
  148. jQuery('#' + container_id).unbind('click', AtD.clickListener);
  149. jQuery('#' + container_id).click(AtD.clickListener);
  150. return results.count;
  151. };
  152. AtD.useSuggestion = function(word) {
  153. this.core.applySuggestion(AtD.errorElement, word);
  154. AtD.counter --;
  155. if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  156. AtD.callback_f.success(AtD.count);
  157. };
  158. AtD.editSelection = function() {
  159. var parent = AtD.errorElement.parent();
  160. if (AtD.callback_f != undefined && AtD.callback_f.editSelection != undefined)
  161. AtD.callback_f.editSelection(AtD.errorElement);
  162. if (AtD.errorElement.parent() != parent) {
  163. AtD.counter --;
  164. if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  165. AtD.callback_f.success(AtD.count);
  166. }
  167. };
  168. AtD.ignoreSuggestion = function() {
  169. AtD.core.removeParent(AtD.errorElement);
  170. AtD.counter --;
  171. if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  172. AtD.callback_f.success(AtD.count);
  173. };
  174. AtD.ignoreAll = function(container_id) {
  175. var target = AtD.errorElement.text();
  176. var removed = AtD._removeWords(container_id, target);
  177. AtD.counter -= removed;
  178. if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
  179. AtD.callback_f.success(AtD.count);
  180. if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined) {
  181. AtD.callback_f.ignore(target);
  182. AtD.core.setIgnoreStrings(target);
  183. }
  184. };
  185. AtD.explainError = function() {
  186. if (AtD.callback_f != undefined && AtD.callback_f.explain != undefined)
  187. AtD.callback_f.explain(AtD.explainURL);
  188. };
  189. AtD.suggest = function(element) {
  190. /* construct the menu if it doesn't already exist */
  191. if (jQuery('#suggestmenu').length == 0) {
  192. var suggest = jQuery('<div id="suggestmenu"></div>');
  193. suggest.prependTo('body');
  194. }
  195. else {
  196. var suggest = jQuery('#suggestmenu');
  197. suggest.hide();
  198. }
  199. /* find the correct suggestions object */
  200. errorDescription = AtD.core.findSuggestion(element);
  201. /* build up the menu y0 */
  202. AtD.errorElement = jQuery(element);
  203. suggest.empty();
  204. if (errorDescription == undefined) {
  205. suggest.append('<strong>' + AtD.getLang('menu_title_no_suggestions', 'No suggestions') + '</strong>');
  206. }
  207. else if (errorDescription["suggestions"].length == 0) {
  208. suggest.append('<strong>' + errorDescription['description'] + '</strong>');
  209. }
  210. else {
  211. suggest.append('<strong>' + errorDescription['description'] + '</strong>');
  212. for (var i = 0; i < errorDescription["suggestions"].length; i++) {
  213. (function(sugg) {
  214. suggest.append('<a href="javascript:AtD.useSuggestion(\'' + sugg.replace(/'/, '\\\'') + '\')">' + sugg + '</a>');
  215. })(errorDescription["suggestions"][i]);
  216. }
  217. }
  218. /* do the explain menu if configured */
  219. if (AtD.callback_f != undefined && AtD.callback_f.explain != undefined && errorDescription['moreinfo'] != undefined) {
  220. suggest.append('<a href="javascript:AtD.explainError()" class="spell_sep_top">' + AtD.getLang('menu_option_explain', 'Explain...') + '</a>');
  221. AtD.explainURL = errorDescription['moreinfo'];
  222. }
  223. /* do the ignore option */
  224. suggest.append('<a href="javascript:AtD.ignoreSuggestion()" class="spell_sep_top">' + AtD.getLang('menu_option_ignore_once', 'Ignore suggestion') + '</a>');
  225. /* add the edit in place and ignore always option */
  226. if (AtD.callback_f != undefined && AtD.callback_f.editSelection != undefined) {
  227. if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined)
  228. suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')">' + AtD.getLang('menu_option_ignore_always', 'Ignore always') + '</a>');
  229. else
  230. suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')">' + AtD.getLang('menu_option_ignore_all', 'Ignore all') + '</a>');
  231. suggest.append('<a href="javascript:AtD.editSelection(\'' + AtD.container + '\')" class="spell_sep_bottom spell_sep_top">' + AtD.getLang('menu_option_edit_selection', 'Edit Selection...') + '</a>');
  232. }
  233. else {
  234. if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined)
  235. suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')" class="spell_sep_bottom">' + AtD.getLang('menu_option_ignore_always', 'Ignore always') + '</a>');
  236. else
  237. suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')" class="spell_sep_bottom">' + AtD.getLang('menu_option_ignore_all', 'Ignore all') + '</a>');
  238. }
  239. /* show the menu */
  240. var pos = jQuery(element).offset();
  241. var width = jQuery(element).width();
  242. /* a sanity check for Internet Explorer--my favorite browser in every possible way */
  243. if (width > 100)
  244. width = 50;
  245. jQuery(suggest).css({ left: (pos.left + width) + 'px', top: pos.top + 'px' });
  246. jQuery(suggest).fadeIn(200);
  247. /* bind events to make the menu disappear when the user clicks outside of it */
  248. AtD.suggestShow = true;
  249. setTimeout(function() {
  250. jQuery("body").bind("click", function() {
  251. if (!AtD.suggestShow)
  252. jQuery('#suggestmenu').fadeOut(200);
  253. });
  254. }, 1);
  255. setTimeout(function() {
  256. AtD.suggestShow = false;
  257. }, 2);
  258. };
  259. AtD._removeWords = function(container_id, w) {
  260. return this.core.removeWords(jQuery('#' + container_id), w);
  261. };
  262. /*
  263. * Set prototypes used by AtD Core UI
  264. */
  265. AtD.initCoreModule = function() {
  266. var core = new AtDCore();
  267. core.hasClass = function(node, className) {
  268. return jQuery(node).hasClass(className);
  269. };
  270. core.map = jQuery.map;
  271. core.contents = function(node) {
  272. return jQuery(node).contents();
  273. };
  274. core.replaceWith = function(old_node, new_node) {
  275. return jQuery(old_node).replaceWith(new_node);
  276. };
  277. core.findSpans = function(parent) {
  278. return jQuery.makeArray(parent.find('span'));
  279. };
  280. core.create = function(string, isTextNode) {
  281. // replace out all tags with &-equivalents so that we preserve tag text.
  282. string = string.replace(/\&/g, '&amp;');
  283. string = string.replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
  284. // find all instances of AtD-created spans
  285. var matches = string.match(/\&lt;span class="hidden\w+?" pre="[^"]*"\&gt;.*?\&lt;\/span\&gt;/g);
  286. // ... and fix the tags in those substrings.
  287. if (matches) {
  288. for (var x = 0; x < matches.length; x++) {
  289. string = string.replace(matches[x], matches[x].replace(/\&lt;/gi, '<').replace(/\&gt;/gi, '>'));
  290. };
  291. }
  292. if (core.isIE()) {
  293. // and... one more round of corrections for our friends over at the Internet Explorer
  294. matches = string.match(/\&lt;span class="mceItemHidden"\&gt;\&amp;nbsp;\&lt;\/span&gt;/g, string);
  295. //|&lt;BR.*?class.*?atd_remove_me.*?\&gt;/gi, string);
  296. if (matches) {
  297. for (var x = 0; x < matches.length; x++) {
  298. string = string.replace(matches[x], matches[x].replace(/\&lt;/gi, '<').replace(/\&gt;/gi, '>').replace(/\&amp;/gi, '&'));
  299. };
  300. }
  301. }
  302. node = jQuery('<span class="mceItemHidden"></span>');
  303. node.html(string);
  304. return node;
  305. };
  306. core.remove = function(node) {
  307. return jQuery(node).remove();
  308. };
  309. core.removeParent = function(node) {
  310. /* unwrap exists in jQuery 1.4+ only. Thankfully because replaceWith as-used here won't work in 1.4 */
  311. if (jQuery(node).unwrap)
  312. return jQuery(node).contents().unwrap();
  313. else
  314. return jQuery(node).replaceWith(jQuery(node).html());
  315. };
  316. core.getAttrib = function(node, name) {
  317. return jQuery(node).attr(name);
  318. };
  319. return core;
  320. };
  321. AtD.core = AtD.initCoreModule();