[ Index ]
 

Code source de DokuWiki 2006-11-06

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/scripts/ -> spellcheck.js (source)

   1  /**
   2   * DokuWiki Spellcheck AJAX clientside script
   3   *
   4   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   5   * @author     Andreas Gohr <andi@splitbrain.org>
   6   */
   7  
   8  /**
   9   * Licence info: This spellchecker is inspired by code by Garrison Locke available
  10   * at http://www.broken-notebook.com/spell_checker/index.php (licensed under the Terms
  11   * of an BSD license). The code in this file was nearly completly rewritten for DokuWiki
  12   * and is licensed under GPL version 2 (See COPYING for details).
  13   *
  14   * Original Copyright notice follows:
  15   *
  16   * Copyright (c) 2005, Garrison Locke
  17   * All rights reserved.
  18   *
  19   * Redistribution and use in source and binary forms, with or without
  20   * modification, are permitted provided that the following conditions are met:
  21   *
  22   *   * Redistributions of source code must retain the above copyright notice,
  23   *     this list of conditions and the following disclaimer.
  24   *   * Redistributions in binary form must reproduce the above copyright notice,
  25   *     this list of conditions and the following disclaimer in the documentation
  26   *     and/or other materials provided with the distribution.
  27   *   * Neither the name of the http://www.broken-notebook.com nor the names of its
  28   *     contributors may be used to endorse or promote products derived from this
  29   *     software without specific prior written permission.
  30   *
  31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  32   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  33   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  34   * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  35   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  37   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  38   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  40   * OF SUCH DAMAGE.
  41   */
  42  
  43  /*
  44   * Uses some general functions defined elsewhere. Here is a list:
  45   *
  46   * Defined in script.js:
  47   *
  48   *   findPosX()
  49   *   findPosY()
  50   *
  51   * Defined in events.js:
  52   *
  53   *   addEvent()
  54   *
  55   * Defined in edit.js:
  56   *
  57   *   createToolButton()
  58   */
  59  
  60  /**
  61   * quotes single quotes
  62   *
  63   * @author Andreas Gohr <andi@splitbrain.org>
  64   */
  65  function qquote(str){
  66    return str.split('\'').join('\\\'');
  67  }
  68  
  69  /**
  70   * AJAX Spellchecker Class
  71   *
  72   * Note to some function use a hardcoded instance named ajax_spell to make
  73   * references to object members. Used Object-IDs are hardcoded in the init()
  74   * method.
  75   *
  76   * @author Andreas Gohr <andi@splitbrain.org>
  77   * @author Garrison Locke <http://www.broken-notebook.com>
  78   */
  79  function ajax_spell_class(){
  80    this.inited = false;
  81    this.utf8ok = 1;
  82    this.handler = DOKU_BASE+'lib/exe/spellcheck.php';
  83    // to hold the page objects (initialized with init())
  84    this.textboxObj = null;
  85    this.showboxObj = null;
  86    this.suggestObj = null;
  87    this.editbarObj = null;
  88    this.buttonObj = null;
  89    this.imageObj  = null;
  90  
  91    // hold translations
  92    this.txtStart = 'Check Spelling';
  93    this.txtStop  = 'Resume Editing';
  94    this.txtRun   = 'Checking...';
  95    this.txtNoErr = 'No Mistakes';
  96    this.txtNoSug = 'No Suggestions';
  97    this.txtChange= 'Change';
  98  
  99    this.timer = null;
 100  
 101    /**
 102     * Initializes everything
 103     *
 104     * Call after the page was setup. Hardcoded element IDs here.
 105     *
 106     * @author Andreas Gohr <andi@splitbrain.org>
 107     */
 108    this.init = function(txtStart,txtStop,txtRun,txtNoErr,txtNoSug,txtChange){
 109       // don't run twice
 110      if (this.inited){ return; }
 111      this.inited = true;
 112  
 113      // check for AJAX availability
 114      var ajax = new sack(this.handler);
 115      if(ajax.failed){ return; }
 116  
 117      // get Elements
 118      this.textboxObj = document.getElementById('wiki__text');
 119      this.editbarObj = document.getElementById('wiki__editbar');
 120      this.showboxObj = document.getElementById('spell__result');
 121      this.suggestObj = document.getElementById('spell__suggest');
 122  
 123  
 124      // set wordwrap style with browser propritary attributes
 125      if(is_gecko){
 126        this.showboxObj.style.whiteSpace = '-moz-pre-wrap'; // Mozilla, since 1999
 127      }else if(is_opera_preseven){
 128        this.showboxObj.style.whiteSpace = '-pre-wrap';     // Opera 4-6
 129      }else if(is_opera_seven){
 130        this.showboxObj.style.whiteSpace = '-o-pre-wrap';   // Opera 7
 131      }else{
 132        this.showboxObj.style['word-wrap']   = 'break-word';    //Internet Explorer 5.5+
 133      }
 134      // Which browser supports this?
 135      // this.showboxObj.style.whiteSpace = 'pre-wrap';      // css-3
 136  
 137  
 138      // set Translation Strings
 139      this.txtStart = txtStart;
 140      this.txtStop  = txtStop;
 141      this.txtRun   = txtRun;
 142      this.txtNoErr = txtNoErr;
 143      this.txtNoSug = txtNoSug;
 144      this.txtChange= txtChange;
 145  
 146      // create ToolBar Button with ID and add it to the toolbar with null action
 147      var toolbarObj = document.getElementById('tool__bar');
 148      this.buttonObj = createToolButton('spellcheck.png',txtStart,'k','spell__check');
 149      this.buttonObj.onclick = function(){return false;};
 150      toolbarObj.appendChild(this.buttonObj);
 151      this.imageObj  = document.getElementById('spell__check_ico');
 152  
 153      // start UTF-8 compliance test - send an UTF-8 char and see what comes back
 154      ajax.AjaxFailedAlert = '';
 155      ajax.encodeURIString = false;
 156      ajax.onCompletion    = this.initReady;
 157      ajax.runAJAX('call=utf8test&data='+encodeURIComponent('ü'));
 158  
 159      // second part of initialisation is in initReady() function
 160    };
 161  
 162    /**
 163     * Eventhandler for click objects anywhere on the document
 164     *
 165     * Disables the suggestion box
 166     *
 167     * @author Andreas Gohr <andi@splitbrain.org>
 168     * @author Garrison Locke <http://www.broken-notebook.com>
 169     */
 170    this.docClick = function(e){
 171      // what was clicked?
 172      try{
 173        target = window.event.srcElement;
 174      }catch(ex){
 175        target = e.target;
 176      }
 177  
 178      if (target.id != ajax_spell.suggestObj.id){
 179        ajax_spell.suggestObj.style.display = "none";
 180      }
 181    };
 182  
 183    /**
 184     * Changes the Spellchecker link according to the given mode
 185     *
 186     * @author Andreas Gohr <andi@splitbrain.org>
 187     */
 188    this.setState = function(state){
 189      switch (state){
 190        case 'stop':
 191          ajax_spell.buttonObj.onclick   = function(){ ajax_spell.resume(); return false; };
 192          ajax_spell.buttonObj.title     = ajax_spell.txtStop;
 193          ajax_spell.buttonObj.accessKey = '';
 194          ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellstop.png';
 195          break;
 196        case 'noerr':
 197          ajax_spell.buttonObj.onclick   = function(){ajax_spell.setState('start'); return false; };
 198          ajax_spell.buttonObj.title     = ajax_spell.txtNoErr;
 199          ajax_spell.buttonObj.accessKey = '';
 200          ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellnoerr.png';
 201          break;
 202        case 'run':
 203          ajax_spell.buttonObj.onclick   = function(){return false;};
 204          ajax_spell.buttonObj.title     = ajax_spell.txtRun;
 205          ajax_spell.buttonObj.accessKey = '';
 206          ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellwait.gif';
 207          break;
 208        default:
 209          ajax_spell.buttonObj.onclick   = function(){ ajax_spell.run(); return false; };
 210          ajax_spell.buttonObj.title     = ajax_spell.txtStart+' [ALT-K]';
 211          ajax_spell.buttonObj.accessKey = 'k';
 212          ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellcheck.png';
 213          break;
 214      }
 215    };
 216  
 217    /**
 218     * Replaces a word identified by id with its correction given in word
 219     *
 220     * @author Garrison Locke <http://www.broken-notebook.com>
 221     */
 222    this.correct = function (id, word){
 223      var obj = document.getElementById('spell__error'+id);
 224      obj.innerHTML = decodeURIComponent(word);
 225      obj.style.color = "#005500";
 226      this.suggestObj.style.display = "none";
 227    };
 228  
 229    /**
 230     * Opens a prompt to let the user change the word her self
 231     *
 232     * @author Andreas Gohr <andi@splitbrain.org>
 233     */
 234    this.ask = function(id){
 235      var word = document.getElementById('spell__error'+id).innerHTML;
 236      word = prompt(this.txtChange,word);
 237      if(word){
 238        this.correct(id,encodeURIComponent(word));
 239      }
 240    };
 241  
 242    /**
 243     * Displays the suggestions for a misspelled word
 244     *
 245     * @author Andreas Gohr <andi@splitbrain.org>
 246     * @author Garrison Locke <http://www.broken-notebook.com>
 247     */
 248    this.suggest = function(){
 249      var args = this.suggest.arguments;
 250      if(!args[0]){ return; }
 251      var id   = args[0];
 252  
 253      // set position of the popup
 254      this.suggestObj.style.display = "none";
 255      var x = findPosX('spell__error'+id);
 256      var y = findPosY('spell__error'+id);
 257  
 258      // handle scrolling
 259      var scrollPos;
 260      if(is_opera){
 261        scrollPos = 0; //FIXME how to do this without browser sniffing?
 262      }else{
 263        scrollPos = this.showboxObj.scrollTop;
 264      }
 265  
 266      this.suggestObj.style.left = x+'px';
 267      this.suggestObj.style.top  = (y+16-scrollPos)+'px';
 268  
 269      // handle suggestions
 270      var text = '';
 271      if(args.length == 1){
 272        text += this.txtNoSug+'<br />';
 273      }else{
 274        for(var i=1; i<args.length; i++){
 275          text += '<a href="javascript:ajax_spell.correct('+id+',\''+
 276                  qquote(args[i])+'\')">';
 277          text += args[i];
 278          text += '</a><br />';
 279        }
 280      }
 281      // add option for manual edit
 282      text += '<a href="javascript:ajax_spell.ask('+id+')">';
 283      text += '['+this.txtChange+']';
 284      text += '</a><br />';
 285  
 286      this.suggestObj.innerHTML = text;
 287      this.suggestObj.style.display = "block";
 288    };
 289  
 290    // --- Callbacks ---
 291  
 292    /**
 293     * Callback. Called after the object was initialized and UTF-8 tested
 294     * Inside the callback 'this' is the SACK object!!
 295     *
 296     * @author Andreas Gohr <andi@splitbrain.org>
 297     */
 298    this.initReady = function(){
 299      var data = this.response;
 300  
 301      //test for UTF-8 compliance (will fail for konqueror)
 302      if(data != 'ü'){
 303        ajax_spell.utf8ok = 0;
 304      }
 305  
 306      // register click event
 307      addEvent(document,'click',ajax_spell.docClick);
 308  
 309      // register focus event
 310      addEvent(ajax_spell.textboxObj,'focus',ajax_spell.setState);
 311  
 312      // get started
 313      ajax_spell.setState('start');
 314    };
 315  
 316    /**
 317     * Callback. Called after finishing spellcheck.
 318     * Inside the callback 'this' is the SACK object!!
 319     *
 320     * @author Andreas Gohr <andi@splitbrain.org>
 321     */
 322    this.start = function(){
 323      if(ajax_spell.timer !== null){
 324        window.clearTimeout(ajax_spell.timer);
 325        ajax_spell.timer = null;
 326      }else{
 327        // there is no timer set, we timed out already
 328        return;
 329      }
 330  
 331      var data  = this.response;
 332      var error = data.charAt(0);
 333          data  = data.substring(1);
 334      if(error == '1'){
 335        ajax_spell.setState('stop');
 336  
 337        // convert numeric entities back to UTF-8 if needed
 338        if(!ajax_spell.utf8ok){
 339          data = data.replace(/&#(\d+);/g,
 340                              function(whole,match1) {
 341                                return String.fromCharCode(+match1);
 342                              });
 343        }
 344  
 345        // replace textbox through div
 346        ajax_spell.showboxObj.innerHTML     = data;
 347        ajax_spell.showboxObj.style.width   = ajax_spell.textboxObj.style.width;
 348        ajax_spell.showboxObj.style.height  = ajax_spell.textboxObj.style.height;
 349        ajax_spell.textboxObj.style.display = 'none';
 350        ajax_spell.showboxObj.style.display = 'block';
 351      }else{
 352        if(error == '2'){
 353          alert(data);
 354        }
 355        ajax_spell.textboxObj.disabled = false;
 356        ajax_spell.editbarObj.style.visibility = 'visible';
 357        ajax_spell.setState('noerr');
 358      }
 359    };
 360  
 361    /**
 362     * Callback. Gets called by resume() - switches back to edit mode
 363     * Inside the callback 'this' is the SACK object!!
 364     *
 365     * @author Andreas Gohr <andi@splitbrain.org>
 366     */
 367    this.stop = function(){
 368      var data = this.response;
 369  
 370      // convert numeric entities back to UTF-8 if needed
 371      if(!ajax_spell.utf8ok){
 372        data = data.replace(/&#(\d+);/g,
 373                            function(whole,match1) {
 374                              return String.fromCharCode(+match1);
 375                            });
 376        // now remove &amp; protection
 377        data = data.replace(/&amp;/g,'&');
 378      }
 379  
 380      // replace div with textbox again
 381      ajax_spell.textboxObj.value         = data;
 382      ajax_spell.textboxObj.disabled      = false;
 383      ajax_spell.showboxObj.style.display = 'none';
 384      ajax_spell.textboxObj.style.display = 'block';
 385      ajax_spell.editbarObj.style.visibility = 'visible';
 386      ajax_spell.showboxObj.innerHTML     = '';
 387      ajax_spell.setState('start');
 388    };
 389  
 390    /**
 391     * Calback for the timeout handling
 392     *
 393     * Will be called when the aspell backend didn't return
 394     */
 395    this.timedOut = function(){
 396      if(ajax_spell.timer !== null){
 397        window.clearTimeout(ajax_spell.timer);
 398        ajax_spell.timer = null;
 399  
 400        ajax_spell.textboxObj.disabled      = false;
 401        ajax_spell.showboxObj.style.display = 'none';
 402        ajax_spell.textboxObj.style.display = 'block';
 403        ajax_spell.editbarObj.style.visibility = 'visible';
 404        ajax_spell.showboxObj.innerHTML     = '';
 405        ajax_spell.setState('start');
 406  
 407        window.alert('Error: The spell checker did not respond');
 408    }
 409    };
 410  
 411    // --- Callers ---
 412  
 413    /**
 414     * Starts the spellchecking by sending an AJAX request
 415     *
 416     * @author Andreas Gohr <andi@splitbrain.org>
 417     */
 418    this.run = function(){
 419      ajax_spell.setState('run');
 420      ajax_spell.textboxObj.disabled = true;
 421      ajax_spell.editbarObj.style.visibility = 'hidden';
 422      var ajax = new sack(ajax_spell.handler);
 423      ajax.AjaxFailedAlert = '';
 424      ajax.encodeURIString = false;
 425      ajax.onCompletion    = this.start;
 426      ajax.runAJAX('call=check&utf8='+ajax_spell.utf8ok+
 427                   '&data='+encodeURIComponent(ajax_spell.textboxObj.value));
 428  
 429      // abort after 13 seconds
 430      this.timer = window.setTimeout(ajax_spell.timedOut,13000);
 431    };
 432  
 433    /**
 434     * Rewrites the HTML back to text again using an AJAX request
 435     *
 436     * @author Andreas Gohr <andi@splitbrain.org>
 437     */
 438    this.resume = function(){
 439      ajax_spell.setState('run');
 440      var text = ajax_spell.showboxObj.innerHTML;
 441      if(text !== ''){
 442        var ajax = new sack(ajax_spell.handler);
 443        ajax.AjaxFailedAlert = '';
 444        ajax.encodeURIString = false;
 445        ajax.onCompletion    = ajax_spell.stop;
 446        ajax.runAJAX('call=resume&utf8='+ajax_spell.utf8ok+
 447                     '&data='+encodeURIComponent(text));
 448      }
 449    };
 450  
 451  }
 452  
 453  // create the global object
 454  ajax_spell = new ajax_spell_class();
 455  
 456  //Setup VIM: ex: et ts=2 enc=utf-8 :


Généré le : Tue Apr 3 20:47:31 2007 par Balluche grâce à PHPXref 0.7