Changeset ffa6c10 in github
- Timestamp:
- May 1, 2009 12:58:25 PM (4 years ago)
- Branches:
- master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
- Children:
- 762a699
- Parents:
- 82475f4
- Files:
-
- 3 edited
-
program/js/app.js (modified) (3 diffs)
-
program/js/googiespell.js (modified) (1 diff)
-
skins/default/googiespell.css (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
program/js/app.js
r23387ef rffa6c10 903 903 } 904 904 else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) { 905 this.env.spellcheck.spellCheck(this.env.spellcheck.check_link); 906 this.set_spellcheck_state('checking'); 905 this.env.spellcheck.spellCheck(); 907 906 } 908 907 break; … … 2124 2123 // stop spellchecking process 2125 2124 if (!vis) 2126 this.stop_spellchecking();2127 2125 this.stop_spellchecking(); 2126 2128 2127 this.env.spellcheck.check_link.style.visibility = vis ? 'visible' : 'hidden'; 2129 2128 this.env.spellcheck.switch_lan_pic.style.visibility = vis ? 'visible' : 'hidden'; … … 2133 2132 this.set_spellcheck_state = function(s) 2134 2133 { 2135 this.spellcheck_ready = (s=='check_spelling' || s==' ready');2134 this.spellcheck_ready = (s=='check_spelling' || s=='spell_check' || s=='ready'); 2136 2135 this.enable_command('spellcheck', this.spellcheck_ready); 2137 2136 }; -
program/js/googiespell.js
r2c63370 rffa6c10 1 1 /* 2 Last Modified: 28/04/06 16:28:09 3 4 AmiJs library 5 A very small library with DOM and Ajax functions. 6 For a much larger script look on http://www.mochikit.com/ 7 AUTHOR 2 Last Modified: 29/04/07 18:44:48 3 4 AJS JavaScript library 5 A very small library with a lot of functionality 6 AUTHOR 8 7 4mir Salihefendic (http://amix.dk) - amix@amix.dk 9 LICENSE8 LICENSE 10 9 Copyright (c) 2006 Amir Salihefendic. All rights reserved. 11 10 Copyright (c) 2005 Bob Ippolito. All rights reserved. 12 11 http://www.opensource.org/licenses/mit-license.php 13 VERSION14 2.115 SITE16 http:// amix.dk/amijs12 VERSION 13 4.0 14 SITE 15 http://orangoo.com/AmiNation/AJS 17 16 **/ 18 17 if(!AJS) { 19 18 var AJS = { 19 BASE_URL: "", 20 21 drag_obj: null, 22 drag_elm: null, 23 _drop_zones: [], 24 _drag_zones: [], 25 _cur_pos: null, 26 27 ajaxErrorHandler: null, 28 20 29 //// 21 // Accessor functions30 // General accessor functions 22 31 //// 23 /** 24 * @returns The element with the id 25 */ 26 getElement: function(id) { 27 if(typeof(id) == "string") 28 return document.getElementById(id); 29 else 30 return id; 31 }, 32 33 /** 34 * @returns The elements with the ids 35 */ 36 getElements: function(/*id1, id2, id3*/) { 37 var elements = new Array(); 38 for (var i = 0; i < arguments.length; i++) { 39 var element = this.getElement(arguments[i]); 40 elements.push(element); 41 } 42 return elements; 43 }, 44 45 /** 46 * @returns The GET query argument 47 */ 48 getQueryArgument: function(var_name) { 49 var query = window.location.search.substring(1); 50 var vars = query.split("&"); 51 for (var i=0;i<vars.length;i++) { 52 var pair = vars[i].split("="); 53 if (pair[0] == var_name) { 54 return pair[1]; 55 } 56 } 57 return null; 58 }, 59 60 /** 61 * @returns If the browser is Internet Explorer 62 */ 63 isIe: function() { 64 return (navigator.userAgent.toLowerCase().indexOf("msie") != -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1); 65 }, 66 67 /** 68 * @returns The document body 69 */ 70 getBody: function() { 71 return this.getElementsByTagAndClassName('body')[0] 72 }, 73 74 /** 75 * @returns All the elements that have a specific tag name or class name 76 */ 77 getElementsByTagAndClassName: function(tag_name, class_name, /*optional*/ parent) { 78 var class_elements = new Array(); 79 if(!this.isDefined(parent)) 80 parent = document; 81 if(!this.isDefined(tag_name)) 82 tag_name = '*'; 83 84 var els = parent.getElementsByTagName(tag_name); 85 var els_len = els.length; 86 var pattern = new RegExp("(^|\\s)" + class_name + "(\\s|$)"); 87 88 for (i = 0, j = 0; i < els_len; i++) { 89 if ( pattern.test(els[i].className) || class_name == null ) { 90 class_elements[j] = els[i]; 91 j++; 92 } 93 } 94 return class_elements; 95 }, 32 getQueryArgument: function(var_name) { 33 var query = window.location.search.substring(1); 34 var vars = query.split("&"); 35 for (var i=0;i<vars.length;i++) { 36 var pair = vars[i].split("="); 37 if (pair[0] == var_name) { 38 return pair[1]; 39 } 40 } 41 return null; 42 }, 43 44 isIe: function() { 45 return (navigator.userAgent.toLowerCase().indexOf("msie") != -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1); 46 }, 47 isNetscape7: function() { 48 return (navigator.userAgent.toLowerCase().indexOf("netscape") != -1 && navigator.userAgent.toLowerCase().indexOf("7.") != -1); 49 }, 50 isSafari: function() { 51 return (navigator.userAgent.toLowerCase().indexOf("khtml") != -1); 52 }, 53 isOpera: function() { 54 return (navigator.userAgent.toLowerCase().indexOf("opera") != -1); 55 }, 56 isMozilla: function() { 57 return (navigator.userAgent.toLowerCase().indexOf("gecko") != -1 && navigator.productSub >= 20030210); 58 }, 59 isMac: function() { 60 return (navigator.userAgent.toLowerCase().indexOf('macintosh') != -1); 61 }, 96 62 97 63 98 64 //// 99 // DOM manipulation65 // Array functions 100 66 //// 101 /** 102 * Appends some nodes to a node 103 */ 104 appendChildNodes: function(node/*, nodes...*/) { 105 if(arguments.length >= 2) { 106 for(var i=1; i < arguments.length; i++) { 107 var n = arguments[i]; 108 if(typeof(n) == "string") 109 n = document.createTextNode(n); 110 if(this.isDefined(n)) 111 node.appendChild(n); 112 } 113 } 114 return node; 115 }, 116 117 /** 118 * Replaces a nodes children with another node(s) 119 */ 120 replaceChildNodes: function(node/*, nodes...*/) { 121 var child; 122 while ((child = node.firstChild)) { 123 node.removeChild(child); 124 } 125 if (arguments.length < 2) { 126 return node; 127 } else { 128 return this.appendChildNodes.apply(this, arguments); 129 } 130 }, 131 132 /** 133 * Insert a node after another node 134 */ 135 insertAfter: function(node, referenceNode) { 136 referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling); 137 }, 138 139 /** 140 * Insert a node before another node 141 */ 142 insertBefore: function(node, referenceNode) { 143 referenceNode.parentNode.insertBefore(node, referenceNode); 144 }, 145 146 /** 147 * Shows the element 148 */ 149 showElement: function(elm) { 150 elm.style.display = ''; 151 }, 152 153 /** 154 * Hides the element 155 */ 156 hideElement: function(elm) { 157 elm.style.display = 'none'; 158 }, 159 160 isElementHidden: function(elm) { 161 return elm.style.visibility == "hidden"; 162 }, 163 164 /** 165 * Swaps one element with another. To delete use swapDOM(elm, null) 166 */ 167 swapDOM: function(dest, src) { 168 dest = this.getElement(dest); 169 var parent = dest.parentNode; 170 if (src) { 171 src = this.getElement(src); 172 parent.replaceChild(src, dest); 173 } else { 174 parent.removeChild(dest); 175 } 176 return src; 177 }, 178 179 /** 180 * Removes an element from the world 181 */ 182 removeElement: function(elm) { 183 this.swapDOM(elm, null); 184 }, 185 186 /** 187 * @returns Is an object a dictionary? 188 */ 189 isDict: function(o) { 190 var str_repr = String(o); 191 return str_repr.indexOf(" Object") != -1; 192 }, 193 194 /** 195 * Creates a DOM element 196 * @param {String} name The elements DOM name 197 * @param {Dict} attrs Attributes sent to the function 198 */ 199 createDOM: function(name, attrs) { 200 var i=0; 201 elm = document.createElement(name); 202 203 if(this.isDict(attrs[i])) { 204 for(k in attrs[0]) { 205 if(k == "style") 206 elm.style.cssText = attrs[0][k]; 207 else if(k == "class") 208 elm.className = attrs[0][k]; 67 //Shortcut: AJS.$A 68 createArray: function(v) { 69 if(AJS.isArray(v) && !AJS.isString(v)) 70 return v; 71 else if(!v) 72 return []; 209 73 else 210 elm.setAttribute(k, attrs[0][k]); 211 } 212 i++; 213 } 214 215 if(attrs[0] == null) 216 i = 1; 217 218 for(i; i < attrs.length; i++) { 219 var n = attrs[i]; 220 if(this.isDefined(n)) { 221 if(typeof(n) == "string") 222 n = document.createTextNode(n); 223 elm.appendChild(n); 224 } 225 } 226 return elm; 227 }, 228 229 UL: function() { return this.createDOM.apply(this, ["ul", arguments]); }, 230 LI: function() { return this.createDOM.apply(this, ["li", arguments]); }, 231 TD: function() { return this.createDOM.apply(this, ["td", arguments]); }, 232 TR: function() { return this.createDOM.apply(this, ["tr", arguments]); }, 233 TH: function() { return this.createDOM.apply(this, ["th", arguments]); }, 234 TBODY: function() { return this.createDOM.apply(this, ["tbody", arguments]); }, 235 TABLE: function() { return this.createDOM.apply(this, ["table", arguments]); }, 236 INPUT: function() { return this.createDOM.apply(this, ["input", arguments]); }, 237 SPAN: function() { return this.createDOM.apply(this, ["span", arguments]); }, 238 B: function() { return this.createDOM.apply(this, ["b", arguments]); }, 239 A: function() { return this.createDOM.apply(this, ["a", arguments]); }, 240 DIV: function() { return this.createDOM.apply(this, ["div", arguments]); }, 241 IMG: function() { return this.createDOM.apply(this, ["img", arguments]); }, 242 BUTTON: function() { return this.createDOM.apply(this, ["button", arguments]); }, 243 H1: function() { return this.createDOM.apply(this, ["h1", arguments]); }, 244 H2: function() { return this.createDOM.apply(this, ["h2", arguments]); }, 245 H3: function() { return this.createDOM.apply(this, ["h3", arguments]); }, 246 BR: function() { return this.createDOM.apply(this, ["br", arguments]); }, 247 TEXTAREA: function() { return this.createDOM.apply(this, ["textarea", arguments]); }, 248 FORM: function() { return this.createDOM.apply(this, ["form", arguments]); }, 249 P: function() { return this.createDOM.apply(this, ["p", arguments]); }, 250 SELECT: function() { return this.createDOM.apply(this, ["select", arguments]); }, 251 OPTION: function() { return this.createDOM.apply(this, ["option", arguments]); }, 252 TN: function(text) { return document.createTextNode(text); }, 253 IFRAME: function() { return this.createDOM.apply(this, ["iframe", arguments]); }, 254 SCRIPT: function() { return this.createDOM.apply(this, ["script", arguments]); }, 74 return [v]; 75 }, 76 77 forceArray: function(args) { 78 var r = []; 79 AJS.map(args, function(elm) { 80 r.push(elm); 81 }); 82 return r; 83 }, 84 85 join: function(delim, list) { 86 try { 87 return list.join(delim); 88 } 89 catch(e) { 90 var r = list[0] || ''; 91 AJS.map(list, function(elm) { 92 r += delim + elm; 93 }, 1); 94 return r + ''; 95 } 96 }, 97 98 isIn: function(elm, list) { 99 var i = AJS.getIndex(elm, list); 100 if(i != -1) 101 return true; 102 else 103 return false; 104 }, 105 106 getIndex: function(elm, list/*optional*/, eval_fn) { 107 for(var i=0; i < list.length; i++) 108 if(eval_fn && eval_fn(list[i]) || elm == list[i]) 109 return i; 110 return -1; 111 }, 112 113 getFirst: function(list) { 114 if(list.length > 0) 115 return list[0]; 116 else 117 return null; 118 }, 119 120 getLast: function(list) { 121 if(list.length > 0) 122 return list[list.length-1]; 123 else 124 return null; 125 }, 126 127 update: function(l1, l2) { 128 for(var i in l2) 129 l1[i] = l2[i]; 130 return l1; 131 }, 132 133 flattenList: function(list) { 134 var r = []; 135 var _flatten = function(r, l) { 136 AJS.map(l, function(o) { 137 if(o == null) {} 138 else if (AJS.isArray(o)) 139 _flatten(r, o); 140 else 141 r.push(o); 142 }); 143 } 144 _flatten(r, list); 145 return r; 146 }, 147 148 149 //// 150 // Functional programming 151 //// 152 map: function(list, fn,/*optional*/ start_index, end_index) { 153 var i = 0, l = list.length; 154 if(start_index) 155 i = start_index; 156 if(end_index) 157 l = end_index; 158 for(i; i < l; i++) { 159 var val = fn.apply(null, [list[i], i]); 160 if(val != undefined) 161 return val; 162 } 163 }, 164 165 rmap: function(list, fn) { 166 var i = list.length-1, l = 0; 167 for(i; i >= l; i--) { 168 var val = fn.apply(null, [list[i], i]); 169 if(val != undefined) 170 return val; 171 } 172 }, 173 174 filter: function(list, fn, /*optional*/ start_index, end_index) { 175 var r = []; 176 AJS.map(list, function(elm) { 177 if(fn(elm)) 178 r.push(elm); 179 }, start_index, end_index); 180 return r; 181 }, 182 183 partial: function(fn) { 184 var args = AJS.$FA(arguments); 185 args.shift(); 186 return function() { 187 args = args.concat(AJS.$FA(arguments)); 188 return fn.apply(window, args); 189 } 190 }, 191 192 193 //// 194 // DOM functions 195 //// 196 //Shortcut: AJS.$ 197 getElement: function(id) { 198 if(AJS.isString(id) || AJS.isNumber(id)) 199 return document.getElementById(id); 200 else 201 return id; 202 }, 203 204 //Shortcut: AJS.$$ 205 getElements: function(/*id1, id2, id3*/) { 206 var args = AJS.forceArray(arguments); 207 var elements = new Array(); 208 for (var i = 0; i < args.length; i++) { 209 var element = AJS.getElement(args[i]); 210 elements.push(element); 211 } 212 return elements; 213 }, 214 215 //Shortcut: AJS.$bytc 216 getElementsByTagAndClassName: function(tag_name, class_name, /*optional*/ parent) { 217 var class_elements = []; 218 if(!AJS.isDefined(parent)) 219 parent = document; 220 if(!AJS.isDefined(tag_name)) 221 tag_name = '*'; 222 223 var els = parent.getElementsByTagName(tag_name); 224 var els_len = els.length; 225 var pattern = new RegExp("(^|\\s)" + class_name + "(\\s|$)"); 226 227 for (i = 0, j = 0; i < els_len; i++) { 228 if ( pattern.test(els[i].className) || class_name == null ) { 229 class_elements[j] = els[i]; 230 j++; 231 } 232 } 233 return class_elements; 234 }, 235 236 _nodeWalk: function(elm, tag_name, class_name, fn_next_elm) { 237 var p = fn_next_elm(elm); 238 239 var checkFn; 240 if(tag_name && class_name) { 241 checkFn = function(p) { 242 return AJS.nodeName(p) == tag_name && AJS.hasClass(p, class_name); 243 } 244 } 245 else if(tag_name) { 246 checkFn = function(p) { return AJS.nodeName(p) == tag_name; } 247 } 248 else { 249 checkFn = function(p) { return AJS.hasClass(p, class_name); } 250 } 251 252 while(p) { 253 if(checkFn(p)) 254 return p; 255 p = fn_next_elm(p); 256 } 257 return null; 258 }, 259 260 getParentBytc: function(elm, tag_name, class_name) { 261 return AJS._nodeWalk(elm, tag_name, class_name, function(m) { return m.parentNode; }); 262 }, 263 264 getPreviousSiblingBytc: function(elm, tag_name, class_name) { 265 return AJS._nodeWalk(elm, tag_name, class_name, function(m) { return m.previousSibling; }); 266 }, 267 268 getNextSiblingBytc: function(elm, tag_name, class_name) { 269 return AJS._nodeWalk(elm, tag_name, class_name, function(m) { return m.nextSibling; }); 270 }, 271 272 //Shortcut: AJS.$f 273 getFormElement: function(form, name) { 274 form = AJS.$(form); 275 var r = null; 276 AJS.map(form.elements, function(elm) { 277 if(elm.name && elm.name == name) 278 r = elm; 279 }); 280 return r; 281 }, 282 283 formContents: function(form) { 284 var form = AJS.$(form); 285 var r = {}; 286 var fn = function(elms) { 287 AJS.map(elms, function(e) { 288 if(e.name) 289 r[e.name] = e.value || ''; 290 }); 291 } 292 fn(AJS.$bytc('input', null, form)); 293 fn(AJS.$bytc('textarea', null, form)); 294 return r; 295 }, 296 297 getBody: function() { 298 return AJS.$bytc('body')[0] 299 }, 300 301 nodeName: function(elm) { 302 return elm.nodeName.toLowerCase(); 303 }, 304 305 hasParent: function(elm, parent_to_consider, max_look_up) { 306 if(elm == parent_to_consider) 307 return true; 308 if(max_look_up == 0) 309 return false; 310 return AJS.hasParent(elm.parentNode, parent_to_consider, max_look_up-1); 311 }, 312 313 isElementHidden: function(elm) { 314 return ((elm.style.display == "none") || (elm.style.visibility == "hidden")); 315 }, 316 317 //Shortcut: AJS.DI 318 documentInsert: function(elm) { 319 if(typeof(elm) == 'string') 320 elm = AJS.HTML2DOM(elm); 321 document.write('<span id="dummy_holder"></span>'); 322 AJS.swapDOM(AJS.$('dummy_holder'), elm); 323 }, 324 325 cloner: function(element) { 326 return function() { 327 return element.cloneNode(true); 328 } 329 }, 330 331 appendToTop: function(elm/*, elms...*/) { 332 var args = AJS.forceArray(arguments).slice(1); 333 if(args.length >= 1) { 334 var first_child = elm.firstChild; 335 if(first_child) { 336 while(true) { 337 var t_elm = args.shift(); 338 if(t_elm) 339 AJS.insertBefore(t_elm, first_child); 340 else 341 break; 342 } 343 } 344 else { 345 AJS.ACN.apply(null, arguments); 346 } 347 } 348 return elm; 349 }, 350 351 //Shortcut: AJS.ACN 352 appendChildNodes: function(elm/*, elms...*/) { 353 if(arguments.length >= 2) { 354 AJS.map(arguments, function(n) { 355 if(AJS.isString(n)) 356 n = AJS.TN(n); 357 if(AJS.isDefined(n)) 358 elm.appendChild(n); 359 }, 1); 360 } 361 return elm; 362 }, 363 364 //Shortcut: AJS.RCN 365 replaceChildNodes: function(elm/*, elms...*/) { 366 var child; 367 while ((child = elm.firstChild)) 368 elm.removeChild(child); 369 if (arguments.length < 2) 370 return elm; 371 else 372 return AJS.appendChildNodes.apply(null, arguments); 373 return elm; 374 }, 375 376 insertAfter: function(elm, reference_elm) { 377 reference_elm.parentNode.insertBefore(elm, reference_elm.nextSibling); 378 return elm; 379 }, 380 381 insertBefore: function(elm, reference_elm) { 382 reference_elm.parentNode.insertBefore(elm, reference_elm); 383 return elm; 384 }, 385 386 showElement: function(/*elms...*/) { 387 var args = AJS.forceArray(arguments); 388 AJS.map(args, function(elm) { elm.style.display = ''}); 389 }, 390 391 hideElement: function(elm) { 392 var args = AJS.forceArray(arguments); 393 AJS.map(args, function(elm) { elm.style.display = 'none'}); 394 }, 395 396 swapDOM: function(dest, src) { 397 dest = AJS.getElement(dest); 398 var parent = dest.parentNode; 399 if (src) { 400 src = AJS.getElement(src); 401 parent.replaceChild(src, dest); 402 } else { 403 parent.removeChild(dest); 404 } 405 return src; 406 }, 407 408 removeElement: function(/*elm1, elm2...*/) { 409 var args = AJS.forceArray(arguments); 410 AJS.map(args, function(elm) { AJS.swapDOM(elm, null); }); 411 }, 412 413 createDOM: function(name, attrs) { 414 var i=0, attr; 415 elm = document.createElement(name); 416 417 if(AJS.isDict(attrs[i])) { 418 for(k in attrs[0]) { 419 attr = attrs[0][k]; 420 if(k == "style") 421 elm.style.cssText = attr; 422 else if(k == "class" || k == 'className') 423 elm.className = attr; 424 else { 425 elm.setAttribute(k, attr); 426 } 427 } 428 i++; 429 } 430 431 if(attrs[0] == null) 432 i = 1; 433 434 AJS.map(attrs, function(n) { 435 if(n) { 436 if(AJS.isString(n) || AJS.isNumber(n)) 437 n = AJS.TN(n); 438 elm.appendChild(n); 439 } 440 }, i); 441 return elm; 442 }, 443 444 _createDomShortcuts: function() { 445 var elms = [ 446 "ul", "li", "td", "tr", "th", 447 "tbody", "table", "input", "span", "b", 448 "a", "div", "img", "button", "h1", 449 "h2", "h3", "br", "textarea", "form", 450 "p", "select", "option", "optgroup", "iframe", "script", 451 "center", "dl", "dt", "dd", "small", 452 "pre" 453 ]; 454 var extends_ajs = function(elm) { 455 AJS[elm.toUpperCase()] = function() { 456 return AJS.createDOM.apply(null, [elm, arguments]); 457 }; 458 } 459 AJS.map(elms, extends_ajs); 460 AJS.TN = function(text) { return document.createTextNode(text) }; 461 }, 462 463 getCssDim: function(dim) { 464 if(AJS.isString(dim)) 465 return dim; 466 else 467 return dim + "px"; 468 }, 469 getCssProperty: function(elm, prop) { 470 elm = AJS.$(elm); 471 var y; 472 if(elm.currentStyle) 473 y = elm.currentStyle[prop]; 474 else if (window.getComputedStyle) 475 y = document.defaultView.getComputedStyle(elm,null).getPropertyValue(prop); 476 return y; 477 }, 478 479 setStyle: function(/*elm1, elm2..., property, new_value*/) { 480 var args = AJS.forceArray(arguments); 481 var new_val = args.pop(); 482 var property = args.pop(); 483 AJS.map(args, function(elm) { 484 elm.style[property] = AJS.getCssDim(new_val); 485 }); 486 }, 487 488 setWidth: function(/*elm1, elm2..., width*/) { 489 var args = AJS.forceArray(arguments); 490 args.splice(args.length-1, 0, 'width'); 491 AJS.setStyle.apply(null, args); 492 }, 493 setHeight: function(/*elm1, elm2..., height*/) { 494 var args = AJS.forceArray(arguments); 495 args.splice(args.length-1, 0, 'height'); 496 AJS.setStyle.apply(null, args); 497 }, 498 setLeft: function(/*elm1, elm2..., left*/) { 499 var args = AJS.forceArray(arguments); 500 args.splice(args.length-1, 0, 'left'); 501 AJS.setStyle.apply(null, args); 502 }, 503 setTop: function(/*elm1, elm2..., top*/) { 504 var args = AJS.forceArray(arguments); 505 args.splice(args.length-1, 0, 'top'); 506 AJS.setStyle.apply(null, args); 507 }, 508 setClass: function(/*elm1, elm2..., className*/) { 509 var args = AJS.forceArray(arguments); 510 var c = args.pop(); 511 AJS.map(args, function(elm) { elm.className = c}); 512 }, 513 addClass: function(/*elm1, elm2..., className*/) { 514 var args = AJS.forceArray(arguments); 515 var cls = args.pop(); 516 var add_class = function(o) { 517 if(!new RegExp("(^|\\s)" + cls + "(\\s|$)").test(o.className)) 518 o.className += (o.className ? " " : "") + cls; 519 }; 520 AJS.map(args, function(elm) { add_class(elm); }); 521 }, 522 hasClass: function(elm, cls) { 523 if(!elm.className) 524 return false; 525 return elm.className == cls || 526 elm.className.search(new RegExp(" " + cls + "|^" + cls)) != -1 527 }, 528 removeClass: function(/*elm1, elm2..., className*/) { 529 var args = AJS.forceArray(arguments); 530 var cls = args.pop(); 531 var rm_class = function(o) { 532 o.className = o.className.replace(new RegExp("\\s?" + cls, 'g'), ""); 533 }; 534 AJS.map(args, function(elm) { rm_class(elm); }); 535 }, 536 537 setHTML: function(elm, html) { 538 elm.innerHTML = html; 539 return elm; 540 }, 541 542 RND: function(tmpl, ns, scope) { 543 scope = scope || window; 544 var fn = function(w, g) { 545 g = g.split("|"); 546 var cnt = ns[g[0]]; 547 for(var i=1; i < g.length; i++) 548 cnt = scope[g[i]](cnt); 549 if(cnt == '') 550 return ''; 551 if(cnt == 0 || cnt == -1) 552 cnt += ''; 553 return cnt || w; 554 }; 555 return tmpl.replace(/%\(([A-Za-z0-9_|.]*)\)/g, fn); 556 }, 557 558 HTML2DOM: function(html,/*optional*/ first_child) { 559 var d = AJS.DIV(); 560 d.innerHTML = html; 561 if(first_child) 562 return d.childNodes[0]; 563 else 564 return d; 565 }, 566 567 preloadImages: function(/*img_src1, ..., img_srcN*/) { 568 AJS.AEV(window, 'load', AJS.$p(function(args) { 569 AJS.map(args, function(src) { 570 var pic = new Image(); 571 pic.src = src; 572 }); 573 }, arguments)); 574 }, 575 576 577 //// 578 // Effects 579 //// 580 setOpacity: function(elm, p) { 581 elm.style.opacity = p; 582 elm.style.filter = "alpha(opacity="+ p*100 +")"; 583 }, 584 585 resetOpacity: function(elm) { 586 elm.style.opacity = 1; 587 elm.style.filter = ""; 588 }, 255 589 256 590 //// 257 591 // Ajax functions 258 592 //// 259 /** 260 * @returns A new XMLHttpRequest object 261 */ 262 getXMLHttpRequest: function() { 263 var try_these = [ 264 function () { return new XMLHttpRequest(); }, 265 function () { return new ActiveXObject('Msxml2.XMLHTTP'); }, 266 function () { return new ActiveXObject('Microsoft.XMLHTTP'); }, 267 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); }, 268 function () { throw "Browser does not support XMLHttpRequest"; } 269 ]; 270 for (var i = 0; i < try_these.length; i++) { 271 var func = try_these[i]; 272 try { 273 return func(); 274 } catch (e) { 275 } 276 } 277 }, 278 279 /** 280 * Use this function to do a simple HTTP Request 281 */ 282 doSimpleXMLHttpRequest: function(url) { 283 var req = this.getXMLHttpRequest(); 284 req.open("GET", url, true); 285 return this.sendXMLHttpRequest(req); 286 }, 287 288 getRequest: function(url, data) { 289 var req = this.getXMLHttpRequest(); 290 req.open("POST", url, true); 291 req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 292 return this.sendXMLHttpRequest(req); 293 }, 294 295 /** 296 * Send a XMLHttpRequest 297 */ 298 sendXMLHttpRequest: function(req, data) { 299 var d = new AJSDeferred(req); 300 301 var onreadystatechange = function () { 302 if (req.readyState == 4) { 593 getXMLHttpRequest: function() { 594 var try_these = [ 595 function () { return new XMLHttpRequest(); }, 596 function () { return new ActiveXObject('Msxml2.XMLHTTP'); }, 597 function () { return new ActiveXObject('Microsoft.XMLHTTP'); }, 598 function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); }, 599 function () { throw "Browser does not support XMLHttpRequest"; } 600 ]; 601 for (var i = 0; i < try_these.length; i++) { 602 var func = try_these[i]; 603 try { 604 return func(); 605 } catch (e) { 606 } 607 } 608 }, 609 610 getRequest: function(url, data, type) { 611 if(!type) 612 type = "POST"; 613 var req = AJS.getXMLHttpRequest(); 614 615 if(url.indexOf("http://") == -1) { 616 if(AJS.BASE_URL != '') { 617 if(AJS.BASE_URL.lastIndexOf('/') != AJS.BASE_URL.length-1) 618 AJS.BASE_URL += '/'; 619 url = AJS.BASE_URL + url; 620 } 621 } 622 623 req.open(type, url, true); 624 if(type == "POST") 625 req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 626 return AJS._sendXMLHttpRequest(req); 627 }, 628 629 _sendXMLHttpRequest: function(req, data) { 630 var d = new AJSDeferred(req); 631 632 var onreadystatechange = function () { 633 if (req.readyState == 4) { 634 var status = ''; 635 try { 636 status = req.status; 637 } 638 catch(e) {}; 639 if(status == 200 || status == 304 || req.responseText == null) { 640 d.callback(); 641 } 642 else { 643 if(d.errbacks.length == 0) { 644 if(AJS.ajaxErrorHandler) 645 AJS.ajaxErrorHandler(req.responseText, req); 646 } 647 else 648 d.errback(); 649 } 650 } 651 } 652 req.onreadystatechange = onreadystatechange; 653 return d; 654 }, 655 656 _reprString: function(o) { 657 return ('"' + o.replace(/(["\\])/g, '\\$1') + '"' 658 ).replace(/[\f]/g, "\\f" 659 ).replace(/[\b]/g, "\\b" 660 ).replace(/[\n]/g, "\\n" 661 ).replace(/[\t]/g, "\\t" 662 ).replace(/[\r]/g, "\\r"); 663 }, 664 665 _reprDate: function(db) { 666 var year = db.getFullYear(); 667 var dd = db.getDate(); 668 var mm = db.getMonth()+1; 669 670 var hh = db.getHours(); 671 var mins = db.getMinutes(); 672 673 function leadingZero(nr) { 674 if (nr < 10) nr = "0" + nr; 675 return nr; 676 } 677 if(hh == 24) hh = '00'; 678 679 var time = leadingZero(hh) + ':' + leadingZero(mins); 680 return '"' + year + '-' + mm + '-' + dd + 'T' + time + '"'; 681 }, 682 683 serializeJSON: function(o) { 684 var objtype = typeof(o); 685 if (objtype == "undefined") { 686 return "undefined"; 687 } else if (objtype == "number" || objtype == "boolean") { 688 return o + ""; 689 } else if (o === null) { 690 return "null"; 691 } 692 if (objtype == "string") { 693 return AJS._reprString(o); 694 } 695 if(objtype == 'object' && o.getFullYear) { 696 return AJS._reprDate(o); 697 } 698 var me = arguments.callee; 699 if (objtype != "function" && typeof(o.length) == "number") { 700 var res = []; 701 for (var i = 0; i < o.length; i++) { 702 var val = me(o[i]); 703 if (typeof(val) != "string") { 704 val = "undefined"; 705 } 706 res.push(val); 707 } 708 return "[" + res.join(",") + "]"; 709 } 710 // it's a function with no adapter, bad 711 if (objtype == "function") 712 return null; 713 res = []; 714 for (var k in o) { 715 var useKey; 716 if (typeof(k) == "number") { 717 useKey = '"' + k + '"'; 718 } else if (typeof(k) == "string") { 719 useKey = AJS._reprString(k); 720 } else { 721 // skip non-string or number keys 722 continue; 723 } 724 val = me(o[k]); 725 if (typeof(val) != "string") { 726 // skip non-serializable values 727 continue; 728 } 729 res.push(useKey + ":" + val); 730 } 731 return "{" + res.join(",") + "}"; 732 }, 733 734 loadJSONDoc: function(url) { 735 var d = AJS.getRequest(url); 736 var eval_req = function(data, req) { 737 var text = req.responseText; 738 if(text == "Error") 739 d.errback(req); 740 else 741 return AJS.evalTxt(text); 742 }; 743 d.addCallback(eval_req); 744 return d; 745 }, 746 747 evalTxt: function(txt) { 303 748 try { 304 var status = req.status; 305 } 306 catch(e) {}; 307 if(status == 200 || status == 304 || req.responseText == null) { 308 d.callback(req, data); 749 return eval('('+ txt + ')'); 750 } 751 catch(e) { 752 return eval(txt); 753 } 754 }, 755 756 evalScriptTags: function(html) { 757 var script_data = html.match(/<script.*?>((\n|\r|.)*?)<\/script>/g); 758 if(script_data != null) { 759 for(var i=0; i < script_data.length; i++) { 760 var script_only = script_data[i].replace(/<script.*?>/g, ""); 761 script_only = script_only.replace(/<\/script>/g, ""); 762 eval(script_only); 763 } 764 } 765 }, 766 767 queryArguments: function(data) { 768 var post_data = []; 769 for(k in data) 770 post_data.push(k + "=" + AJS.urlencode(data[k])); 771 return post_data.join("&"); 772 }, 773 774 775 //// 776 // Position and size 777 //// 778 getMousePos: function(e) { 779 var posx = 0; 780 var posy = 0; 781 if (!e) var e = window.event; 782 if (e.pageX || e.pageY) { 783 posx = e.pageX; 784 posy = e.pageY; 785 } 786 else if (e.clientX || e.clientY) { 787 posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 788 posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 789 } 790 return {x: posx, y: posy}; 791 }, 792 793 getScrollTop: function() { 794 //From: http://www.quirksmode.org/js/doctypes.html 795 var t; 796 if (document.documentElement && document.documentElement.scrollTop) 797 t = document.documentElement.scrollTop; 798 else if (document.body) 799 t = document.body.scrollTop; 800 return t; 801 }, 802 803 absolutePosition: function(elm) { 804 var posObj = {'x': elm.offsetLeft, 'y': elm.offsetTop}; 805 806 if(elm.offsetParent) { 807 var next = elm.offsetParent; 808 while(next) { 809 posObj.x += next.offsetLeft; 810 posObj.y += next.offsetTop; 811 next = next.offsetParent; 812 } 813 } 814 // safari bug 815 if (AJS.isSafari() && elm.style.position == 'absolute' ) { 816 posObj.x -= document.body.offsetLeft; 817 posObj.y -= document.body.offsetTop; 818 } 819 return posObj; 820 }, 821 822 getWindowSize: function(doc) { 823 doc = doc || document; 824 var win_w, win_h; 825 if (self.innerHeight) { 826 win_w = self.innerWidth; 827 win_h = self.innerHeight; 828 } else if (doc.documentElement && doc.documentElement.clientHeight) { 829 win_w = doc.documentElement.clientWidth; 830 win_h = doc.documentElement.clientHeight; 831 } else if (doc.body) { 832 win_w = doc.body.clientWidth; 833 win_h = doc.body.clientHeight; 834 } 835 return {'w': win_w, 'h': win_h}; 836 }, 837 838 isOverlapping: function(elm1, elm2) { 839 var pos_elm1 = AJS.absolutePosition(elm1); 840 var pos_elm2 = AJS.absolutePosition(elm2); 841 842 var top1 = pos_elm1.y; 843 var left1 = pos_elm1.x; 844 var right1 = left1 + elm1.offsetWidth; 845 var bottom1 = top1 + elm1.offsetHeight; 846 var top2 = pos_elm2.y; 847 var left2 = pos_elm2.x; 848 var right2 = left2 + elm2.offsetWidth; 849 var bottom2 = top2 + elm2.offsetHeight; 850 var getSign = function(v) { 851 if(v > 0) return "+"; 852 else if(v < 0) return "-"; 853 else return 0; 854 } 855 856 if ((getSign(top1 - bottom2) != getSign(bottom1 - top2)) && 857 (getSign(left1 - right2) != getSign(right1 - left2))) 858 return true; 859 return false; 860 }, 861 862 863 //// 864 // Events 865 //// 866 getEventElm: function(e) { 867 if(e && !e.type && !e.keyCode) 868 return e 869 var targ; 870 if (!e) var e = window.event; 871 if (e.target) targ = e.target; 872 else if (e.srcElement) targ = e.srcElement; 873 if (targ.nodeType == 3) // defeat Safari bug 874 targ = targ.parentNode; 875 return targ; 876 }, 877 878 _getRealScope: function(fn, /*optional*/ extra_args) { 879 extra_args = AJS.$A(extra_args); 880 var scope = fn._cscope || window; 881 882 return function() { 883 var args = AJS.$FA(arguments).concat(extra_args); 884 return fn.apply(scope, args); 885 }; 886 }, 887 888 _unloadListeners: function() { 889 if(AJS.listeners) 890 AJS.map(AJS.listeners, function(elm, type, fn) { AJS.REV(elm, type, fn) }); 891 AJS.listeners = []; 892 }, 893 894 setEventKey: function(e) { 895 e.key = e.keyCode ? e.keyCode : e.charCode; 896 897 if(window.event) { 898 e.ctrl = window.event.ctrlKey; 899 e.shift = window.event.shiftKey; 309 900 } 310 901 else { 311 d.errback(); 312 } 313 } 314 } 315 req.onreadystatechange = onreadystatechange; 316 return d; 317 }, 318 319 /** 320 * Represent an object as a string 321 */ 322 reprString: function(o) { 323 return ('"' + o.replace(/(["\\])/g, '\\$1') + '"' 324 ).replace(/[\f]/g, "\\f" 325 ).replace(/[\b]/g, "\\b" 326 ).replace(/[\n]/g, "\\n" 327 ).replace(/[\t]/g, "\\t" 328 ).replace(/[\r]/g, "\\r"); 329 }, 330 331 /** 332 * Serialize an object to JSON notation 333 */ 334 serializeJSON: function(o) { 335 var objtype = typeof(o); 336 if (objtype == "undefined") { 337 return "undefined"; 338 } else if (objtype == "number" || objtype == "boolean") { 339 return o + ""; 340 } else if (o === null) { 341 return "null"; 342 } 343 if (objtype == "string") { 344 return this.reprString(o); 345 } 346 var me = arguments.callee; 347 var newObj; 348 if (typeof(o.__json__) == "function") { 349 newObj = o.__json__(); 350 if (o !== newObj) { 351 return me(newObj); 352 } 353 } 354 if (typeof(o.json) == "function") { 355 newObj = o.json(); 356 if (o !== newObj) { 357 return me(newObj); 358 } 359 } 360 if (objtype != "function" && typeof(o.length) == "number") { 361 var res = []; 362 for (var i = 0; i < o.length; i++) { 363 var val = me(o[i]); 364 if (typeof(val) != "string") { 365 val = "undefined"; 366 } 367 res.push(val); 368 } 369 return "[" + res.join(",") + "]"; 370 } 371 res = []; 372 for (var k in o) { 373 var useKey; 374 if (typeof(k) == "number") { 375 useKey = '"' + k + '"'; 376 } else if (typeof(k) == "string") { 377 useKey = this.reprString(k); 378 } else { 379 // skip non-string or number keys 380 continue; 381 } 382 val = me(o[k]); 383 if (typeof(val) != "string") { 384 // skip non-serializable values 385 continue; 386 } 387 res.push(useKey + ":" + val); 388 } 389 return "{" + res.join(",") + "}"; 390 }, 391 392 /** 393 * Send and recive JSON using GET 394 */ 395 loadJSONDoc: function(url) { 396 var d = this.getRequest(url); 397 var eval_req = function(req) { 398 var text = req.responseText; 399 return eval('(' + text + ')'); 400 }; 401 d.addCallback(eval_req); 402 return d; 403 }, 404 405 902 e.ctrl = e.ctrlKey; 903 e.shift = e.shiftKey; 904 } 905 switch(e.key) { 906 case 63232: 907 e.key = 38; 908 break; 909 case 63233: 910 e.key = 40; 911 break; 912 case 63235: 913 e.key = 39; 914 break; 915 case 63234: 916 e.key = 37; 917 break; 918 } 919 }, 920 921 //Shortcut: AJS.AEV 922 addEventListener: function(elm, type, fn, /*optional*/listen_once, cancle_bubble) { 923 if(!cancle_bubble) 924 cancle_bubble = false; 925 926 var elms = AJS.$A(elm); 927 AJS.map(elms, function(elmz) { 928 if(listen_once) 929 fn = AJS._listenOnce(elmz, type, fn); 930 931 //Hack since it does not work in all browsers 932 if(AJS.isIn(type, ['submit', 'load', 'scroll', 'resize'])) { 933 var old = elm['on' + type]; 934 elm['on' + type] = function() { 935 if(old) { 936 fn(arguments); 937 return old(arguments); 938 } 939 else 940 return fn(arguments); 941 }; 942 return; 943 } 944 945 //Fix keyCode 946 if(AJS.isIn(type, ['keypress', 'keydown', 'keyup', 'click'])) { 947 var old_fn = fn; 948 fn = function(e) { 949 AJS.setEventKey(e); 950 return old_fn.apply(null, arguments); 951 } 952 } 953 954 if (elmz.attachEvent) { 955 //FIXME: We ignore cancle_bubble for IE... could be a problem? 956 elmz.attachEvent("on" + type, fn); 957 } 958 else if(elmz.addEventListener) 959 elmz.addEventListener(type, fn, cancle_bubble); 960 961 AJS.listeners = AJS.$A(AJS.listeners); 962 AJS.listeners.push([elmz, type, fn]); 963 }); 964 }, 965 966 //Shortcut: AJS.REV 967 removeEventListener: function(elm, type, fn, /*optional*/cancle_bubble) { 968 if(!cancle_bubble) 969 cancle_bubble = false; 970 if(elm.removeEventListener) { 971 elm.removeEventListener(type, fn, cancle_bubble); 972 if(AJS.isOpera()) 973 elm.removeEventListener(type, fn, !cancle_bubble); 974 } 975 else if(elm.detachEvent) 976 elm.detachEvent("on" + type, fn); 977 }, 978 979 //Shortcut: AJS.$b 980 bind: function(fn, scope, /*optional*/ extra_args) { 981 fn._cscope = scope; 982 return AJS._getRealScope(fn, extra_args); 983 }, 984 985 bindMethods: function(self) { 986 for (var k in self) { 987 var func = self[k]; 988 if (typeof(func) == 'function') { 989 self[k] = AJS.$b(func, self); 990 } 991 } 992 }, 993 994 _listenOnce: function(elm, type, fn) { 995 var r_fn = function() { 996 AJS.removeEventListener(elm, type, r_fn); 997 fn(arguments); 998 } 999 return r_fn; 1000 }, 1001 1002 callLater: function(fn, interval) { 1003 var fn_no_send = function() { 1004 fn(); 1005 }; 1006 window.setTimeout(fn_no_send, interval); 1007 }, 1008 1009 preventDefault: function(e) { 1010 if(AJS.isIe()) 1011 window.event.returnValue = false; 1012 else 1013 e.preventDefault(); 1014 }, 1015 1016 1017 //// 1018 // Drag and drop 1019 //// 1020 dragAble: function(elm, /*optional*/ handler, args) { 1021 if(!args) 1022 args = {}; 1023 if(!AJS.isDefined(args['move_x'])) 1024 args['move_x'] = true; 1025 if(!AJS.isDefined(args['move_y'])) 1026 args['move_y'] = true; 1027 if(!AJS.isDefined(args['moveable'])) 1028 args['moveable'] = false; 1029 if(!AJS.isDefined(args['hide_on_move'])) 1030 args['hide_on_move'] = true; 1031 if(!AJS.isDefined(args['on_mouse_up'])) 1032 args['on_mouse_up'] = null; 1033 if(!AJS.isDefined(args['cursor'])) 1034 args['cursor'] = 'move'; 1035 if(!AJS.isDefined(args['max_move'])) 1036 args['max_move'] = {'top': null, 'left': null}; 1037 1038 elm = AJS.$(elm); 1039 1040 if(!handler) 1041 handler = elm; 1042 1043 handler = AJS.$(handler); 1044 var old_cursor = handler.style.cursor; 1045 handler.style.cursor = args['cursor']; 1046 elm.style.position = 'relative'; 1047 1048 AJS.addClass(handler, '_ajs_handler'); 1049 handler._args = args; 1050 handler._elm = elm; 1051 AJS.AEV(handler, 'mousedown', AJS._dragStart); 1052 }, 1053 1054 _dragStart: function(e) { 1055 var handler = AJS.getEventElm(e); 1056 if(!AJS.hasClass(handler, '_ajs_handler')) { 1057 handler = AJS.getParentBytc(handler, null, '_ajs_handler'); 1058 } 1059 if(handler) 1060 AJS._dragInit(e, handler._elm, handler._args); 1061 }, 1062 1063 dropZone: function(elm, args) { 1064 elm = AJS.$(elm); 1065 var item = {elm: elm}; 1066 AJS.update(item, args); 1067 AJS._drop_zones.push(item); 1068 }, 1069 1070 removeDragAble: function(elm) { 1071 AJS.REV(elm, 'mousedown', AJS._dragStart); 1072 elm.style.cursor = ''; 1073 }, 1074 1075 removeDropZone: function(elm) { 1076 var i = AJS.getIndex(elm, AJS._drop_zones, function(item) { 1077 if(item.elm == elm) return true; 1078 }); 1079 if(i != -1) { 1080 AJS._drop_zones.splice(i, 1); 1081 } 1082 }, 1083 1084 _dragInit: function(e, click_elm, args) { 1085 AJS.drag_obj = new Object(); 1086 AJS.drag_obj.args = args; 1087 1088 AJS.drag_obj.click_elm = click_elm; 1089 AJS.drag_obj.mouse_pos = AJS.getMousePos(e); 1090 AJS.drag_obj.click_elm_pos = AJS.absolutePosition(click_elm); 1091 1092 AJS.AEV(document, 'mousemove', AJS._dragMove, false, true); 1093 AJS.AEV(document, 'mouseup', AJS._dragStop, false, true); 1094 1095 if (AJS.isIe()) 1096 window.event.cancelBubble = true; 1097 AJS.preventDefault(e); 1098 }, 1099 1100 _initDragElm: function(elm) { 1101 if(AJS.drag_elm && AJS.drag_elm.style.display == 'none') 1102 AJS.removeElement(AJS.drag_elm); 1103 1104 if(!AJS.drag_elm) { 1105 AJS.drag_elm = AJS.DIV(); 1106 var d = AJS.drag_elm; 1107 AJS.insertBefore(d, AJS.getBody().firstChild); 1108 AJS.setHTML(d, elm.innerHTML); 1109 1110 d.className = elm.className; 1111 d.style.cssText = elm.style.cssText; 1112 1113 d.style.position = 'absolute'; 1114 d.style.zIndex = 10000; 1115 1116 var t = AJS.absolutePosition(elm); 1117 AJS.setTop(d, t.y); 1118 AJS.setLeft(d, t.x); 1119 1120 if(AJS.drag_obj.args.on_init) { 1121 AJS.drag_obj.args.on_init(elm); 1122 } 1123 } 1124 }, 1125 1126 _dragMove: function(e) { 1127 var drag_obj = AJS.drag_obj; 1128 var click_elm = drag_obj.click_elm; 1129 1130 AJS._initDragElm(click_elm); 1131 var drag_elm = AJS.drag_elm; 1132 1133 if(drag_obj.args['hide_on_move']) 1134 click_elm.style.visibility = 'hidden'; 1135 1136 var cur_pos = AJS.getMousePos(e); 1137 1138 var mouse_pos = drag_obj.mouse_pos; 1139 1140 var click_elm_pos = drag_obj.click_elm_pos; 1141 1142 var p_x, p_y; 1143 p_x = cur_pos.x - (mouse_pos.x - click_elm_pos.x); 1144 p_y = cur_pos.y - (mouse_pos.y - click_elm_pos.y); 1145 1146 AJS.map(AJS._drop_zones, function(d_z) { 1147 if(AJS.isOverlapping(d_z['elm'], drag_elm)) { 1148 if(d_z['elm'] != drag_elm) { 1149 var on_hover = d_z['on_hover']; 1150 if(on_hover) 1151 on_hover(d_z['elm'], click_elm, drag_elm); 1152 } 1153 } 1154 }); 1155 1156 if(drag_obj.args['on_drag']) 1157 drag_obj.args['on_drag'](click_elm, e); 1158 1159 var max_move_top = drag_obj.args['max_move']['top']; 1160 var max_move_left = drag_obj.args['max_move']['left']; 1161 if(drag_obj.args['move_x']) { 1162 if(max_move_left == null || max_move_left <= p) 1163 AJS.setLeft(elm, p_x); 1164 } 1165 1166 if(drag_obj.args['move_y']) { 1167 if(max_move_top == null || max_move_top <= p_y) 1168 AJS.setTop(elm, p_y); 1169 } 1170 if(AJS.isIe()) { 1171 window.event.cancelBubble = true; 1172 window.event.returnValue = false; 1173 } 1174 else 1175 e.preventDefault(); 1176 1177 //Moving scroll to the top, should move the scroll up 1178 var sc_top = AJS.getScrollTop(); 1179 var sc_bottom = sc_top + AJS.getWindowSize().h; 1180 var d_e_top = AJS.absolutePosition(drag_elm).y; 1181 var d_e_bottom = drag_elm.offsetTop + drag_elm.offsetHeight; 1182 1183 if(d_e_top <= sc_top + 20) { 1184 window.scrollBy(0, -15); 1185 } 1186 else if(d_e_bottom >= sc_bottom - 20) { 1187 window.scrollBy(0, 15); 1188 } 1189 }, 1190 1191 _dragStop: function(e) { 1192 var drag_obj = AJS.drag_obj; 1193 var drag_elm = AJS.drag_elm; 1194 var click_elm = drag_obj.click_elm; 1195 1196 AJS.REV(document, "mousemove", AJS._dragMove, true); 1197 AJS.REV(document, "mouseup", AJS._dragStop, true); 1198 1199 var dropped = false; 1200 AJS.map(AJS._drop_zones, function(d_z) { 1201 if(AJS.isOverlapping(d_z['elm'], click_elm)) { 1202 if(d_z['elm'] != click_elm) { 1203 var on_drop = d_z['on_drop']; 1204 if(on_drop) { 1205 dropped = true; 1206 on_drop(d_z['elm'], click_elm); 1207 } 1208 } 1209 } 1210 }); 1211 1212 if(drag_obj.args['moveable']) { 1213 var t = parseInt(click_elm.style.top) || 0; 1214 var l = parseInt(click_elm.style.left) || 0; 1215 var drag_elm_xy = AJS.absolutePosition(drag_elm); 1216 var click_elm_xy = AJS.absolutePosition(click_elm); 1217 AJS.setTop(click_elm, t + drag_elm_xy.y - click_elm_xy.y); 1218 AJS.setLeft(click_elm, l + drag_elm_xy.x - click_elm_xy.x); 1219 } 1220 1221 if(!dropped && drag_obj.args['on_mouse_up']) 1222 drag_obj.args['on_mouse_up'](click_elm, e); 1223 1224 if(drag_obj.args['hide_on_move']) 1225 drag_obj.click_elm.style.visibility = 'visible'; 1226 1227 if(drag_obj.args.on_end) { 1228 drag_obj.args.on_end(click_elm); 1229 } 1230 1231 AJS._dragObj = null; 1232 if(drag_elm) 1233 AJS.hideElement(drag_elm); 1234 AJS.drag_elm = null; 1235 }, 1236 1237 406 1238 //// 407 1239 // Misc. 408 1240 //// 409 /** 410 * Alert the objects key attrs 411 */ 412 keys: function(obj) { 413 var rval = []; 414 for (var prop in obj) { 415 rval.push(prop); 416 } 417 return rval; 418 }, 419 420 urlencode: function(str) { 421 return encodeURIComponent(str.toString()); 422 }, 423 424 /** 425 * @returns True if the object is defined, otherwise false 426 */ 427 isDefined: function(o) { 428 return (o != "undefined" && o != null) 429 }, 430 431 /** 432 * @returns True if an object is a array, false otherwise 433 */ 434 isArray: function(obj) { 435 try { return (typeof(obj.length) == "undefined") ? false : true; } 436 catch(e) 437 { return false; } 438 }, 439 440 isObject: function(obj) { 441 return (obj && typeof obj == 'object'); 442 }, 443 444 /** 445 * Export DOM elements to the global namespace 446 */ 447 exportDOMElements: function() { 448 UL = this.UL; 449 LI = this.LI; 450 TD = this.TD; 451 TR = this.TR; 452 TH = this.TH; 453 TBODY = this.TBODY; 454 TABLE = this.TABLE; 455 INPUT = this.INPUT; 456 SPAN = this.SPAN; 457 B = this.B; 458 A = this.A; 459 DIV = this.DIV; 460 IMG = this.IMG; 461 BUTTON = this.BUTTON; 462 H1 = this.H1; 463 H2 = this.H2; 464 H3 = this.H3; 465 BR = this.BR; 466 TEXTAREA = this.TEXTAREA; 467 FORM = this.FORM; 468 P = this.P; 469 SELECT = this.SELECT; 470 OPTION = this.OPTION; 471 TN = this.TN; 472 IFRAME = this.IFRAME; 473 SCRIPT = this.SCRIPT; 474 }, 475 476 /** 477 * Export AmiJS functions to the global namespace 478 */ 479 exportToGlobalScope: function() { 480 getElement = this.getElement; 481 getQueryArgument = this.getQueryArgument; 482 isIe = this.isIe; 483 $ = this.getElement; 484 getElements = this.getElements; 485 getBody = this.getBody; 486 getElementsByTagAndClassName = this.getElementsByTagAndClassName; 487 appendChildNodes = this.appendChildNodes; 488 ACN = appendChildNodes; 489 replaceChildNodes = this.replaceChildNodes; 490 RCN = replaceChildNodes; 491 insertAfter = this.insertAfter; 492 insertBefore = this.insertBefore; 493 showElement = this.showElement; 494 hideElement = this.hideElement; 495 isElementHidden = this.isElementHidden; 496 swapDOM = this.swapDOM; 497 removeElement = this.removeElement; 498 isDict = this.isDict; 499 createDOM = this.createDOM; 500 this.exportDOMElements(); 501 getXMLHttpRequest = this.getXMLHttpRequest; 502 doSimpleXMLHttpRequest = this.doSimpleXMLHttpRequest; 503 getRequest = this.getRequest; 504 sendXMLHttpRequest = this.sendXMLHttpRequest; 505 reprString = this.reprString; 506 serializeJSON = this.serializeJSON; 507 loadJSONDoc = this.loadJSONDoc; 508 keys = this.keys; 509 isDefined = this.isDefined; 510 isArray = this.isArray; 511 } 512 } 513 514 1241 keys: function(obj) { 1242 var rval = []; 1243 for (var prop in obj) { 1244 rval.push(prop); 1245 } 1246 return rval; 1247 }, 1248 1249 values: function(obj) { 1250 var rval = []; 1251 for (var prop in obj) { 1252 rval.push(obj[prop]); 1253 } 1254 return rval; 1255 }, 1256 1257 urlencode: function(str) { 1258 return encodeURIComponent(str.toString()); 1259 }, 1260 1261 isDefined: function(o) { 1262 return (o != "undefined" && o != null) 1263 }, 1264 1265 isArray: function(obj) { 1266 return obj instanceof Array; 1267 }, 1268 1269 isString: function(obj) { 1270 return (typeof obj == 'string'); 1271 }, 1272 1273 isNumber: function(obj) { 1274 return (typeof obj == 'number'); 1275 }, 1276 1277 isObject: function(obj) { 1278 return (typeof obj == 'object'); 1279 }, 1280 1281 isFunction: function(obj) { 1282 return (typeof obj == 'function'); 1283 }, 1284 1285 isDict: function(o) { 1286 var str_repr = String(o); 1287 return str_repr.indexOf(" Object") != -1; 1288 }, 1289 1290 exportToGlobalScope: function() { 1291 for(e in AJS) 1292 window[e] = AJS[e]; 1293 }, 1294 1295 log: function(o) { 1296 if(window.console) 1297 console.log(o); 1298 else { 1299 var div = AJS.$('ajs_logger'); 1300 if(!div) { 1301 div = AJS.DIV({id: 'ajs_logger', 'style': 'color: green; position: absolute; left: 0'}); 1302 div.style.top = AJS.getScrollTop() + 'px'; 1303 AJS.ACN(AJS.getBody(), div); 1304 } 1305 AJS.setHTML(div, ''+o); 1306 } 1307 } 1308 1309 } 1310 1311 AJS.Class = function(members) { 1312 var fn = function() { 1313 if(arguments[0] != 'no_init') { 1314 return this.init.apply(this, arguments); 1315 } 1316 } 1317 fn.prototype = members; 1318 AJS.update(fn, AJS.Class.prototype); 1319 return fn; 1320 } 1321 AJS.Class.prototype = { 1322 extend: function(members) { 1323 var parent = new this('no_init'); 1324 for(k in members) { 1325 var prev = parent[k]; 1326 var cur = members[k]; 1327 if (prev && prev != cur && typeof cur == 'function') { 1328 cur = this._parentize(cur, prev); 1329 } 1330 parent[k] = cur; 1331 } 1332 return new AJS.Class(parent); 1333 }, 1334 1335 implement: function(members) { 1336 AJS.update(this.prototype, members); 1337 }, 1338 1339 _parentize: function(cur, prev) { 1340 return function(){ 1341 this.parent = prev; 1342 return cur.apply(this, arguments); 1343 } 1344 } 1345 }; 1346 1347 //Shortcuts 1348 AJS.$ = AJS.getElement; 1349 AJS.$$ = AJS.getElements; 1350 AJS.$f = AJS.getFormElement; 1351 AJS.$b = AJS.bind; 1352 AJS.$p = AJS.partial; 1353 AJS.$FA = AJS.forceArray; 1354 AJS.$A = AJS.createArray; 1355 AJS.DI = AJS.documentInsert; 1356 AJS.ACN = AJS.appendChildNodes; 1357 AJS.RCN = AJS.replaceChildNodes; 1358 AJS.AEV = AJS.addEventListener; 1359 AJS.REV = AJS.removeEventListener; 1360 AJS.$bytc = AJS.getElementsByTagAndClassName; 515 1361 516 1362 AJSDeferred = function(req) { 517 this.callbacks = []; 518 this.req = req; 519 520 this.callback = function (res) { 521 while (this.callbacks.length > 0) { 522 var fn = this.callbacks.pop(); 523 res = fn(res); 524 } 525 }; 526 527 this.errback = function(e){ 528 alert("Error encountered:\n" + e); 529 }; 530 531 this.addErrback = function(fn) { 532 this.errback = fn; 533 }; 534 535 this.addCallback = function(fn) { 536 this.callbacks.unshift(fn); 537 }; 538 539 this.addCallbacks = function(fn1, fn2) { 540 this.addCallback(fn1); 541 this.addErrback(fn2); 542 }; 543 544 this.sendReq = function(data) { 545 if(AJS.isObject(data)) { 546 var post_data = []; 547 for(k in data) { 548 post_data.push(k + "=" + AJS.urlencode(data[k])); 549 } 550 post_data = post_data.join("&"); 551 this.req.send(post_data); 552 } 553 else if(AJS.isDefined(data)) 554 this.req.send(data); 1363 this.callbacks = []; 1364 this.errbacks = []; 1365 this.req = req; 1366 } 1367 AJSDeferred.prototype = { 1368 excCallbackSeq: function(req, list) { 1369 var data = req.responseText; 1370 while (list.length > 0) { 1371 var fn = list.pop(); 1372 var new_data = fn(data, req); 1373 if(new_data) 1374 data = new_data; 1375 } 1376 }, 1377 1378 callback: function () { 1379 this.excCallbackSeq(this.req, this.callbacks); 1380 }, 1381 1382 errback: function() { 1383 if(this.errbacks.length == 0) 1384 alert("Error encountered:\n" + this.req.responseText); 1385 1386 this.excCallbackSeq(this.req, this.errbacks); 1387 }, 1388 1389 addErrback: function(fn) { 1390 this.errbacks.unshift(fn); 1391 }, 1392 1393 addCallback: function(fn) { 1394 this.callbacks.unshift(fn); 1395 }, 1396 1397 abort: function() { 1398 this.req.abort(); 1399 }, 1400 1401 addCallbacks: function(fn1, fn2) { 1402 this.addCallback(fn1); 1403 this.addErrback(fn2); 1404 }, 1405 1406 sendReq: function(data) { 1407 if(AJS.isObject(data)) { 1408 this.req.send(AJS.queryArguments(data)); 1409 } 1410 else if(AJS.isDefined(data)) 1411 this.req.send(data); 1412 else { 1413 this.req.send(""); 1414 } 1415 } 1416 }; 1417 1418 //Prevent memory-leaks 1419 AJS.addEventListener(window, 'unload', AJS._unloadListeners); 1420 AJS._createDomShortcuts() 1421 } 1422 1423 script_loaded = true; 1424 1425 /**** 1426 Last Modified: 13/05/07 00:25:28 1427 1428 GoogieSpell 1429 Google spell checker for your own web-apps :) 1430 Copyright Amir Salihefendic 2006 1431 LICENSE 1432 GPL (see gpl.txt for more information) 1433 This basically means that you can't use this script with/in proprietary software! 1434 There is another license that permits you to use this script with proprietary software. Check out:... for more info. 1435 AUTHOR 1436 4mir Salihefendic (http://amix.dk) - amix@amix.dk 1437 VERSION 1438 4.0 1439 ****/ 1440 var GOOGIE_CUR_LANG = null; 1441 var GOOGIE_DEFAULT_LANG = "en"; 1442 1443 function GoogieSpell(img_dir, server_url) { 1444 var cookie_value; 1445 var lang; 1446 cookie_value = getCookie('language'); 1447 1448 if(cookie_value != null) 1449 GOOGIE_CUR_LANG = cookie_value; 1450 else 1451 GOOGIE_CUR_LANG = GOOGIE_DEFAULT_LANG; 1452 1453 this.img_dir = img_dir; 1454 this.server_url = server_url; 1455 1456 this.org_lang_to_word = {"da": "Dansk", "de": "Deutsch", "en": "English", 1457 "es": "Español", "fr": "Français", "it": "Italiano", 1458 "nl": "Nederlands", "pl": "Polski", "pt": "Português", 1459 "fi": "Suomi", "sv": "Svenska"}; 1460 this.lang_to_word = this.org_lang_to_word; 1461 this.langlist_codes = AJS.keys(this.lang_to_word); 1462 1463 this.show_change_lang_pic = true; 1464 this.change_lang_pic_placement = "left"; 1465 1466 this.report_state_change = true; 1467 1468 this.ta_scroll_top = 0; 1469 this.el_scroll_top = 0; 1470 1471 this.lang_chck_spell = "Check spelling"; 1472 this.lang_revert = "Revert to"; 1473 this.lang_close = "Close"; 1474 this.lang_rsm_edt = "Resume editing"; 1475 this.lang_no_error_found = "No spelling errors found"; 1476 this.lang_no_suggestions = "No suggestions"; 1477 1478 this.show_spell_img = false; // modified by roundcube 1479 this.decoration = true; 1480 this.use_close_btn = true; 1481 this.edit_layer_dbl_click = true; 1482 this.report_ta_not_found = true; 1483 1484 //Extensions 1485 this.custom_ajax_error = null; 1486 this.custom_no_spelling_error = null; 1487 this.custom_menu_builder = []; //Should take an eval function and a build menu function 1488 this.custom_item_evaulator = null; //Should take an eval function and a build menu function 1489 this.extra_menu_items = []; 1490 this.custom_spellcheck_starter = null; 1491 this.main_controller = true; 1492 1493 //Observers 1494 this.lang_state_observer = null; 1495 this.spelling_state_observer = null; 1496 this.show_menu_observer = null; 1497 this.all_errors_fixed_observer = null; 1498 1499 //Focus links - used to give the text box focus 1500 this.use_focus = false; 1501 this.focus_link_t = null; 1502 this.focus_link_b = null; 1503 1504 //Counters 1505 this.cnt_errors = 0; 1506 this.cnt_errors_fixed = 0; 1507 1508 //Set document on click to hide the language and error menu 1509 var fn = function(e) { 1510 var elm = AJS.getEventElm(e); 1511 if(elm.googie_action_btn != "1" && this.isLangWindowShown()) 1512 this.hideLangWindow(); 1513 if(elm.googie_action_btn != "1" && this.isErrorWindowShown()) 1514 this.hideErrorWindow(); 1515 }; 1516 AJS.AEV(document, "click", AJS.$b(fn, this)); 1517 } 1518 1519 GoogieSpell.prototype.decorateTextarea = function(id) { 1520 if(typeof(id) == "string") 1521 this.text_area = AJS.$(id); 1522 else 1523 this.text_area = id; 1524 1525 var r_width, r_height; 1526 1527 if(this.text_area != null) { 1528 if(!AJS.isDefined(this.spell_container) && this.decoration) { 1529 var table = AJS.TABLE(); 1530 var tbody = AJS.TBODY(); 1531 var tr = AJS.TR(); 1532 if(AJS.isDefined(this.force_width)) 1533 r_width = this.force_width; 1534 else 1535 r_width = this.text_area.offsetWidth + "px"; 1536 1537 if(AJS.isDefined(this.force_height)) 1538 r_height = this.force_height; 1539 else 1540 r_height = ""; 1541 1542 var spell_container = AJS.TD(); 1543 this.spell_container = spell_container; 1544 1545 tr.appendChild(spell_container); 1546 1547 tbody.appendChild(tr); 1548 table.appendChild(tbody); 1549 1550 AJS.insertBefore(table, this.text_area); 1551 1552 //Set width 1553 AJS.setHeight(table, spell_container, r_height); 1554 AJS.setWidth(table, spell_container, '100%'); // modified by roundcube (old: r_width) 1555 1556 spell_container.style.textAlign = "right"; 1557 } 1558 1559 this.checkSpellingState(); 1560 } 1561 else 1562 if(this.report_ta_not_found) 1563 alert("Text area not found"); 1564 } 1565 1566 ////// 1567 // API Functions (the ones that you can call) 1568 ///// 1569 GoogieSpell.prototype.setSpellContainer = function(elm) { 1570 this.spell_container = AJS.$(elm); 1571 } 1572 1573 GoogieSpell.prototype.setLanguages = function(lang_dict) { 1574 this.lang_to_word = lang_dict; 1575 this.langlist_codes = AJS.keys(lang_dict); 1576 } 1577 1578 GoogieSpell.prototype.setForceWidthHeight = function(width, height) { 1579 /*** 1580 Set to null if you want to use one of them 1581 ***/ 1582 this.force_width = width; 1583 this.force_height = height; 1584 } 1585 1586 GoogieSpell.prototype.setDecoration = function(bool) { 1587 this.decoration = bool; 1588 } 1589 1590 GoogieSpell.prototype.dontUseCloseButtons = function() { 1591 this.use_close_btn = false; 1592 } 1593 1594 GoogieSpell.prototype.appendNewMenuItem = function(name, call_back_fn, checker) { 1595 this.extra_menu_items.push([name, call_back_fn, checker]); 1596 } 1597 1598 GoogieSpell.prototype.appendCustomMenuBuilder = function(eval, builder) { 1599 this.custom_menu_builder.push([eval, builder]); 1600 } 1601 1602 GoogieSpell.prototype.setFocus = function() { 1603 try { 1604 this.focus_link_b.focus(); 1605 this.focus_link_t.focus(); 1606 return true; 1607 } 1608 catch(e) { 1609 return false; 1610 } 1611 } 1612 1613 GoogieSpell.prototype.getValue = function(ta) { 1614 return ta.value; 1615 } 1616 1617 GoogieSpell.prototype.setValue = function(ta, value) { 1618 ta.value = value; 1619 } 1620 1621 1622 ////// 1623 // Set functions (internal) 1624 ///// 1625 GoogieSpell.prototype.setStateChanged = function(current_state) { 1626 this.state = current_state; 1627 if(this.spelling_state_observer != null && this.report_state_change) 1628 this.spelling_state_observer(current_state, this); 1629 } 1630 1631 GoogieSpell.prototype.setReportStateChange = function(bool) { 1632 this.report_state_change = bool; 1633 } 1634 1635 1636 ////// 1637 // Request functions 1638 ///// 1639 GoogieSpell.prototype.getGoogleUrl = function() { 1640 return this.server_url + GOOGIE_CUR_LANG; 1641 } 1642 1643 GoogieSpell.escapeSepcial = function(val) { 1644 return val.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); 1645 } 1646 1647 GoogieSpell.createXMLReq = function (text) { 1648 return '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' + text + '</text></spellrequest>'; 1649 } 1650 1651 GoogieSpell.prototype.spellCheck = function(ignore) { 1652 var me = this; 1653 1654 this.cnt_errors_fixed = 0; 1655 this.cnt_errors = 0; 1656 this.setStateChanged("checking_spell"); 1657 1658 if(this.main_controller) 1659 this.appendIndicator(this.spell_span); 1660 1661 this.error_links = []; 1662 this.ta_scroll_top = this.text_area.scrollTop; 1663 1664 try { this.hideLangWindow(); } 1665 catch(e) {} 1666 1667 this.ignore = ignore; 1668 1669 if(this.getValue(this.text_area) == '' || ignore) { 1670 if(!me.custom_no_spelling_error) 1671 me.flashNoSpellingErrorState(); 1672 else 1673 me.custom_no_spelling_error(me); 1674 me.removeIndicator(); 1675 return ; 1676 } 1677 1678 this.createEditLayer(this.text_area.offsetWidth, this.text_area.offsetHeight); 1679 1680 this.createErrorWindow(); 1681 AJS.getBody().appendChild(this.error_window); 1682 1683 try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } 1684 catch (e) { } 1685 1686 if(this.main_controller) 1687 this.spell_span.onclick = null; 1688 1689 this.orginal_text = this.getValue(this.text_area); 1690 1691 //Create request 1692 var d = AJS.getRequest(this.getGoogleUrl()); 1693 var reqdone = function(res_txt) { 1694 var r_text = res_txt; 1695 me.results = me.parseResult(r_text); 1696 1697 if(r_text.match(/<c.*>/) != null) { 1698 //Before parsing be sure that errors were found 1699 me.showErrorsInIframe(); 1700 me.resumeEditingState(); 1701 } 1702 else { 1703 if(!me.custom_no_spelling_error) 1704 me.flashNoSpellingErrorState(); 1705 else 1706 me.custom_no_spelling_error(me); 1707 } 1708 me.removeIndicator(); 1709 }; 1710 1711 d.addCallback(reqdone); 1712 reqdone = null; 1713 1714 var reqfailed = function(res_txt, req) { 1715 if(me.custom_ajax_error) 1716 me.custom_ajax_error(req); 1717 else 1718 alert("An error was encountered on the server. Please try again later."); 1719 1720 if(me.main_controller) { 1721 AJS.removeElement(me.spell_span); 1722 me.removeIndicator(); 1723 } 1724 me.checkSpellingState(); 1725 }; 1726 d.addErrback(reqfailed); 1727 reqfailed = null; 1728 1729 var req_text = GoogieSpell.escapeSepcial(this.orginal_text); 1730 d.sendReq(GoogieSpell.createXMLReq(req_text)); 1731 } 1732 1733 1734 ////// 1735 // Spell checking functions 1736 ///// 1737 GoogieSpell.prototype.parseResult = function(r_text) { 1738 /*** 1739 Retunrs an array 1740 result[item] -> ['attrs'], ['suggestions'] 1741 ***/ 1742 var re_split_attr_c = /\w+="(\d+|true)"/g; 1743 var re_split_text = /\t/g; 1744 1745 var matched_c = r_text.match(/<c[^>]*>[^<]*<\/c>/g); 1746 var results = new Array(); 1747 1748 if(matched_c == null) 1749 return results; 1750 1751 for(var i=0; i < matched_c.length; i++) { 1752 var item = new Array(); 1753 this.errorFound(); 1754 1755 //Get attributes 1756 item['attrs'] = new Array(); 1757 var split_c = matched_c[i].match(re_split_attr_c); 1758 for(var j=0; j < split_c.length; j++) { 1759 var c_attr = split_c[j].split(/=/); 1760 var val = c_attr[1].replace(/"/g, ''); 1761 if(val != "true") 1762 item['attrs'][c_attr[0]] = parseInt(val); 1763 else { 1764 item['attrs'][c_attr[0]] = val; 1765 } 1766 } 1767 1768 //Get suggestions 1769 item['suggestions'] = new Array(); 1770 var only_text = matched_c[i].replace(/<[^>]*>/g, ""); 1771 var split_t = only_text.split(re_split_text); 1772 for(var k=0; k < split_t.length; k++) { 1773 if(split_t[k] != "") 1774 item['suggestions'].push(split_t[k]); 1775 } 1776 results.push(item); 1777 } 1778 return results; 1779 } 1780 1781 ////// 1782 // Counters 1783 ///// 1784 GoogieSpell.prototype.errorFixed = function() { 1785 this.cnt_errors_fixed++; 1786 if(this.all_errors_fixed_observer) 1787 if(this.cnt_errors_fixed == this.cnt_errors) { 1788 this.hideErrorWindow(); 1789 this.all_errors_fixed_observer(); 1790 } 1791 } 1792 GoogieSpell.prototype.errorFound = function() { this.cnt_errors++; } 1793 1794 ////// 1795 // Error menu functions 1796 ///// 1797 GoogieSpell.prototype.createErrorWindow = function() { 1798 this.error_window = AJS.DIV(); 1799 this.error_window.className = "googie_window"; 1800 this.error_window.googie_action_btn = "1"; 1801 } 1802 1803 GoogieSpell.prototype.isErrorWindowShown = function() { 1804 return this.error_window != null && this.error_window.style.visibility == "visible"; 1805 } 1806 1807 GoogieSpell.prototype.hideErrorWindow = function() { 1808 try { 1809 this.error_window.style.visibility = "hidden"; 1810 if(this.error_window_iframe) 1811 this.error_window_iframe.style.visibility = "hidden"; 1812 } 1813 catch(e) {} 1814 } 1815 1816 GoogieSpell.prototype.updateOrginalText = function(offset, old_value, new_value, id) { 1817 var part_1 = this.orginal_text.substring(0, offset); 1818 var part_2 = this.orginal_text.substring(offset+old_value.length); 1819 this.orginal_text = part_1 + new_value + part_2; 1820 this.setValue(this.text_area, this.orginal_text); 1821 var add_2_offset = new_value.length - old_value.length; 1822 for(var j=0; j < this.results.length; j++) { 1823 //Don't edit the offset of the current item 1824 if(j != id && j > id){ 1825 this.results[j]['attrs']['o'] += add_2_offset; 1826 } 1827 } 1828 } 1829 1830 GoogieSpell.prototype.saveOldValue = function(elm, old_value) { 1831 elm.is_changed = true; 1832 elm.old_value = old_value; 1833 } 1834 1835 GoogieSpell.prototype.createListSeparator = function() { 1836 var e_col = AJS.TD(" "); 1837 e_col.googie_action_btn = "1"; 1838 e_col.style.cursor = "default"; 1839 e_col.style.fontSize = "3px"; 1840 e_col.style.borderTop = "1px solid #ccc"; 1841 e_col.style.paddingTop = "3px"; 1842 1843 return AJS.TR(e_col); 1844 } 1845 1846 GoogieSpell.prototype.correctError = function(id, elm, l_elm, /*optional*/ rm_pre_space) { 1847 var old_value = elm.innerHTML; 1848 var new_value = l_elm.innerHTML; 1849 var offset = this.results[id]['attrs']['o']; 1850 1851 if(rm_pre_space) { 1852 var pre_length = elm.previousSibling.innerHTML; 1853 elm.previousSibling.innerHTML = pre_length.slice(0, pre_length.length-1); 1854 old_value = " " + old_value; 1855 offset--; 1856 } 1857 1858 this.hideErrorWindow(); 1859 1860 this.updateOrginalText(offset, old_value, new_value, id); 1861 1862 elm.innerHTML = new_value; 1863 1864 elm.style.color = "green"; 1865 elm.is_corrected = true; 1866 1867 this.results[id]['attrs']['l'] = new_value.length; 1868 1869 if(!AJS.isDefined(elm.old_value)) 1870 this.saveOldValue(elm, old_value); 1871 1872 this.errorFixed(); 1873 } 1874 1875 GoogieSpell.prototype.showErrorWindow = function(elm, id) { 1876 if(this.show_menu_observer) 1877 this.show_menu_observer(this); 1878 var me = this; 1879 1880 var abs_pos = AJS.absolutePosition(elm); 1881 abs_pos.y -= this.edit_layer.scrollTop; 1882 this.error_window.style.visibility = "visible"; 1883 1884 AJS.setTop(this.error_window, (abs_pos.y+20)); 1885 AJS.setLeft(this.error_window, (abs_pos.x)); 1886 1887 this.error_window.innerHTML = ""; 1888 1889 var table = AJS.TABLE({'class': 'googie_list'}); 1890 table.googie_action_btn = "1"; 1891 var list = AJS.TBODY(); 1892 1893 //Check if we should use custom menu builder, if not we use the default 1894 var changed = false; 1895 if(this.custom_menu_builder != []) { 1896 for(var k=0; k<this.custom_menu_builder.length; k++) { 1897 var eb = this.custom_menu_builder[k]; 1898 if(eb[0]((this.results[id]))){ 1899 changed = eb[1](this, list, elm); 1900 break; 1901 } 1902 } 1903 } 1904 if(!changed) { 1905 //Build up the result list 1906 var suggestions = this.results[id]['suggestions']; 1907 var offset = this.results[id]['attrs']['o']; 1908 var len = this.results[id]['attrs']['l']; 1909 1910 if(suggestions.length == 0) { 1911 var row = AJS.TR(); 1912 var item = AJS.TD({'style': 'cursor: default;'}); 1913 var dummy = AJS.SPAN(); 1914 dummy.innerHTML = this.lang_no_suggestions; 1915 AJS.ACN(item, AJS.TN(dummy.innerHTML)); 1916 item.googie_action_btn = "1"; 1917 row.appendChild(item); 1918 list.appendChild(row); 1919 } 1920 1921 for(i=0; i < suggestions.length; i++) { 1922 var row = AJS.TR(); 1923 var item = AJS.TD(); 1924 var dummy = AJS.SPAN(); 1925 dummy.innerHTML = suggestions[i]; 1926 item.appendChild(AJS.TN(dummy.innerHTML)); 1927 1928 var fn = function(e) { 1929 var l_elm = AJS.getEventElm(e); 1930 this.correctError(id, elm, l_elm); 1931 }; 1932 1933 AJS.AEV(item, "click", AJS.$b(fn, this)); 1934 1935 item.onmouseover = GoogieSpell.item_onmouseover; 1936 item.onmouseout = GoogieSpell.item_onmouseout; 1937 row.appendChild(item); 1938 list.appendChild(row); 1939 } 1940 1941 //The element is changed, append the revert 1942 if(elm.is_changed && elm.innerHTML != elm.old_value) { 1943 var old_value = elm.old_value; 1944 var revert_row = AJS.TR(); 1945 var revert = AJS.TD(); 1946 1947 revert.onmouseover = GoogieSpell.item_onmouseover; 1948 revert.onmouseout = GoogieSpell.item_onmouseout; 1949 var rev_span = AJS.SPAN({'class': 'googie_list_revert'}); 1950 rev_span.innerHTML = this.lang_revert + " " + old_value; 1951 revert.appendChild(rev_span); 1952 1953 var fn = function(e) { 1954 this.updateOrginalText(offset, elm.innerHTML, old_value, id); 1955 elm.is_corrected = true; 1956 elm.style.color = "#b91414"; 1957 elm.innerHTML = old_value; 1958 this.hideErrorWindow(); 1959 }; 1960 AJS.AEV(revert, "click", AJS.$b(fn, this)); 1961 1962 revert_row.appendChild(revert); 1963 list.appendChild(revert_row); 1964 } 1965 1966 //Append the edit box 1967 var edit_row = AJS.TR(); 1968 var edit = AJS.TD({'style': 'cursor: default'}); 1969 1970 var edit_input = AJS.INPUT({'style': 'width: 120px; margin:0; padding:0', 'value': elm.innerHTML}); 1971 edit_input.googie_action_btn = "1"; 1972 1973 var onsub = function () { 1974 if(edit_input.value != "") { 1975 if(!AJS.isDefined(elm.old_value)) 1976 this.saveOldValue(elm, elm.innerHTML); 1977 1978 this.updateOrginalText(offset, elm.innerHTML, edit_input.value, id); 1979 elm.style.color = "green" 1980 elm.is_corrected = true; 1981 elm.innerHTML = edit_input.value; 1982 1983 this.hideErrorWindow(); 1984 } 1985 return false; 1986 }; 1987 onsub = AJS.$b(onsub, this); 1988 1989 var ok_pic = AJS.IMG({'src': this.img_dir + "ok.gif", 'style': 'width: 32px; height: 16px; margin-left: 2px; margin-right: 2px; cursor: pointer;'}); 1990 var edit_form = AJS.FORM({'style': 'margin: 0; padding: 0; cursor: default;'}, edit_input, ok_pic); 1991 1992 edit_form.googie_action_btn = "1"; 1993 edit.googie_action_btn = "1"; 1994 1995 AJS.AEV(edit_form, "submit", onsub); 1996 AJS.AEV(ok_pic, "click", onsub); 1997 1998 edit.appendChild(edit_form); 1999 edit_row.appendChild(edit); 2000 list.appendChild(edit_row); 2001 2002 //Append extra menu items 2003 if(this.extra_menu_items.length > 0) 2004 AJS.ACN(list, this.createListSeparator()); 2005 2006 var loop = function(i) { 2007 if(i < me.extra_menu_items.length) { 2008 var e_elm = me.extra_menu_items[i]; 2009 2010 if(!e_elm[2] || e_elm[2](elm, me)) { 2011 var e_row = AJS.TR(); 2012 var e_col = AJS.TD(e_elm[0]); 2013 2014 e_col.onmouseover = GoogieSpell.item_onmouseover; 2015 e_col.onmouseout = GoogieSpell.item_onmouseout; 2016 2017 var fn = function() { 2018 return e_elm[1](elm, me); 2019 }; 2020 AJS.AEV(e_col, "click", fn); 2021 2022 AJS.ACN(e_row, e_col); 2023 AJS.ACN(list, e_row); 2024 2025 } 2026 loop(i+1); 2027 } 2028 } 2029 loop(0); 2030 loop = null; 2031 2032 //Close button 2033 if(this.use_close_btn) { 2034 AJS.ACN(list, this.createCloseButton(this.hideErrorWindow)); 2035 } 2036 } 2037 2038 table.appendChild(list); 2039 this.error_window.appendChild(table); 2040 2041 //Dummy for IE - dropdown bug fix 2042 if(AJS.isIe() && !this.error_window_iframe) { 2043 var iframe = AJS.IFRAME({'style': 'position: absolute; z-index: 0;'}); 2044 AJS.ACN(AJS.getBody(), iframe); 2045 this.error_window_iframe = iframe; 2046 } 2047 if(AJS.isIe()) { 2048 var iframe = this.error_window_iframe; 2049 AJS.setTop(iframe, this.error_window.offsetTop); 2050 AJS.setLeft(iframe, this.error_window.offsetLeft); 2051 2052 AJS.setWidth(iframe, this.error_window.offsetWidth); 2053 AJS.setHeight(iframe, this.error_window.offsetHeight); 2054 2055 iframe.style.visibility = "visible"; 2056 } 2057 2058 //Set focus on the last element 2059 var link = this.createFocusLink('link'); 2060 list.appendChild(AJS.TR(AJS.TD({'style': 'text-align: right; font-size: 1px; height: 1px; margin: 0; padding: 0;'}, link))); 2061 link.focus(); 2062 } 2063 2064 2065 ////// 2066 // Edit layer (the layer where the suggestions are stored) 2067 ////// 2068 GoogieSpell.prototype.createEditLayer = function(width, height) { 2069 this.edit_layer = AJS.DIV({'class': 'googie_edit_layer'}); 2070 2071 //Set the style so it looks like edit areas 2072 this.edit_layer.className = this.text_area.className; 2073 this.edit_layer.style.border = "1px solid #999"; 2074 this.edit_layer.style.backgroundColor = "#F1EDFE"; // modified by roundcube 2075 this.edit_layer.style.padding = "3px"; 2076 this.edit_layer.style.margin = "0px"; 2077 2078 AJS.setWidth(this.edit_layer, (width-8)); 2079 2080 if(AJS.nodeName(this.text_area) != "input" || this.getValue(this.text_area) == "") { 2081 this.edit_layer.style.overflow = "auto"; 2082 AJS.setHeight(this.edit_layer, (height-6)); 2083 } 555 2084 else { 556 this.req.send(""); 557 } 558 }; 559 }; 560 AJSDeferred.prototype = new AJSDeferred(); 561 562 563 564 565 566 567 /**** 568 Last Modified: 28/04/06 15:26:06 569 570 GoogieSpell 571 Google spell checker for your own web-apps :) 572 Copyright Amir Salihefendic 2006 573 LICENSE 574 GPL (see gpl.txt for more information) 575 This basically means that you can't use this script with/in proprietary software! 576 There is another license that permits you to use this script with proprietary software. Check out:... for more info. 577 AUTHOR 578 4mir Salihefendic (http://amix.dk) - amix@amix.dk 579 VERSION 580 3.22 581 ****/ 582 var GOOGIE_CUR_LANG = "en"; 583 584 function GoogieSpell(img_dir, server_url) { 585 var cookie_value; 586 var lang; 587 cookie_value = getCookie('language'); 588 589 if(cookie_value != null) 590 GOOGIE_CUR_LANG = cookie_value; 591 592 this.img_dir = img_dir; 593 this.server_url = server_url; 594 595 this.lang_to_word = {"da": "Dansk", "de": "Deutsch", "en": "English", 596 "es": "Español", "fr": "Français", "it": "Italiano", 597 "nl": "Nederlands", "pl": "Polski", "pt": "Português", 598 "fi": "Suomi", "sv": "Svenska"}; 599 this.langlist_codes = AJS.keys(this.lang_to_word); 600 601 this.show_change_lang_pic = true; 602 603 this.lang_state_observer = null; 604 605 this.spelling_state_observer = null; 606 607 this.request = null; 608 this.error_window = null; 609 this.language_window = null; 610 this.edit_layer = null; 611 this.orginal_text = null; 612 this.results = null; 613 this.text_area = null; 614 this.gselm = null; 615 this.ta_scroll_top = 0; 616 this.el_scroll_top = 0; 617 618 this.lang_chck_spell = "Check spelling"; 619 this.lang_rsm_edt = "Resume editing"; 620 this.lang_close = "Close"; 621 this.lang_no_error_found = "No spelling errors found"; 622 this.lang_revert = "Revert to"; 623 this.show_spell_img = false; // modified by roundcube 624 } 625 626 GoogieSpell.prototype.setStateChanged = function(current_state) { 627 if(this.spelling_state_observer != null) 628 this.spelling_state_observer(current_state); 629 } 630 2085 this.edit_layer.style.overflow = "hidden"; 2086 } 2087 2088 if(this.edit_layer_dbl_click) { 2089 var me = this; 2090 var fn = function(e) { 2091 if(AJS.getEventElm(e).className != "googie_link" && !me.isErrorWindowShown()) { 2092 me.resumeEditing(); 2093 var fn1 = function() { 2094 me.text_area.focus(); 2095 fn1 = null; 2096 }; 2097 AJS.callLater(fn1, 10); 2098 } 2099 return false; 2100 }; 2101 this.edit_layer.ondblclick = fn; 2102 fn = null; 2103 } 2104 } 2105 2106 GoogieSpell.prototype.resumeEditing = function() { 2107 this.setStateChanged("spell_check"); 2108 this.switch_lan_pic.style.display = "inline"; 2109 2110 if(this.edit_layer) 2111 this.el_scroll_top = this.edit_layer.scrollTop; 2112 2113 this.hideErrorWindow(); 2114 2115 if(this.main_controller) 2116 this.spell_span.className = "googie_no_style"; 2117 2118 if(!this.ignore) { 2119 //Remove the EDIT_LAYER 2120 try { 2121 this.edit_layer.parentNode.removeChild(this.edit_layer); 2122 if(this.use_focus) { 2123 AJS.removeElement(this.focus_link_t); 2124 AJS.removeElement(this.focus_link_b); 2125 } 2126 } 2127 catch(e) { 2128 } 2129 2130 AJS.showElement(this.text_area); 2131 2132 if(this.el_scroll_top != undefined) 2133 this.text_area.scrollTop = this.el_scroll_top; 2134 } 2135 2136 this.checkSpellingState(false); 2137 } 2138 2139 GoogieSpell.prototype.createErrorLink = function(text, id) { 2140 var elm = AJS.SPAN({'class': 'googie_link'}); 2141 var me = this; 2142 var d = function (e) { 2143 me.showErrorWindow(elm, id); 2144 d = null; 2145 return false; 2146 }; 2147 AJS.AEV(elm, "click", d); 2148 2149 elm.googie_action_btn = "1"; 2150 elm.g_id = id; 2151 elm.is_corrected = false; 2152 elm.oncontextmenu = d; 2153 elm.innerHTML = text; 2154 return elm; 2155 } 2156 2157 GoogieSpell.createPart = function(txt_part) { 2158 if(txt_part == " ") 2159 return AJS.TN(" "); 2160 var result = AJS.SPAN(); 2161 2162 var is_first = true; 2163 var is_safari = (navigator.userAgent.toLowerCase().indexOf("safari") != -1); 2164 2165 var part = AJS.SPAN(); 2166 txt_part = GoogieSpell.escapeSepcial(txt_part); 2167 txt_part = txt_part.replace(/\n/g, "<br>"); 2168 txt_part = txt_part.replace(/ /g, " "); 2169 txt_part = txt_part.replace(/^ /g, " "); 2170 txt_part = txt_part.replace(/ $/g, " "); 2171 2172 part.innerHTML = txt_part; 2173 2174 return part; 2175 } 2176 2177 GoogieSpell.prototype.showErrorsInIframe = function() { 2178 var output = AJS.DIV(); 2179 output.style.textAlign = "left"; 2180 var pointer = 0; 2181 var results = this.results; 2182 2183 if(results.length > 0) { 2184 for(var i=0; i < results.length; i++) { 2185 var offset = results[i]['attrs']['o']; 2186 var len = results[i]['attrs']['l']; 2187 2188 var part_1_text = this.orginal_text.substring(pointer, offset); 2189 var part_1 = GoogieSpell.createPart(part_1_text); 2190 output.appendChild(part_1); 2191 pointer += offset - pointer; 2192 2193 //If the last child was an error, then insert some space 2194 var err_link = this.createErrorLink(this.orginal_text.substr(offset, len), i); 2195 this.error_links.push(err_link); 2196 output.appendChild(err_link); 2197 pointer += len; 2198 } 2199 //Insert the rest of the orginal text 2200 var part_2_text = this.orginal_text.substr(pointer, this.orginal_text.length); 2201 2202 var part_2 = GoogieSpell.createPart(part_2_text); 2203 output.appendChild(part_2); 2204 } 2205 else 2206 output.innerHTML = this.orginal_text; 2207 2208 var me = this; 2209 if(this.custom_item_evaulator) 2210 AJS.map(this.error_links, function(elm){me.custom_item_evaulator(me, elm)}); 2211 2212 AJS.ACN(this.edit_layer, output); 2213 2214 //Hide text area 2215 this.text_area_bottom = this.text_area.offsetTop + this.text_area.offsetHeight; 2216 2217 AJS.hideElement(this.text_area); 2218 2219 AJS.insertBefore(this.edit_layer, this.text_area); 2220 2221 if(this.use_focus) { 2222 this.focus_link_t = this.createFocusLink('focus_t'); 2223 this.focus_link_b = this.createFocusLink('focus_b'); 2224 2225 AJS.insertBefore(this.focus_link_t, this.edit_layer); 2226 AJS.insertAfter(this.focus_link_b, this.edit_layer); 2227 } 2228 2229 this.edit_layer.scrollTop = this.ta_scroll_top; 2230 } 2231 2232 2233 ////// 2234 // Choose language menu 2235 ////// 2236 GoogieSpell.prototype.createLangWindow = function() { 2237 this.language_window = AJS.DIV({'class': 'googie_window'}); 2238 AJS.setWidth(this.language_window, 100); 2239 2240 this.language_window.googie_action_btn = "1"; 2241 2242 //Build up the result list 2243 var table = AJS.TABLE({'class': 'googie_list'}); 2244 AJS.setWidth(table, "100%"); 2245 var list = AJS.TBODY(); 2246 2247 this.lang_elms = new Array(); 2248 2249 for(i=0; i < this.langlist_codes.length; i++) { 2250 var row = AJS.TR(); 2251 var item = AJS.TD(); 2252 item.googieId = this.langlist_codes[i]; 2253 this.lang_elms.push(item); 2254 var lang_span = AJS.SPAN(); 2255 lang_span.innerHTML = this.lang_to_word[this.langlist_codes[i]]; 2256 item.appendChild(AJS.TN(lang_span.innerHTML)); 2257 2258 var fn = function(e) { 2259 var elm = AJS.getEventElm(e); 2260 this.deHighlightCurSel(); 2261 2262 this.setCurrentLanguage(elm.googieId); 2263 2264 if(this.lang_state_observer != null) { 2265 this.lang_state_observer(); 2266 } 2267 2268 this.highlightCurSel(); 2269 this.hideLangWindow(); 2270 }; 2271 AJS.AEV(item, "click", AJS.$b(fn, this)); 2272 2273 item.onmouseover = function(e) { 2274 var i_it = AJS.getEventElm(e); 2275 if(i_it.className != "googie_list_selected") 2276 i_it.className = "googie_list_onhover"; 2277 }; 2278 item.onmouseout = function(e) { 2279 var i_it = AJS.getEventElm(e); 2280 if(i_it.className != "googie_list_selected") 2281 i_it.className = "googie_list_onout"; 2282 }; 2283 2284 row.appendChild(item); 2285 list.appendChild(row); 2286 } 2287 2288 //Close button 2289 if(this.use_close_btn) { 2290 list.appendChild(this.createCloseButton(this.hideLangWindow)); 2291 } 2292 2293 this.highlightCurSel(); 2294 2295 table.appendChild(list); 2296 this.language_window.appendChild(table); 2297 } 2298 2299 GoogieSpell.prototype.setCurrentLanguage = function(lan_code) { 2300 GOOGIE_CUR_LANG = lan_code; 2301 2302 //Set cookie 2303 var now = new Date(); 2304 now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); 2305 setCookie('language', lan_code, now); 2306 } 2307 2308 GoogieSpell.prototype.isLangWindowShown = function() { 2309 return this.language_window != null && this.language_window.style.visibility == "visible"; 2310 } 2311 2312 GoogieSpell.prototype.hideLangWindow = function() { 2313 try { 2314 this.language_window.style.visibility = "hidden"; 2315 this.switch_lan_pic.className = "googie_lang_3d_on"; 2316 } 2317 catch(e) {} 2318 } 2319 2320 GoogieSpell.prototype.deHighlightCurSel = function() { 2321 this.lang_cur_elm.className = "googie_list_onout"; 2322 } 2323 2324 GoogieSpell.prototype.highlightCurSel = function() { 2325 if(GOOGIE_CUR_LANG == null) 2326 GOOGIE_CUR_LANG = GOOGIE_DEFAULT_LANG; 2327 for(var i=0; i < this.lang_elms.length; i++) { 2328 if(this.lang_elms[i].googieId == GOOGIE_CUR_LANG) { 2329 this.lang_elms[i].className = "googie_list_selected"; 2330 this.lang_cur_elm = this.lang_elms[i]; 2331 } 2332 else { 2333 this.lang_elms[i].className = "googie_list_onout"; 2334 } 2335 } 2336 } 2337 2338 GoogieSpell.prototype.showLangWindow = function(elm, ofst_top, ofst_left) { 2339 if(this.show_menu_observer) 2340 this.show_menu_observer(this); 2341 if(!AJS.isDefined(ofst_top)) 2342 ofst_top = 18; // modified by roundcube 2343 if(!AJS.isDefined(ofst_left)) 2344 ofst_left = 22; // modified by roundcube 2345 2346 this.createLangWindow(); 2347 AJS.getBody().appendChild(this.language_window); 2348 2349 var abs_pos = AJS.absolutePosition(elm); 2350 AJS.showElement(this.language_window); 2351 AJS.setTop(this.language_window, (abs_pos.y+ofst_top)); 2352 AJS.setLeft(this.language_window, (abs_pos.x+ofst_left-this.language_window.offsetWidth)); 2353 2354 this.highlightCurSel(); 2355 this.language_window.style.visibility = "visible"; 2356 } 2357 2358 GoogieSpell.prototype.createChangeLangPic = function() { 2359 var img = AJS.IMG({'src': this.img_dir + 'change_lang.gif', 'alt': "Change language"}); 2360 img.googie_action_btn = "1"; 2361 var switch_lan = AJS.SPAN({'class': 'googie_lang_3d_on', 'style': 'padding-left: 6px;'}, img); 2362 2363 var fn = function(e) { 2364 var elm = AJS.getEventElm(e); 2365 if(AJS.nodeName(elm) == 'img') 2366 elm = elm.parentNode; 2367 if(elm.className == "googie_lang_3d_click") { 2368 elm.className = "googie_lang_3d_on"; 2369 this.hideLangWindow(); 2370 } 2371 else { 2372 elm.className = "googie_lang_3d_click"; 2373 this.showLangWindow(switch_lan); 2374 } 2375 } 2376 2377 AJS.AEV(switch_lan, "click", AJS.$b(fn, this)); 2378 return switch_lan; 2379 } 2380 2381 GoogieSpell.prototype.createSpellDiv = function() { 2382 var chk_spell = AJS.SPAN({'class': 'googie_check_spelling_link'}); 2383 2384 chk_spell.innerHTML = this.lang_chck_spell; 2385 var spell_img = null; 2386 if(this.show_spell_img) 2387 spell_img = AJS.IMG({'src': this.img_dir + "spellc.gif"}); 2388 return AJS.SPAN(spell_img, " ", chk_spell); 2389 } 2390 2391 2392 ////// 2393 // State functions 2394 ///// 2395 GoogieSpell.prototype.flashNoSpellingErrorState = function(on_finish) { 2396 var no_spell_errors; 2397 2398 if(on_finish) { 2399 var fn = function() { 2400 on_finish(); 2401 this.checkSpellingState(); 2402 }; 2403 no_spell_errors = fn; 2404 } 2405 else 2406 no_spell_errors = this.checkSpellingState; 2407 2408 this.setStateChanged("no_error_found"); 2409 2410 if(this.main_controller) { 2411 AJS.hideElement(this.switch_lan_pic); 2412 2413 var dummy = AJS.IMG({'src': this.img_dir + "blank.gif", 'style': 'height: 16px; width: 1px;'}); 2414 var rsm = AJS.SPAN(); 2415 rsm.innerHTML = this.lang_no_error_found; 2416 2417 AJS.RCN(this.spell_span, AJS.SPAN(dummy, rsm)); 2418 2419 this.spell_span.className = "googie_check_spelling_ok"; 2420 this.spell_span.style.textDecoration = "none"; 2421 this.spell_span.style.cursor = "default"; 2422 2423 AJS.callLater(AJS.$b(no_spell_errors, this), 1200, [false]); 2424 } 2425 } 2426 2427 GoogieSpell.prototype.resumeEditingState = function() { 2428 this.setStateChanged("resume_editing"); 2429 2430 //Change link text to resume 2431 if(this.main_controller) { 2432 AJS.hideElement(this.switch_lan_pic); 2433 var dummy = AJS.IMG({'src': this.img_dir + "blank.gif", 'style': 'height: 16px; width: 1px;'}); 2434 var rsm = AJS.SPAN(); 2435 rsm.innerHTML = this.lang_rsm_edt; 2436 AJS.RCN(this.spell_span, AJS.SPAN(dummy, rsm)); 2437 2438 var fn = function(e) { 2439 this.resumeEditing(); 2440 } 2441 this.spell_span.onclick = AJS.$b(fn, this); 2442 2443 this.spell_span.className = "googie_resume_editing"; 2444 } 2445 2446 try { this.edit_layer.scrollTop = this.ta_scroll_top; } 2447 catch(e) { } 2448 } 2449 2450 GoogieSpell.prototype.checkSpellingState = function(fire) { 2451 if(!AJS.isDefined(fire) || fire) 2452 this.setStateChanged("spell_check"); 2453 2454 if(this.show_change_lang_pic) 2455 this.switch_lan_pic = this.createChangeLangPic(); 2456 else 2457 this.switch_lan_pic = AJS.SPAN(); 2458 2459 var span_chck = this.createSpellDiv(); 2460 var fn = function() { 2461 this.spellCheck(); 2462 }; 2463 2464 if(this.custom_spellcheck_starter) 2465 span_chck.onclick = this.custom_spellcheck_starter; 2466 else { 2467 span_chck.onclick = AJS.$b(fn, this); 2468 } 2469 2470 this.spell_span = span_chck; 2471 if(this.main_controller) { 2472 if(this.change_lang_pic_placement == "left") 2473 AJS.RCN(this.spell_container, span_chck, " ", this.switch_lan_pic); 2474 else 2475 AJS.RCN(this.spell_container, this.switch_lan_pic, " ", span_chck); 2476 } 2477 // modified by roundcube 2478 this.check_link = span_chck; 2479 } 2480 2481 2482 ////// 2483 // Misc. functions 2484 ///// 631 2485 GoogieSpell.item_onmouseover = function(e) { 632 var elm = GoogieSpell.getEventElm(e); 633 if(elm.className != "googie_list_close" && elm.className != "googie_list_revert") 634 elm.className = "googie_list_onhover"; 635 else 636 elm.parentNode.className = "googie_list_onhover"; 637 } 638 2486 var elm = AJS.getEventElm(e); 2487 if(elm.className != "googie_list_revert" && elm.className != "googie_list_close") 2488 elm.className = "googie_list_onhover"; 2489 else 2490 elm.parentNode.className = "googie_list_onhover"; 2491 } 639 2492 GoogieSpell.item_onmouseout = function(e) { 640 var elm = GoogieSpell.getEventElm(e); 641 if(elm.className != "googie_list_close" && elm.className != "googie_list_revert") 642 elm.className = "googie_list_onout"; 643 else 644 elm.parentNode.className = "googie_list_onout"; 645 } 646 647 GoogieSpell.prototype.getGoogleUrl = function() { 648 return this.server_url + GOOGIE_CUR_LANG; 649 } 650 651 GoogieSpell.prototype.spellCheck = function(elm, name) { 652 this.ta_scroll_top = this.text_area.scrollTop; 653 654 this.appendIndicator(elm); 655 656 try { 657 this.hideLangWindow(); 658 } 659 catch(e) {} 660 661 this.gselm = elm; 662 663 this.createEditLayer(this.text_area.offsetWidth, this.text_area.offsetHeight); 664 665 this.createErrorWindow(); 666 AJS.getBody().appendChild(this.error_window); 667 668 try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } 669 catch (e) { } 670 671 this.gselm.onclick = null; 672 673 this.orginal_text = this.text_area.value; 674 var me = this; 675 676 //Create request 677 var d = AJS.getRequest(this.getGoogleUrl()); 678 var reqdone = function(req) { 679 var r_text = req.responseText; 680 if(r_text.match(/<c.*>/) != null) { 681 var results = GoogieSpell.parseResult(r_text); 682 //Before parsing be sure that errors were found 683 me.results = results; 684 me.showErrorsInIframe(results); 685 me.resumeEditingState(); 2493 var elm = AJS.getEventElm(e); 2494 if(elm.className != "googie_list_revert" && elm.className != "googie_list_close") 2495 elm.className = "googie_list_onout"; 2496 else 2497 elm.parentNode.className = "googie_list_onout"; 2498 } 2499 2500 GoogieSpell.prototype.createCloseButton = function(c_fn) { 2501 return this.createButton(this.lang_close, 'googie_list_close', AJS.$b(c_fn, this)); 2502 } 2503 2504 GoogieSpell.prototype.createButton = function(name, css_class, c_fn) { 2505 var btn_row = AJS.TR(); 2506 var btn = AJS.TD(); 2507 2508 btn.onmouseover = GoogieSpell.item_onmouseover; 2509 btn.onmouseout = GoogieSpell.item_onmouseout; 2510 2511 var spn_btn; 2512 if(css_class != "") { 2513 spn_btn = AJS.SPAN({'class': css_class}); 2514 spn_btn.innerHTML = name; 686 2515 } 687 2516 else { 688 me.flashNoSpellingErrorState(); 689 } 690 me.removeIndicator(); 691 }; 692 693 var reqfailed = function(req) { 694 alert("An error was encountered on the server. Please try again later."); 695 AJS.removeElement(me.gselm); 696 me.checkSpellingState(); 697 me.removeIndicator(); 698 }; 699 700 d.addCallback(reqdone); 701 d.addErrback(reqfailed); 702 703 var req_text = GoogieSpell.escapeSepcial(this.orginal_text); 704 d.sendReq(GoogieSpell.createXMLReq(req_text)); 705 } 706 707 GoogieSpell.escapeSepcial = function(val) { 708 return val.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); 709 } 710 711 GoogieSpell.createXMLReq = function (text) { 712 return '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' + text + '</text></spellrequest>'; 713 } 714 715 //Retunrs an array 716 //result[item] -> ['attrs'] 717 // ['suggestions'] 718 GoogieSpell.parseResult = function(r_text) { 719 var re_split_attr_c = /\w="\d+"/g; 720 var re_split_text = /\t/g; 721 722 var matched_c = r_text.match(/<c[^>]*>[^<]*<\/c>/g); 723 var results = new Array(); 724 725 for(var i=0; i < matched_c.length; i++) { 726 var item = new Array(); 727 728 //Get attributes 729 item['attrs'] = new Array(); 730 var split_c = matched_c[i].match(re_split_attr_c); 731 for(var j=0; j < split_c.length; j++) { 732 var c_attr = split_c[j].split(/=/); 733 item['attrs'][c_attr[0]] = parseInt(c_attr[1].replace('"', '')); 734 } 735 736 //Get suggestions 737 item['suggestions'] = new Array(); 738 var only_text = matched_c[i].replace(/<[^>]*>/g, ""); 739 var split_t = only_text.split(re_split_text); 740 for(var k=0; k < split_t.length; k++) { 741 if(split_t[k] != "") 742 item['suggestions'].push(split_t[k]); 743 } 744 results.push(item); 745 } 746 return results; 747 } 748 749 /**** 750 Error window (the drop-down window) 751 ****/ 752 GoogieSpell.prototype.createErrorWindow = function() { 753 this.error_window = AJS.DIV(); 754 this.error_window.className = "googie_window"; 755 } 756 757 GoogieSpell.prototype.hideErrorWindow = function() { 758 this.error_window.style.visibility = "hidden"; 759 } 760 761 GoogieSpell.prototype.updateOrginalText = function(offset, old_value, new_value, id) { 762 var part_1 = this.orginal_text.substring(0, offset); 763 var part_2 = this.orginal_text.substring(offset+old_value.length); 764 this.orginal_text = part_1 + new_value + part_2; 765 var add_2_offset = new_value.length - old_value.length; 766 for(var j=0; j < this.results.length; j++) { 767 //Don't edit the offset of the current item 768 if(j != id && j > id){ 769 this.results[j]['attrs']['o'] += add_2_offset; 770 } 771 } 772 } 773 774 GoogieSpell.prototype.saveOldValue = function (id, old_value) { 775 this.results[id]['is_changed'] = true; 776 this.results[id]['old_value'] = old_value; 777 } 778 779 GoogieSpell.prototype.showErrorWindow = function(elm, id) { 780 var me = this; 781 782 var abs_pos = GoogieSpell.absolutePosition(elm); 783 abs_pos.y -= this.edit_layer.scrollTop; 784 this.error_window.style.visibility = "visible"; 785 this.error_window.style.top = (abs_pos.y+20) + "px"; 786 this.error_window.style.left = (abs_pos.x) + "px"; 787 this.error_window.innerHTML = ""; 788 789 //Build up the result list 790 var table = AJS.TABLE({'class': 'googie_list'}); 791 var list = AJS.TBODY(); 792 793 var suggestions = this.results[id]['suggestions']; 794 var offset = this.results[id]['attrs']['o']; 795 var len = this.results[id]['attrs']['l']; 796 797 if(suggestions.length == 0) { 798 var row = AJS.TR(); 799 var item = AJS.TD(); 800 var dummy = AJS.SPAN(); 801 item.appendChild(AJS.TN("No suggestions :(")); 802 row.appendChild(item); 803 list.appendChild(row); 804 } 805 806 for(i=0; i < suggestions.length; i++) { 807 var row = AJS.TR(); 808 var item = AJS.TD(); 809 var dummy = AJS.SPAN(); 810 dummy.innerHTML = suggestions[i]; 811 item.appendChild(AJS.TN(dummy.innerHTML)); 812 813 item.onclick = function(e) { 814 var l_elm = GoogieSpell.getEventElm(e); 815 var old_value = elm.innerHTML; 816 var new_value = l_elm.innerHTML; 817 818 elm.style.color = "green"; 819 elm.innerHTML = l_elm.innerHTML; 820 me.hideErrorWindow(); 821 822 me.updateOrginalText(offset, old_value, new_value, id); 823 824 //Update to the new length 825 me.results[id]['attrs']['l'] = new_value.length; 826 me.saveOldValue(id, old_value); 827 }; 828 item.onmouseover = GoogieSpell.item_onmouseover; 829 item.onmouseout = GoogieSpell.item_onmouseout; 830 row.appendChild(item); 831 list.appendChild(row); 832 } 833 834 //The element is changed, append the revert 835 if(this.results[id]['is_changed']) { 836 var old_value = this.results[id]['old_value']; 837 var offset = this.results[id]['attrs']['o']; 838 var revert_row = AJS.TR(); 839 var revert = AJS.TD(); 840 841 revert.onmouseover = GoogieSpell.item_onmouseover; 842 revert.onmouseout = GoogieSpell.item_onmouseout; 843 var rev_span = AJS.SPAN({'class': 'googie_list_revert'}); 844 rev_span.innerHTML = this.lang_revert + " " + old_value; 845 revert.appendChild(rev_span); 846 847 revert.onclick = function(e) { 848 me.updateOrginalText(offset, elm.innerHTML, old_value, id); 849 elm.style.color = "#b91414"; 850 elm.innerHTML = old_value; 851 me.hideErrorWindow(); 852 }; 853 854 revert_row.appendChild(revert); 855 list.appendChild(revert_row); 856 } 857 858 //Append the edit box 859 var edit_row = AJS.TR(); 860 var edit = AJS.TD(); 861 862 var edit_input = AJS.INPUT({'style': 'width: 120px; margin:0; padding:0'}); 863 864 var onsub = function () { 865 if(edit_input.value != "") { 866 me.saveOldValue(id, elm.innerHTML); 867 me.updateOrginalText(offset, elm.innerHTML, edit_input.value, id); 868 elm.style.color = "green" 869 elm.innerHTML = edit_input.value; 870 871 me.hideErrorWindow(); 872 return false; 873 } 874 }; 875 876 var ok_pic = AJS.IMG({'src': this.img_dir + "ok.gif", 'style': 'width: 32px; height: 16px; margin-left: 2px; margin-right: 2px;'}); 877 var edit_form = AJS.FORM({'style': 'margin: 0; padding: 0'}, edit_input, ok_pic); 878 ok_pic.onclick = onsub; 879 edit_form.onsubmit = onsub; 880 881 edit.appendChild(edit_form); 882 edit_row.appendChild(edit); 883 list.appendChild(edit_row); 884 885 //Close button 886 var close_row = AJS.TR(); 887 var close = AJS.TD(); 888 889 close.onmouseover = GoogieSpell.item_onmouseover; 890 close.onmouseout = GoogieSpell.item_onmouseout; 891 892 var spn_close = AJS.SPAN({'class': 'googie_list_close'}); 893 spn_close.innerHTML = this.lang_close; 894 close.appendChild(spn_close); 895 close.onclick = function() { me.hideErrorWindow()}; 896 close_row.appendChild(close); 897 list.appendChild(close_row); 898 899 table.appendChild(list); 900 this.error_window.appendChild(table); 901 } 902 903 904 /**** 905 Edit layer (the layer where the suggestions are stored) 906 ****/ 907 GoogieSpell.prototype.createEditLayer = function(width, height) { 908 this.edit_layer = AJS.DIV({'class': 'googie_edit_layer'}); 909 910 //Set the style so it looks like edit areas 911 this.edit_layer.className = this.text_area.className; 912 this.edit_layer.style.border = "1px solid #999"; 913 this.edit_layer.style.overflow = "auto"; 914 this.edit_layer.style.backgroundColor = "#F1EDFE"; 915 this.edit_layer.style.padding = "3px"; 916 917 this.edit_layer.style.width = (width-8) + "px"; 918 this.edit_layer.style.height = height + "px"; 919 } 920 921 GoogieSpell.prototype.resumeEditing = function(e, me) { 922 this.setStateChanged("check_spelling"); 923 me.switch_lan_pic.style.display = "inline"; 924 925 this.el_scroll_top = me.edit_layer.scrollTop; 926 927 var elm = GoogieSpell.getEventElm(e); 928 AJS.replaceChildNodes(elm, this.createSpellDiv()); 929 930 elm.onclick = function(e) { 931 me.spellCheck(elm, me.text_area.id); 932 }; 933 me.hideErrorWindow(); 934 935 //Remove the EDIT_LAYER 936 me.edit_layer.parentNode.removeChild(me.edit_layer); 937 938 me.text_area.value = me.orginal_text; 939 AJS.showElement(me.text_area); 940 me.gselm.className = "googie_no_style"; 941 942 me.text_area.scrollTop = this.el_scroll_top; 943 944 elm.onmouseout = null; 945 } 946 947 GoogieSpell.prototype.createErrorLink = function(text, id) { 948 var elm = AJS.SPAN({'class': 'googie_link'}); 949 var me = this; 950 elm.onclick = function () { 951 me.showErrorWindow(elm, id); 952 }; 953 elm.innerHTML = text; 954 return elm; 955 } 956 957 GoogieSpell.createPart = function(txt_part) { 958 if(txt_part == " ") 959 return AJS.TN(" "); 960 var result = AJS.SPAN(); 961 962 var is_first = true; 963 var is_safari = (navigator.userAgent.toLowerCase().indexOf("safari") != -1); 964 965 var part = AJS.SPAN(); 966 txt_part = GoogieSpell.escapeSepcial(txt_part); 967 txt_part = txt_part.replace(/\n/g, "<br>"); 968 txt_part = txt_part.replace(/ /g, " "); 969 txt_part = txt_part.replace(/^ /g, " "); 970 txt_part = txt_part.replace(/ $/g, " "); 971 972 part.innerHTML = txt_part; 973 974 return part; 975 } 976 977 GoogieSpell.prototype.showErrorsInIframe = function(results) { 978 var output = AJS.DIV(); 979 output.style.textAlign = "left"; 980 var pointer = 0; 981 for(var i=0; i < results.length; i++) { 982 var offset = results[i]['attrs']['o']; 983 var len = results[i]['attrs']['l']; 984 985 var part_1_text = this.orginal_text.substring(pointer, offset); 986 var part_1 = GoogieSpell.createPart(part_1_text); 987 output.appendChild(part_1); 988 pointer += offset - pointer; 989 990 //If the last child was an error, then insert some space 991 output.appendChild(this.createErrorLink(this.orginal_text.substr(offset, len), i)); 992 pointer += len; 993 } 994 //Insert the rest of the orginal text 995 var part_2_text = this.orginal_text.substr(pointer, this.orginal_text.length); 996 997 var part_2 = GoogieSpell.createPart(part_2_text); 998 output.appendChild(part_2); 999 1000 this.edit_layer.appendChild(output); 1001 1002 //Hide text area 1003 AJS.hideElement(this.text_area); 1004 this.text_area.parentNode.insertBefore(this.edit_layer, this.text_area.nextSibling); 1005 this.edit_layer.scrollTop = this.ta_scroll_top; 1006 } 1007 1008 GoogieSpell.Position = function(x, y) { 1009 this.x = x; 1010 this.y = y; 1011 } 1012 1013 //Get the absolute position of menu_slide 1014 GoogieSpell.absolutePosition = function(element) { 1015 //Create a new object that has elements y and x pos... 1016 var posObj = new GoogieSpell.Position(element.offsetLeft, element.offsetTop); 1017 1018 //Check if the element has an offsetParent - if it has .. loop until it has not 1019 if(element.offsetParent) { 1020 var temp_pos = GoogieSpell.absolutePosition(element.offsetParent); 1021 posObj.x += temp_pos.x; 1022 posObj.y += temp_pos.y; 1023 } 1024 return posObj; 1025 } 1026 1027 GoogieSpell.getEventElm = function(e) { 1028 var targ; 1029 if (!e) var e = window.event; 1030 if (e.target) targ = e.target; 1031 else if (e.srcElement) targ = e.srcElement; 1032 if (targ.nodeType == 3) // defeat Safari bug 1033 targ = targ.parentNode; 1034 return targ; 2517 spn_btn = AJS.TN(name); 2518 } 2519 btn.appendChild(spn_btn); 2520 AJS.AEV(btn, "click", c_fn); 2521 btn_row.appendChild(btn); 2522 2523 return btn_row; 1035 2524 } 1036 2525 1037 2526 GoogieSpell.prototype.removeIndicator = function(elm) { 1038 // modified by roundcube 1039 if (window.rcube_webmail_client) 1040 rcube_webmail_client.set_busy(false); 1041 //AJS.removeElement(this.indicator); 2527 // modified by roundcube 2528 if (window.rcmail) 2529 rcmail.set_busy(false); 2530 //try { AJS.removeElement(this.indicator); } 2531 //catch(e) {} 1042 2532 } 1043 2533 1044 2534 GoogieSpell.prototype.appendIndicator = function(elm) { 1045 // modified by roundcube 1046 if (window.rcube_webmail_client) 1047 rcube_webmail_client.set_busy(true, 'checking'); 1048 /* 1049 var img = AJS.IMG({'src': this.img_dir + 'indicator.gif', 'style': 'margin-right: 5px;'}); 1050 img.style.width = "16px"; 1051 img.style.height = "16px"; 1052 this.indicator = img; 1053 img.style.textDecoration = "none"; 1054 AJS.insertBefore(img, elm); 2535 // modified by roundcube 2536 if (window.rcmail) 2537 rcmail.set_busy(true, 'checking'); 2538 /* 2539 var img = AJS.IMG({'src': this.img_dir + 'indicator.gif', 'style': 'margin-right: 5px;'}); 2540 AJS.setWidth(img, 16); 2541 AJS.setHeight(img, 16); 2542 this.indicator = img; 2543 img.style.textDecoration = "none"; 2544 try { 2545 AJS.insertBefore(img, elm); 2546 } 2547 catch(e) {} 1055 2548 */ 1056 2549 } 1057 2550 1058 /**** 1059 Choose language 1060 ****/ 1061 GoogieSpell.prototype.createLangWindow = function() { 1062 this.language_window = AJS.DIV({'class': 'googie_window'}); 1063 this.language_window.style.width = "130px"; 1064 1065 //Build up the result list 1066 var table = AJS.TABLE({'class': 'googie_list'}); 1067 var list = AJS.TBODY(); 1068 1069 this.lang_elms = new Array(); 1070 1071 for(i=0; i < this.langlist_codes.length; i++) { 1072 var row = AJS.TR(); 1073 var item = AJS.TD(); 1074 item.googieId = this.langlist_codes[i]; 1075 this.lang_elms.push(item); 1076 var lang_span = AJS.SPAN(); 1077 lang_span.innerHTML = this.lang_to_word[this.langlist_codes[i]]; 1078 item.appendChild(AJS.TN(lang_span.innerHTML)); 1079 1080 var me = this; 1081 1082 item.onclick = function(e) { 1083 var elm = GoogieSpell.getEventElm(e); 1084 me.deHighlightCurSel(); 1085 1086 me.setCurrentLanguage(elm.googieId); 1087 1088 if(me.lang_state_observer != null) { 1089 me.lang_state_observer(); 1090 } 1091 1092 me.highlightCurSel(); 1093 me.hideLangWindow(); 1094 }; 1095 1096 item.onmouseover = function(e) { 1097 var i_it = GoogieSpell.getEventElm(e); 1098 if(i_it.className != "googie_list_selected") 1099 i_it.className = "googie_list_onhover"; 1100 }; 1101 item.onmouseout = function(e) { 1102 var i_it = GoogieSpell.getEventElm(e); 1103 if(i_it.className != "googie_list_selected") 1104 i_it.className = "googie_list_onout"; 1105 }; 1106 1107 row.appendChild(item); 1108 list.appendChild(row); 1109 } 1110 1111 this.highlightCurSel(); 1112 1113 //Close button 1114 var close_row = AJS.TR(); 1115 var close = AJS.TD(); 1116 close.onmouseover = GoogieSpell.item_onmouseover; 1117 close.onmouseout = GoogieSpell.item_onmouseout; 1118 var spn_close = AJS.SPAN({'class': 'googie_list_close'}); 1119 spn_close.innerHTML = this.lang_close; 1120 close.appendChild(spn_close); 1121 var me = this; 1122 close.onclick = function(e) { 1123 me.hideLangWindow(); GoogieSpell.item_onmouseout(e); 1124 }; 1125 close_row.appendChild(close); 1126 list.appendChild(close_row); 1127 1128 table.appendChild(list); 1129 this.language_window.appendChild(table); 1130 } 1131 1132 GoogieSpell.prototype.setCurrentLanguage = function(lan_code) { 1133 GOOGIE_CUR_LANG = lan_code; 1134 1135 //Set cookie 1136 var now = new Date(); 1137 now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); 1138 setCookie('language', lan_code, now); 1139 } 1140 1141 GoogieSpell.prototype.hideLangWindow = function() { 1142 this.language_window.style.visibility = "hidden"; 1143 this.switch_lan_pic.className = "googie_lang_3d_on"; 1144 } 1145 1146 GoogieSpell.prototype.deHighlightCurSel = function() { 1147 this.lang_cur_elm.className = "googie_list_onout"; 1148 } 1149 1150 GoogieSpell.prototype.highlightCurSel = function() { 1151 for(var i=0; i < this.lang_elms.length; i++) { 1152 if(this.lang_elms[i].googieId == GOOGIE_CUR_LANG) { 1153 this.lang_elms[i].className = "googie_list_selected"; 1154 this.lang_cur_elm = this.lang_elms[i]; 1155 } 1156 else { 1157 this.lang_elms[i].className = "googie_list_onout"; 1158 } 1159 } 1160 } 1161 1162 GoogieSpell.prototype.showLangWindow = function(elm, ofst_top, ofst_left) { 1163 if(!AJS.isDefined(ofst_top)) 1164 ofst_top = 20; 1165 if(!AJS.isDefined(ofst_left)) 1166 ofst_left = 50; 1167 1168 this.createLangWindow(); 1169 AJS.getBody().appendChild(this.language_window); 1170 1171 var abs_pos = GoogieSpell.absolutePosition(elm); 1172 AJS.showElement(this.language_window); 1173 this.language_window.style.top = (abs_pos.y+ofst_top) + "px"; 1174 this.language_window.style.left = (abs_pos.x+ofst_left-this.language_window.offsetWidth) + "px"; 1175 this.highlightCurSel(); 1176 this.language_window.style.visibility = "visible"; 1177 } 1178 1179 GoogieSpell.prototype.flashNoSpellingErrorState = function() { 1180 this.setStateChanged("no_error_found"); 1181 var me = this; 1182 AJS.hideElement(this.switch_lan_pic); 1183 this.gselm.innerHTML = this.lang_no_error_found; 1184 this.gselm.className = "googie_check_spelling_ok"; 1185 this.gselm.style.textDecoration = "none"; 1186 this.gselm.style.cursor = "default"; 1187 var fu = function() { 1188 AJS.removeElement(me.gselm); 1189 me.checkSpellingState(); 1190 }; 1191 setTimeout(fu, 1000); 1192 } 1193 1194 GoogieSpell.prototype.resumeEditingState = function() { 1195 this.setStateChanged("resume_editing"); 1196 var me = this; 1197 AJS.hideElement(me.switch_lan_pic); 1198 1199 //Change link text to resume 1200 me.gselm.innerHTML = this.lang_rsm_edt; 1201 me.gselm.onclick = function(e) { 1202 me.resumeEditing(e, me); 1203 } 1204 me.gselm.className = "googie_check_spelling_ok"; 1205 me.edit_layer.scrollTop = me.ta_scroll_top; 1206 } 1207 1208 GoogieSpell.prototype.createChangeLangPic = function() { 1209 var switch_lan = AJS.A({'class': 'googie_lang_3d_on', 'style': 'padding-left: 6px;'}, AJS.IMG({'src': this.img_dir + 'change_lang.gif', 'alt': "Change language"})); 1210 switch_lan.onmouseover = function() { 1211 if(this.className != "googie_lang_3d_click") 1212 this.className = "googie_lang_3d_on"; 1213 } 1214 1215 var me = this; 1216 switch_lan.onclick = function() { 1217 if(this.className == "googie_lang_3d_click") { 1218 me.hideLangWindow(); 1219 } 1220 else { 1221 me.showLangWindow(switch_lan); 1222 this.className = "googie_lang_3d_click"; 1223 } 1224 } 1225 return switch_lan; 1226 } 1227 1228 GoogieSpell.prototype.createSpellDiv = function() { 1229 var chk_spell = AJS.SPAN({'class': 'googie_check_spelling_link'}); 1230 chk_spell.innerHTML = this.lang_chck_spell; 1231 var spell_img = null; 1232 if(this.show_spell_img) 1233 spell_img = AJS.IMG({'src': this.img_dir + "spellc.gif"}); 1234 return AJS.SPAN(spell_img, " ", chk_spell); 1235 } 1236 1237 GoogieSpell.prototype.checkSpellingState = function() { 1238 this.setStateChanged("check_spelling"); 1239 var me = this; 1240 if(this.show_change_lang_pic) 1241 this.switch_lan_pic = this.createChangeLangPic(); 1242 else 1243 this.switch_lan_pic = AJS.SPAN(); 1244 1245 var span_chck = this.createSpellDiv(); 1246 span_chck.onclick = function() { 1247 me.spellCheck(span_chck); 1248 } 1249 AJS.appendChildNodes(this.spell_container, span_chck, " ", this.switch_lan_pic); 1250 // modified by roundcube 1251 this.check_link = span_chck; 1252 } 1253 1254 GoogieSpell.prototype.setLanguages = function(lang_dict) { 1255 this.lang_to_word = lang_dict; 1256 this.langlist_codes = AJS.keys(lang_dict); 1257 } 1258 1259 GoogieSpell.prototype.decorateTextarea = function(id, /*optional*/spell_container_id, force_width) { 1260 var me = this; 1261 1262 if(typeof(id) == "string") 1263 this.text_area = AJS.getElement(id); 1264 else 1265 this.text_area = id; 1266 1267 var r_width; 1268 1269 if(this.text_area != null) { 1270 if(AJS.isDefined(spell_container_id)) { 1271 if(typeof(spell_container_id) == "string") 1272 this.spell_container = AJS.getElement(spell_container_id); 1273 else 1274 this.spell_container = spell_container_id; 1275 } 1276 else { 1277 var table = AJS.TABLE(); 1278 var tbody = AJS.TBODY(); 1279 var tr = AJS.TR(); 1280 if(AJS.isDefined(force_width)) { 1281 r_width = force_width; 1282 } 1283 else { 1284 r_width = this.text_area.offsetWidth + "px"; 1285 } 1286 1287 var spell_container = AJS.TD(); 1288 this.spell_container = spell_container; 1289 1290 tr.appendChild(spell_container); 1291 1292 tbody.appendChild(tr); 1293 table.appendChild(tbody); 1294 1295 AJS.insertBefore(table, this.text_area); 1296 1297 //Set width 1298 table.style.width = '100%'; // modified by roundcube (old: r_width) 1299 spell_container.style.width = r_width; 1300 spell_container.style.textAlign = "right"; 1301 } 1302 1303 this.checkSpellingState(); 1304 } 1305 else { 1306 alert("Text area not found"); 1307 } 1308 } 2551 GoogieSpell.prototype.createFocusLink = function(name) { 2552 return AJS.A({'href': 'javascript:;', name: name}); 2553 } -
skins/default/googiespell.css
r2c63370 rffa6c10 63 63 } 64 64 65 .googie_check_spelling_link { 65 .googie_resume_editing, 66 .googie_check_spelling_link { 66 67 color: #CC0000; 67 68 font-size: 11px; … … 70 71 } 71 72 73 .googie_resume_editing:hover, 72 74 .googie_check_spelling_link:hover { 73 75 text-decoration: underline; 76 } 77 78 .googie_resume_editing { 79 color: green; 74 80 } 75 81
Note: See TracChangeset
for help on using the changeset viewer.
