Changeset 1394


Ignore:
Timestamp:
02/10/18 06:36:44 (2 months ago)
Author:
gogo
Message:

Rewrite and standardise key events (see #1393), add onKeyDown, onKeyUp and also onShortCut

This commit rewrites much of the keyboard event handling, but it is (hopefully, in theory, as far as I can test) backwards compatible, in fact, it's so compatible it is used in the exact same way so far as plugins are concerned.

It adds events for plugins of onKeyDown, onKeyUp and also onShortCut

The existing onKeyPress is still fired - however with some caveat, namely the intention is that onKeyPress is only fired for the following classifications of key pressing...

"Adding Characters"

letters, numbers, space, punctuation, symbols, tab, enter

"Deleting Characters"

delete, backspace

"Shortcuts and Other Useful Things"

esc, ctrl-a, ctrl-b...


where previously under some browsers (WebKit?, IE) it would be fired for all keydown events, now it will only fire for "normally useful" events, and the event noise is reduced.

Also considerable work to make sure that the browsers are consistent, to ensure this some "keydown" events in some browsers also produce a "fake" keypress event, where in other browsers they would get a real keypress event (and we want them to).

getKey() hs been improved in Gecko and WebKit? and should be about the same for most uses (certainly all uses in the Xinha distribution), as it now uses the DOM3 keyboard event codes, special keys are now returned by name (where possible), eg tab is reported by getKey as "Tab", where previously, it would have been probably an actual tab character (but other special keys would have been pretty random incorrect characters).

Whew. This was a lot more work than I had anticipated. KeyboardEvent? across browsers is a mess.


Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/XinhaCore.js

    r1389 r1394  
    48324832    { 
    48334833      this.setHTML(txt); 
     4834       
    48344835    } 
    48354836    else 
     
    57885789  } 
    57895790   
    5790   if ( this.isKeyEvent(ev) ) 
    5791   { 
    5792     // Run the ordinary plugins first 
     5791 
     5792  var isShortCut = this.isShortCut(ev); 
     5793   
     5794  // Order of priority is something like... 
     5795  // Keydown Cancels 
     5796  //   KeyPress Cancels 
     5797  //      ShortCut Cancels  
     5798  //         (built in shortcuts) 
     5799  //         KeyUp 
     5800   
     5801  if(ev.type == 'keydown') 
     5802  { 
     5803    if(editor.firePluginEvent('onKeyDown', ev)) 
     5804    { 
     5805      return false; 
     5806    } 
     5807     
     5808    // If this is a shortcut, fire it as a keypress but when the key down 
     5809    //  happens, this is because some browsers (various versions and platform combinations even!)  
     5810    //  fire press and some do not, so we can only rely on keydown here 
     5811    //  we will suppress an actual shortcut press a bit further down to avoid duplicates 
     5812    if(isShortCut) 
     5813    { 
     5814      if(editor.firePluginEvent('onKeyPress', ev)) 
     5815      { 
     5816        return false; 
     5817      } 
     5818       
     5819      // Also we have a special onShortCut which only fires for them 
     5820      if(editor.firePluginEvent('onShortCut', ev, isShortCut)) 
     5821      { 
     5822        return false; 
     5823      } 
     5824       
     5825      this._shortCuts(ev); 
     5826    } 
     5827  } 
     5828   
     5829  // Shortcuts were fired as a keydown masquerading as a keypress already 
     5830  // so don't fire them again on an actual keypress.  Additionally 
     5831  // browsers differ slightly in what they call a keypress, to be sure we  
     5832  // issue keyress on a standard set of things we pass off to isKeyPressEvent 
     5833  // to do some more indepth checking, it will a boolean, some keypress will 
     5834  // be invalid and skiped, some keydown will be repeated as a keypress because 
     5835  // that browser wouldn't normally issue a keypress.  Sigh. 
     5836  if(!isShortCut && this.isKeyPressEvent(ev)) 
     5837  { 
    57935838    if(editor.firePluginEvent('onKeyPress', ev)) 
    57945839    { 
    57955840      return false; 
    57965841    } 
    5797      
    5798     // Handle the core shortcuts 
    5799     if ( this.isShortCut( ev ) ) 
    5800     { 
    5801       this._shortCuts(ev); 
     5842  } 
     5843   
     5844  // At last, something we can rely on! 
     5845  if(ev.type == 'keyup') 
     5846  { 
     5847    if(editor.firePluginEvent('onKeyUp', ev)) 
     5848    { 
     5849      return false; 
    58025850    } 
    58035851  } 
     
    86348682Xinha.prototype.createRange           = function(sel) { Xinha.notImplemented("createRange"); }; 
    86358683 
    8636 /** Determine if the given event object is a keydown/press event. 
     8684/** Different browsers have subtle differences in what they call a "keypress", we try and 
     8685 *  standardise them here.  For example, Firefox calls Tab a keypress (with keyCode 9) 
     8686 *  while WebKit does not record a keypress for the Tab key. 
     8687 *  
     8688 *  Webkit does record a keydown for tab, but typically not a keyup as it's caused a  
     8689 *  defocus by then, and there is no keypress. 
     8690 *   
     8691 *  For the sake of Xinha, we will define keyPress something like... 
     8692 *  
     8693 *   "Adding Characters" 
     8694 *      letters, numbers, space, punctuation, symbols, tab, enter 
     8695 *  
     8696 *   "Deleting Characters" 
     8697 *      delete, backspace 
     8698 *  
     8699 *   "Shortcuts and Other Useful Things" 
     8700 *      esc, ctrl-a, ctrl-b... 
     8701 *  
     8702 * Note that in the interests of performance, we are not too strict about removing things 
     8703 *   that should not be keypresses if they don't happen frequently, like for example, 
     8704 *   Function Keys **might** get passed as onKeyPress, depending on browser, since it's 
     8705 *   rare and plugins probably won't be looking for them anyway, there's no sense 
     8706 *   wasting cycles looking for them. 
     8707 *  
     8708 * If you are looking for something that is not "officially" a keypress as defined above 
     8709 *   use onKeyDown and you will get notifications for EVERY key down, even if it's for 
     8710 *   example a modifier like shift (eg ctrl-shift-a would give three keydowns), which is  
     8711 *   why keypress is a better idea if you can do that. 
     8712 *  
     8713 * Note also that you can listen to onShortCut to only hear about those if you want,  
     8714 *   it gets a second argument of the shortcut key already decoded for you. 
     8715 *  
     8716 * A useful key Tester is here: 
     8717 *    https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html 
     8718 *  
     8719 * A useful reference of DOM3 key names is here: 
     8720 *    https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values 
     8721 *  
     8722 * @param KeyboardEvent 
     8723 * @return boolean 
     8724 */ 
     8725 
     8726Xinha.prototype.isKeyPressEvent = function(keyEvent) 
     8727{ 
     8728  if(typeof Xinha.DOM3NotAKeyPress == 'undefined') 
     8729  { 
     8730    // The following regular expressions match KeyboardEvent.key for keys which should NOT be  
     8731    //  regarded as a keypress 
     8732    // 
     8733    // Note that we don't actually test them all, currently only modifier, navigation and editing 
     8734    // are actually tested and excluded, the others wont' happen frequently enough to bother 
     8735    // with testing.  It's not typically a big deal if keys slip-through the net and issue  
     8736    // a keypress as plugins will likely just skip it as an unknown key. 
     8737    // 
     8738    // See:   https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values 
     8739     
     8740    Xinha.DOM3NotAKeyPress = { 
     8741      'modifier'    : /^(Alt|CapsLock|Control|F[0-9]+|FnLock|Hyper|Meta|NumLock|ScrollLock|Shift|Super|Symbol|OS|Scroll)/, 
     8742      'navigation'  : /^(Arrow|Page|End|Home|Left|Right|Up|Down)/, 
     8743      'editing'     : /^(Insert)/, 
     8744      'ui'          : /^(Accept|Again|Attn|Cancel|ContextMenu|Execute|Find|Finish|Help|Pause|Play|Props|Select|Zoom|Pause|Apps)/, 
     8745      'device'      : /^(Brightness|Eject|LoghOff|Power|Print|Hibernate|Standby|WakeUp)/, 
     8746      'ime'         : /^(AllCandidates|Alphanumeric|CodeInput|Compose|Convert|Dead|FinalMode|Group|ModeChange|NextCandidate|NonConvert|PreviousCandidate|Process|SingleCandidate|Multi|Nonconvert|AltGraph)/, 
     8747      'korean'      : /^(Hangul|Hanja|Junja)/, 
     8748      'japanese'    : /^(Eisu|Hanakaku|Hirigana|Kana|Kanji|Katakana|Romanji|Zenkaku|RomanCharacters|HalfWidth|FullWidth)/, 
     8749      'function'    : /^(F[0-9]+|Soft[0-9]+)/, 
     8750      'phone'       : /^(AppSwitch|Call|Camera|EndCall|GoBack|GoHome|HeadsetHook|LastNumber|Notification|Manner|Voice|Exit|MozHomeScreen)/, 
     8751      'multimedia'  : /^(Channel|Media|FastFwd)/, 
     8752      'audio'       : /^(Audio|Microphone|Volume)/, 
     8753      'tv'          : /^(TV|Live)/, 
     8754      'media'       : /^(AVR|Color|ClosedCaption|Dummer|DisplaySwap|DVR|Exit|Favorite|Guide|Info|InstantReplay|Link|List|Live|Lock|Media|Navigate|Next|OnDemand|Pairing|PinP|Play|Random|RcLow|Record|RfBypass|ScanChannels|ScreenMode|Settings|SplitScreen|STBInput|Subtitle|Teletext|VideoMode|Wink|ZoomToggle|Zoom)/, 
     8755      'speech'      : /^(Speech)/, 
     8756      'document'    : /^(Close|New|Open|Print|Save|Spellcheck|Mail)/, 
     8757      'application' : /^(Launch|MediaSelect|SelectMedia)/ 
     8758    }; 
     8759  } 
     8760 
     8761  if(keyEvent.type == 'keypress') 
     8762  { 
     8763    // Detect some things that might come in as a press and should not be a press 
     8764     
     8765    //  DOM3 Keys 
     8766     
     8767    if(typeof keyEvent.key != 'undefined') 
     8768    { 
     8769      if(keyEvent.key == 'Unidentified') 
     8770      { 
     8771        // Some old Gecko versions called Shift-tab Unidentified ! 
     8772        if(typeof keyEvent.keyCode != 'undefined' && keyEvent.keyCode == 9) return true; 
     8773        return false; 
     8774      } 
     8775 
     8776      // Modifier keys 
     8777      if(Xinha.DOM3NotAKeyPress.modifier.test(keyEvent.key))   return false; 
     8778          
     8779      // Navigation Keys 
     8780      if(Xinha.DOM3NotAKeyPress.navigation.test(keyEvent.key)) return false; 
     8781                 
     8782      // Editing Keys 
     8783      if(Xinha.DOM3NotAKeyPress.editing.test(keyEvent.key))    return false; 
     8784            
     8785    } 
     8786    // Old DOM3 (only Safari and old Chrome) 
     8787    /* I could not find anything reported as a press that should not be in Safari 9.1 and that  
     8788     * is as far back as I can easily test, my thought is that dropping straight through to the  
     8789     * legacy keys should work fine so I have disabled this 
     8790     */  
     8791    else if( 0 && typeof keyEvent.keyIdentifier != 'undefined' && keyEvent.keyIdentifier.length) 
     8792    { 
     8793      var kI = parseInt(keyEvent.keyIdentifier.replace(/^U\+/,''),16); 
     8794       
     8795    } 
     8796    // Legacy Keys 
     8797    else  
     8798    { 
     8799      if(keyEvent.charCode == 0) 
     8800      { 
     8801        if((keyEvent.keyCode >= 37 && keyEvent.keyCode <= 40)) return false; // Arrows 
     8802            
     8803        if(   keyEvent.keyCode == 45 // Insert 
     8804          ||  keyEvent.keyCode == 36 // Home 
     8805          ||  keyEvent.keyCode == 35 // End 
     8806          ||  keyEvent.keyCode == 33 // Page Up 
     8807          ||  keyEvent.keyCode == 34 // Page Dn 
     8808          ||  keyEvent.keyCode == 19 // Pause/Break 
     8809          ||  keyEvent.keyCode == 17 // Control 
     8810          ||  keyEvent.keyCode == 18 // Alt 
     8811          ||  keyEvent.keyCode == 20 // CapsLock 
     8812          ||  keyEvent.keyCode == 91 // OS 
     8813          ||  keyEvent.keyCode == 93 // ContextMenu           
     8814        ) return false; 
     8815         
     8816        if( keyEvent.keyCode >= 112 && keyEvent <= 123 ) return false; // F1 through F12 
     8817        if( keyEvent.keyCode == 0) return false; // Other things (like "LaunchApp1") 
     8818      } 
     8819    } 
     8820    
     8821    // If it wasn't a bad thing we skiped, then a keypress is a keypress 
     8822    return true; 
     8823  } 
     8824  else if(keyEvent.type == 'keydown') 
     8825  { 
     8826    // Now we get into browser specifics, we want to return true  
     8827    //  if the keydown event is for a key which should be reported as a press 
     8828    //  and is NOT reported as  a press (otherwise press would fire twice for it) 
     8829    return this.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent(keyEvent); 
     8830  } 
     8831}; 
     8832 
     8833/** Due to browser differences, some keys which Xinha prefers to call a keyPress 
     8834 *   do not get an actual keypress event.  This browser specific function  
     8835 *   overridden in the browser's engine (eg modules/WebKit/WebKit.js) as required 
     8836 *   takes a keydown event type and tells us if we should treat it as a  
     8837 *   keypress event type. 
    86378838 * 
    8638  *  @param {Event} event  
    8639  *  @returns {Boolean} 
    8640  */ 
    8641   
    8642 Xinha.prototype.isKeyEvent            = function(event) { Xinha.notImplemented("isKeyEvent"); }; 
     8839 *  To be clear, the keys we are interested here are 
     8840 *        Escape, Tab, Backspace, Delete, Enter 
     8841 *   these are "non printable" characters which we still want to regard generally 
     8842 *   as a keypress.   
     8843 *  
     8844 *  If the browser does not report these as a keypress 
     8845 *   ( https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html ) 
     8846 *   then this function must return true for such keydown events as it is 
     8847 *   given. 
     8848 *  
     8849 * @param KeyboardEvent 
     8850 * @return boolean 
     8851 */ 
     8852 
     8853Xinha.prototype.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent = function(keyEvent) 
     8854{ 
     8855  return false; 
     8856}; 
    86438857 
    86448858/** Determines if the given key event object represents a combination of CTRL-<key>, 
     
    86468860 * 
    86478861 *  @param    {Event} keyEvent 
    8648  *  @returns  {Boolean} 
     8862 *  @returns  {mixed} Either the key representing the short cut (eg ctrl-b gives 'b'), or false 
    86498863 */ 
    86508864  
    86518865Xinha.prototype.isShortCut = function(keyEvent) 
    86528866{ 
    8653   if(keyEvent.ctrlKey && !keyEvent.altKey) 
    8654   { 
    8655     return true; 
     8867  if(keyEvent.ctrlKey && !keyEvent.altKey && this.getKey(keyEvent).length == 1) 
     8868  { 
     8869    return this.getKey(keyEvent); 
    86568870  } 
    86578871   
  • trunk/modules/Gecko/Gecko.js

    r1378 r1394  
    5050/** Allow Gecko to handle some key events in a special way. 
    5151 */ 
    52    
    5352Gecko.prototype.onKeyPress = function(ev) 
    5453{ 
    5554  var editor = this.editor; 
    5655  var s = editor.getSelection(); 
    57    
    5856  // Handle shortcuts 
    5957  if(editor.isShortCut(ev)) 
     
    133131        return a; 
    134132      }; 
    135    
     133 
    136134      if ( editor.config.convertUrlsToLinks && s && s.isCollapsed && s.anchorNode.nodeType == 3 && s.anchorNode.data.length > 3 && s.anchorNode.data.indexOf('.') >= 0 ) 
    137135      { 
     
    157155 
    158156          autoWrap(midTextEmail, 'a').href = 'mailto:' + mEmail[0]; 
    159           break; 
     157          return true; 
    160158        } 
    161159 
     
    177175          var midTextUrl   = leftTextUrl.splitText(midStart); 
    178176          autoWrap(midTextUrl, 'a').href = (mUrl[1] ? mUrl[1] : 'http://') + mUrl[2]; 
    179           break; 
     177          return true; 
    180178        } 
    181179      } 
     
    734732}; 
    735733 
    736 /** Determine if the given event object is a keydown/press event. 
     734/** Due to browser differences, some keys which Xinha prefers to call a keyPress 
     735 *   do not get an actual keypress event.  This browser specific function  
     736 *   overridden in the browser's engine (eg modules/WebKit/WebKit.js) as required 
     737 *   takes a keydown event type and tells us if we should treat it as a  
     738 *   keypress event type. 
    737739 * 
    738  *  @param event Event  
    739  *  @returns true|false 
    740  */ 
    741   
    742 Xinha.prototype.isKeyEvent = function(event) 
    743 { 
    744   return event.type == "keypress"; 
    745 } 
     740 *  To be clear, the keys we are interested here are 
     741 *        Escape, Tab, Backspace, Delete, Enter 
     742 *   these are "non printable" characters which we still want to regard generally 
     743 *   as a keypress.   
     744 *  
     745 *  If the browser does not report these as a keypress 
     746 *   ( https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html ) 
     747 *   then this function must return true for such keydown events as it is 
     748 *   given. 
     749 *  
     750 * @param KeyboardEvent with keyEvent.type == keydown 
     751 * @return boolean 
     752 */ 
     753 
     754Xinha.prototype.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent = function(keyEvent) 
     755{ 
     756  // Dom 3 
     757  if(typeof keyEvent.key != 'undefined') 
     758  { 
     759    // Found using IE11 (which uses Gecko) 
     760    //   this seems to be a reasonable way to distinguish 
     761    //   between IE11 and other Gecko browsers which do  
     762    //   not provide the "Old DOM3" .char property 
     763    if(typeof keyEvent.char != 'undefined') 
     764    { 
     765      if(typeof Xinha.DOM3_IE11_KeyDownKeyPress_RE == 'undefined') 
     766      { 
     767        // I don't know if pre-defining this is really faster in the modern world of 
     768        //  Javascript JIT compiling, but it does no harm 
     769        Xinha.DOM3_IE11_KeyDownKeyPress_RE = /^(Tab|Backspace|Del)/; 
     770      } 
     771       
     772      if(Xinha.DOM3_IE11_KeyDownKeyPress_RE.test(keyEvent.key)) 
     773      { 
     774        return true; 
     775      } 
     776    } 
     777     
     778    // Firefox reports everything we need as a keypress 
     779    // correctly (in terms of Xinha) 
     780  } 
     781  // Legacy 
     782  else 
     783  { 
     784    // Even very old firefox reports everything we need as a keypress 
     785    // correctly (in terms of Xinha) 
     786  } 
     787}; 
    746788 
    747789/** Return the character (as a string) of a keyEvent  - ie, press the 'a' key and 
     
    751793 *  @returns string 
    752794 */ 
    753                                     
     795 
    754796Xinha.prototype.getKey = function(keyEvent) 
    755 { 
    756   return String.fromCharCode(keyEvent.charCode); 
     797{  
     798  // DOM3 Key is easy (ish) 
     799  if(typeof keyEvent.key != 'undefined' && keyEvent.key.length > 0) 
     800  { 
     801    switch(keyEvent.key) 
     802    { 
     803      case 'Unidentified': 
     804        // Some old Gecko version reports Shift-Tab as Unidentified 
     805        if(typeof keyEvent.keyCode != 'undefined' && keyEvent.keyCode == 9) return 'Tab'; 
     806         
     807        // Otherwise not know 
     808        return ''; 
     809         
     810      case 'Spacebar': // FF<37 
     811        return ' ';  
     812    } 
     813     
     814    return keyEvent.key; 
     815  } 
     816  // If charCode is specified, that's what we want 
     817  else if(keyEvent.charCode) 
     818  { 
     819    return String.fromCharCode(keyEvent.charCode); 
     820  } 
     821  // Safari does not set charCode if CTRL is pressed 
     822  //  but does set keyCode to the key, it also sets keyCode 
     823  //  for the actual pressing of ctrl, skip that 
     824  //  the keyCode in Safari si the uppercase character's code  
     825  //  for that key, so if shift is not pressed, lowercase it 
     826  else if(keyEvent.ctrlKey && keyEvent.keyCode != 17) 
     827  { 
     828    if(keyEvent.shiftKey) 
     829    { 
     830      return String.fromCharCode(keyEvent.keyCode); 
     831    } 
     832    else 
     833    { 
     834      return String.fromCharCode(keyEvent.keyCode).toLowerCase(); 
     835    } 
     836  } 
     837   
     838  // Ok, give up, no idea! 
     839  return ''; 
    757840} 
    758841 
  • trunk/modules/InternetExplorer/InternetExplorer.js

    r1312 r1394  
    11 
    22  /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- 
     3    -- 
     4    --  NOTICE Modern IE does not use this engine any more 
     5    -- 
     6    --          IE 11 identifies as Gecko 
     7    --          Edge  identifies as WebKit 
     8    -- 
     9    --  The last IE version to use this engine is probably IE10, people should 
     10    --   not use such an old version of IE and should upgrade or use a WebKit 
     11    --   or Gecko based browser. 
     12    -- 
     13    --  This engine is no longer officially supported or tested. 
     14    -- 
     15    ----------------------------------------------------------------------------- 
     16    -- 
    317    --  Xinha (is not htmlArea) - http://xinha.gogo.co.nz/ 
    418    -- 
     
    5064/** Allow Internet Explorer to handle some key events in a special way. 
    5165 */ 
    52    
    5366InternetExplorer.prototype.onKeyPress = function(ev) 
    5467{ 
     68  var editor = this.editor; 
     69   
    5570  // Shortcuts 
    5671  if(this.editor.isShortCut(ev)) 
     
    94109    break; 
    95110     
    96     case 9: // KEY tab, see ticket #1121 
    97     { 
     111    case 9: // KEY tab 
     112    { 
     113      // Note that the ListOperations plugin will handle tabs in list items and indent/outdent those 
     114      // at some point TableOperations might do also 
     115      // so this only has to handle a tab/untab in text 
     116      if(editor.config.tabSpanClass) 
     117      { 
     118        if(!ev.shiftKey) 
     119        { 
     120          editor.insertHTML('<span class="'+editor.config.tabSpanClass+'">'+editor.config.tabSpanContents+'</span>'); 
     121          var s = editor.getSelection(); 
     122          var r = editor.createRange(s);                    
     123          r.collapse(true); 
     124          r.select(); 
     125        } 
     126        else 
     127        { 
     128          // Shift tab is not trivial to fix in old IE 
     129          // and I don't care enough about it to try hard 
     130        } 
     131      } 
     132       
    98133      Xinha._stopEvent(ev); 
    99134      return true; 
    100135    } 
     136    break; 
    101137 
    102138  } 
     
    825861}; 
    826862 
    827 /** Determine if the given event object is a keydown/press event. 
     863/** Due to browser differences, some keys which Xinha prefers to call a keyPress 
     864 *   do not get an actual keypress event.  This browser specific function  
     865 *   overridden in the browser's engine (eg modules/WebKit/WebKit.js) as required 
     866 *   takes a keydown event type and tells us if we should treat it as a  
     867 *   keypress event type. 
    828868 * 
    829  *  @param event Event  
    830  *  @returns true|false 
    831  */ 
    832   
    833 Xinha.prototype.isKeyEvent = function(event) 
    834 { 
    835   return event.type == "keydown"; 
    836 } 
     869 *  To be clear, the keys we are interested here are 
     870 *        Escape, Tab, Backspace, Delete, Enter 
     871 *   these are "non printable" characters which we still want to regard generally 
     872 *   as a keypress.   
     873 *  
     874 *  If the browser does not report these as a keypress 
     875 *   ( https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html ) 
     876 *   then this function must return true for such keydown events as it is 
     877 *   given. 
     878 *  
     879 * @param KeyboardEvent with keyEvent.type == keydown 
     880 * @return boolean 
     881 */ 
     882 
     883Xinha.prototype.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent = function(keyEvent) 
     884{ 
     885  // Dom 3 
     886  if(typeof keyEvent.key != 'undefined') 
     887  { 
     888    // Found using IE11 in 9-10 modes 
     889    if(keyEvent.key.match(/^(Tab|Backspace|Del)/)) 
     890    { 
     891      return true; 
     892    } 
     893  } 
     894  // Legacy 
     895  else 
     896  { 
     897    // Found using IE11 in 5-8 modes 
     898    if(keyEvent.keyCode == 9   // Tab 
     899    || keyEvent.keyCode == 8   // Backspace 
     900    || keyEvent.keyCode == 46  // Del 
     901    ) return true; 
     902  } 
     903}; 
    837904 
    838905/** Return the character (as a string) of a keyEvent  - ie, press the 'a' key and 
  • trunk/modules/Opera/Opera.js

    r1312 r1394  
    11 
    22  /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- 
     3    -- 
     4    -- 
     5    --  NOTICE Modern Opera does not use this engine any more, it identifies as 
     6    --           and uses WebKit (Opera is these days based on Blink). 
     7    -- 
     8    --   People using older versions of Opera that need this engine should 
     9    --   upgrade to a WebKit or Gecko based browser. 
     10    -- 
     11    --  This engine is no longer officially supported or tested. 
     12    -- 
     13    ----------------------------------------------------------------------------- 
    314    --  Xinha (is not htmlArea) - http://xinha.gogo.co.nz/ 
    415    -- 
     
    5061/** Allow Opera to handle some key events in a special way. 
    5162 */ 
    52    
    5363Opera.prototype.onKeyPress = function(ev) 
    5464{ 
     
    693703}; 
    694704 
    695 /** Determine if the given event object is a keydown/press event. 
     705/**  
     706 * @NOTE I don't have a way to test this any more (don't have old opera version 
     707 *   and don't care enough to find one), I'm assuming it will probably be close 
     708 *   to Gecko so I have just copied it directly. 
     709 *  
     710 * Due to browser differences, some keys which Xinha prefers to call a keyPress 
     711 *   do not get an actual keypress event.  This browser specific function  
     712 *   overridden in the browser's engine (eg modules/WebKit/WebKit.js) as required 
     713 *   takes a keydown event type and tells us if we should treat it as a  
     714 *   keypress event type. 
    696715 * 
    697  *  @param event Event  
    698  *  @returns true|false 
    699  */ 
    700   
    701 Xinha.prototype.isKeyEvent = function(event) 
    702 { 
    703   return event.type == "keypress"; 
    704 } 
     716 *  To be clear, the keys we are interested here are 
     717 *        Escape, Tab, Backspace, Delete, Enter 
     718 *   these are "non printable" characters which we still want to regard generally 
     719 *   as a keypress.   
     720 *  
     721 *  If the browser does not report these as a keypress 
     722 *   ( https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html ) 
     723 *   then this function must return true for such keydown events as it is 
     724 *   given. 
     725 *  
     726 * @param KeyboardEvent with keyEvent.type == keydown 
     727 * @return boolean 
     728 */ 
     729 
     730Xinha.prototype.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent = function(keyEvent) 
     731{ 
     732  // Dom 3 
     733  if(typeof keyEvent.key != 'undefined') 
     734  { 
     735    // Found using IE11 (which uses Gecko) 
     736    //   this seems to be a reasonable way to distinguish 
     737    //   between IE11 and other Gecko browsers which do  
     738    //   not provide the "Old DOM3" .char property 
     739    if(typeof keyEvent.char != 'undefined') 
     740    { 
     741      if(keyEvent.key.match(/^(Tab|Backspace|Del)/)) 
     742      { 
     743        return true; 
     744      } 
     745    } 
     746     
     747    // Firefox reports everything we need as a keypress 
     748    // correctly (in terms of Xinha) 
     749  } 
     750  // Legacy 
     751  else 
     752  { 
     753    // Even very old firefox reports everything we need as a keypress 
     754    // correctly (in terms of Xinha) 
     755  } 
     756}; 
    705757 
    706758/** Return the character (as a string) of a keyEvent  - ie, press the 'a' key and 
  • trunk/modules/WebKit/WebKit.js

    r1378 r1394  
    5757  // Handle shortcuts 
    5858  if(editor.isShortCut(ev)) 
    59   { 
     59  {     
    6060    switch(editor.getKey(ev).toLowerCase()) 
    6161    { 
     
    115115        }; 
    116116        editor._unlinkOnUndo = true; 
    117      
    118117        return a; 
    119118      }; 
     
    142141 
    143142          autoWrap(midTextEmail, 'a').href = 'mailto:' + mEmail[0]; 
    144           break; 
     143          return true; 
    145144        } 
    146145 
     
    162161          var midTextUrl   = leftTextUrl.splitText(midStart); 
    163162          autoWrap(midTextUrl, 'a').href = (mUrl[1] ? mUrl[1] : 'http://') + mUrl[2]; 
    164           break; 
     163          return true; 
    165164        } 
    166165      } 
     
    718717}; 
    719718 
    720 /** Determine if the given event object is a keydown/press event. 
     719 
     720/** Due to browser differences, some keys which Xinha prefers to call a keyPress 
     721 *   do not get an actual keypress event.  This browser specific function  
     722 *   overridden in the browser's engine (eg modules/WebKit/WebKit.js) as required 
     723 *   takes a keydown event type and tells us if we should treat it as a  
     724 *   keypress event type. 
    721725 * 
    722  *  @param event Event  
    723  *  @returns true|false 
    724  */ 
    725   
    726 Xinha.prototype.isKeyEvent = function(event) 
    727 { 
    728   return event.type == "keydown"; 
    729 } 
     726 *  To be clear, the keys we are interested here are 
     727 *        Escape, Tab, Backspace, Delete, Enter 
     728 *   these are "non printable" characters which we still want to regard generally 
     729 *   as a keypress.   
     730 *  
     731 *  If the browser does not report these as a keypress 
     732 *   ( https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html ) 
     733 *   then this function must return true for such keydown events as it is 
     734 *   given. 
     735 *  
     736 * @param KeyboardEvent with keyEvent.type == keydown 
     737 * @return boolean 
     738 */ 
     739 
     740Xinha.prototype.isKeyDownThatShouldGetButDoesNotGetAKeyPressEvent = function(keyEvent) 
     741{ 
     742  // Dom 3 
     743  if(typeof keyEvent.key != 'undefined') 
     744  { 
     745    if(typeof Xinha.DOM3_WebKit_KeyDownKeyPress_RE == 'undefined') 
     746    { 
     747      // I don't know if pre-defining this is really faster in the modern world of 
     748      //  Javascript JIT compiling, but it does no harm 
     749      Xinha.DOM3_WebKit_KeyDownKeyPress_RE = /^(Escape|Esc|Tab|Backspace|Delete|Del)/; 
     750    } 
     751     
     752    // Found using Chrome 65 and Opera 50, Edge 
     753    //  Note that Edge calls Escape Esc, and Delete Del 
     754    if(Xinha.DOM3_WebKit_KeyDownKeyPress_RE.test(keyEvent.key)) 
     755    { 
     756      return true; 
     757    } 
     758  } 
     759  // Old Safari and Chrome 
     760  else if(typeof keyEvent.keyIdentifier != 'undefined' && keyEvent.keyIdentifier.length) 
     761  { 
     762    var kI = parseInt(keyEvent.keyIdentifier.replace(/^U\+/,''),16); 
     763    // Found using Safari 9.1.1 - safari seems to pass ESC ok as a keyPress 
     764    if(kI == 9 /* Tab */ || kI == 8 /* Backspace */ || kI == 127 /* Delete */ ) return true; 
     765  } 
     766  // Legacy 
     767  else 
     768  { 
     769    // Also Chrome 65, I'm assuming perhaps dangerously, that it's about the same as  
     770    // older pre-KeyboardEvent.key but that's been around a few years now so 
     771    // people will mostly be on supporting browsers anyway so this probably 
     772    // won't be hit by that many people 
     773    if(keyEvent.charCode == 0) 
     774    { 
     775      if( keyEvent.keyCode == 27  // ESC 
     776       || keyEvent.keyCode == 9   // Tab 
     777       || keyEvent.keyCode == 8   // Backspace 
     778       || keyEvent.keyCode == 46  // Del 
     779      ) return true; 
     780    } 
     781  } 
     782}; 
    730783 
    731784/** Return the character (as a string) of a keyEvent  - ie, press the 'a' key and 
     
    738791Xinha.prototype.getKey = function(keyEvent) 
    739792{  
    740  // with ctrl pressed Safari does not give the charCode, unfortunately this (shortcuts) is about the only thing this function is for 
    741   if(typeof keyEvent.keyIdentifier == 'undefined') 
    742   { 
    743     if(typeof keyEvent.key != 'undefined') 
    744     { 
    745       return keyEvent.key; 
    746     } 
    747   } 
    748    
    749   var key = String.fromCharCode(parseInt(keyEvent.keyIdentifier.replace(/^U\+/,''),16)); 
    750   if (keyEvent.shiftKey) return key; 
    751   else return key.toLowerCase(); 
     793  // DOM3 Key is easy (ish) 
     794  if(typeof keyEvent.key != 'undefined' && keyEvent.key.length > 0) 
     795  { 
     796    return keyEvent.key; 
     797  } 
     798  // Old DOM3 used by (Old?) Safari SOMETIMES (but not ALWAYS!) and old Chrome 
     799  else if(typeof keyEvent.keyIdentifier != 'undefined' && keyEvent.keyIdentifier.length > 0 && keyEvent.keyIdentifier.match(/^U\+/)) 
     800  { 
     801      var key = String.fromCharCode(parseInt(keyEvent.keyIdentifier.replace(/^U\+/,''),16)); 
     802      if (keyEvent.shiftKey) return key; 
     803      else return key.toLowerCase(); 
     804  } 
     805  // If charCode is specified, that's what we want 
     806  else if(keyEvent.charCode) 
     807  { 
     808    return String.fromCharCode(keyEvent.charCode); 
     809  } 
     810  // Safari does not set charCode if CTRL is pressed 
     811  //  but does set keyCode to the key, it also sets keyCode 
     812  //  for the actual pressing of ctrl, skip that 
     813  //  the keyCode in Safari si the uppercase character's code  
     814  //  for that key, so if shift is not pressed, lowercase it 
     815  else if(keyEvent.ctrlKey && keyEvent.keyCode != 17) 
     816  { 
     817    if(keyEvent.shiftKey) 
     818    { 
     819      return String.fromCharCode(keyEvent.keyCode); 
     820    } 
     821    else 
     822    { 
     823      return String.fromCharCode(keyEvent.keyCode).toLowerCase(); 
     824    } 
     825  } 
     826   
     827  // Ok, give up, no idea! 
     828  return ''; 
    752829} 
    753830 
  • trunk/plugins/Equation/ASCIIMathML.js

    r1342 r1394  
    23892389  src = src.replace(/height\s*=\s*\d+/,"height="+(factor*(pic.getAttribute("height")-0))); 
    23902390  document.getElementById(name+"input").value = src; 
    2391 //alert(getKey(evt.keycode)) 
    23922391  updatePicture(name); 
    23932392} 
  • trunk/plugins/GenericPlugin/GenericPlugin.js

    r1067 r1394  
    4646} 
    4747 
     48GenericPlugin.prototype.onKeyDown = function ( event ) 
     49{ 
     50  return false; 
     51} 
     52 
    4853GenericPlugin.prototype.onKeyPress = function ( event ) 
    4954{ 
    5055        return false; 
     56} 
     57 
     58GenericPlugin.prototype.onOnShortCut = function ( event , shortCut ) 
     59{ 
     60  // Where shortCut is a single character, eg if you press ctrl-a, then 
     61  //  shortCut == 'a' 
     62  return false; 
     63} 
     64 
     65GenericPlugin.prototype.onKeyUp = function ( event ) 
     66{ 
     67  return false; 
    5168} 
    5269 
  • trunk/plugins/InsertNote/InsertNote.js

    r1086 r1394  
    568568  // This seems a bit hacky, but I don't presently see 
    569569  // a better way. 
     570  //@NOTE: 8 = Backspace, 46 = Delete; this undocumented 
     571  //  function apears to be for handling delete note references 
     572  //  to have the note automatically deleted also 
    570573  if (event.keyCode == 8 || event.keyCode == 46) 
    571574  { 
  • trunk/plugins/ListOperations/ListOperations.js

    r1377 r1394  
    7777  } 
    7878 
    79   ev.preventDefault(); 
     79  Xinha._stopEvent(ev); 
    8080 
    8181  if( ev.shiftKey ) { 
  • trunk/plugins/TableOperations/TableOperations.js

    r1392 r1394  
    717717        Styler.applyStyleIfMatch(params, /border($|Color|Width|Style)/); 
    718718      } 
     719       
     720      // It is also friendly to remove table borders as it tends to override 
     721      // and this could be confusing when styling borders (user thinks it didn't work) 
     722      Xinha._removeClass(table, 'htmtableborders'); 
    719723    } 
    720724     
     
    883887  } 
    884888 
    885   ev.preventDefault(); 
     889  Xinha._stopEvent(ev); 
    886890     
    887891  // find the next cell, get all the cells (td/th) which are in this table 
Note: See TracChangeset for help on using the changeset viewer.