InplaceEditor.js 4.5 KB

1234567891011121314151617181920212223242526272829303132
  1. export default class InplaceEditor{static startEditing(element,config){if(!InplaceEditor._defaultInstance){InplaceEditor._defaultInstance=new InplaceEditor();}
  2. return InplaceEditor._defaultInstance.startEditing(element,config);}
  3. editorContent(editingContext){const element=editingContext.element;if(element.tagName==='INPUT'&&element.type==='text'){return element.value;}
  4. return element.textContent;}
  5. setUpEditor(editingContext){const element=editingContext.element;element.classList.add('editing');element.setAttribute('contenteditable','plaintext-only');const oldRole=element.getAttribute('role');UI.ARIAUtils.markAsTextBox(element);editingContext.oldRole=oldRole;const oldTabIndex=element.getAttribute('tabIndex');if(typeof oldTabIndex!=='number'||oldTabIndex<0){element.tabIndex=0;}
  6. this._focusRestorer=new UI.ElementFocusRestorer(element);editingContext.oldTabIndex=oldTabIndex;}
  7. closeEditor(editingContext){const element=editingContext.element;element.classList.remove('editing');element.removeAttribute('contenteditable');if(typeof editingContext.oldRole!=='string'){element.removeAttribute('role');}else{element.role=editingContext.oldRole;}
  8. if(typeof editingContext.oldTabIndex!=='number'){element.removeAttribute('tabIndex');}else{element.tabIndex=editingContext.oldTabIndex;}
  9. element.scrollTop=0;element.scrollLeft=0;}
  10. cancelEditing(editingContext){const element=editingContext.element;if(element.tagName==='INPUT'&&element.type==='text'){element.value=editingContext.oldText;}else{element.textContent=editingContext.oldText;}}
  11. augmentEditingHandle(editingContext,handle){}
  12. startEditing(element,config){if(!UI.markBeingEdited(element,true)){return null;}
  13. config=config||new InplaceEditor.Config(function(){},function(){});const editingContext={element:element,config:config};const committedCallback=config.commitHandler;const cancelledCallback=config.cancelHandler;const pasteCallback=config.pasteHandler;const context=config.context;let moveDirection='';const self=this;this.setUpEditor(editingContext);editingContext.oldText=this.editorContent(editingContext);function blurEventListener(e){if(config.blurHandler&&!config.blurHandler(element,e)){return;}
  14. editingCommitted.call(element);}
  15. function cleanUpAfterEditing(){UI.markBeingEdited(element,false);element.removeEventListener('blur',blurEventListener,false);element.removeEventListener('keydown',keyDownEventListener,true);if(pasteCallback){element.removeEventListener('paste',pasteEventListener,true);}
  16. if(self._focusRestorer){self._focusRestorer.restore();}
  17. self.closeEditor(editingContext);}
  18. function editingCancelled(){self.cancelEditing(editingContext);cleanUpAfterEditing();cancelledCallback(this,context);}
  19. function editingCommitted(){cleanUpAfterEditing();committedCallback(this,self.editorContent(editingContext),editingContext.oldText,context,moveDirection);}
  20. function defaultFinishHandler(event){if(isEnterKey(event)){return'commit';}else if(event.keyCode===UI.KeyboardShortcut.Keys.Esc.code||event.key==='Escape'){return'cancel';}else if(event.key==='Tab'){return'move-'+(event.shiftKey?'backward':'forward');}
  21. return'';}
  22. function handleEditingResult(result,event){if(result==='commit'){editingCommitted.call(element);event.consume(true);}else if(result==='cancel'){editingCancelled.call(element);event.consume(true);}else if(result&&result.startsWith('move-')){moveDirection=result.substring(5);if(event.key==='Tab'){event.consume(true);}
  23. blurEventListener();}}
  24. function pasteEventListener(event){const result=pasteCallback(event);handleEditingResult(result,event);}
  25. function keyDownEventListener(event){let result=defaultFinishHandler(event);if(!result&&config.postKeydownFinishHandler){result=config.postKeydownFinishHandler(event);}
  26. handleEditingResult(result,event);}
  27. element.addEventListener('blur',blurEventListener,false);element.addEventListener('keydown',keyDownEventListener,true);if(pasteCallback){element.addEventListener('paste',pasteEventListener,true);}
  28. const handle={cancel:editingCancelled.bind(element),commit:editingCommitted.bind(element)};this.augmentEditingHandle(editingContext,handle);return handle;}}
  29. export class Config{constructor(commitHandler,cancelHandler,context,blurHandler){this.commitHandler=commitHandler;this.cancelHandler=cancelHandler;this.context=context;this.blurHandler=blurHandler;this.pasteHandler;this.postKeydownFinishHandler;}
  30. setPasteHandler(pasteHandler){this.pasteHandler=pasteHandler;}
  31. setPostKeydownFinishHandler(postKeydownFinishHandler){this.postKeydownFinishHandler=postKeydownFinishHandler;}}
  32. self.UI=self.UI||{};UI=UI||{};UI.InplaceEditor=InplaceEditor;UI.InplaceEditor.Config=Config;UI.InplaceEditor.Controller;