UNPKG

@yuebai008/cli

Version:

Command line interface for rapid qg-minigame development

1 lines 14.2 kB
import*as Common from"../../core/common/common.js";import*as Platform from"../../core/platform/platform.js";import*as TextUtils from"../../models/text_utils/text_utils.js";import*as ARIAUtils from"./ARIAUtils.js";import*as ThemeSupport from"./theme_support/theme_support.js";import{SuggestBox}from"./SuggestBox.js";import{Tooltip}from"./Tooltip.js";import{ElementFocusRestorer}from"./UIUtils.js";import textPromptStyles from"./textPrompt.css.legacy.js";export class TextPrompt extends Common.ObjectWrapper.ObjectWrapper{proxyElement;proxyElementDisplay;autocompletionTimeout;titleInternal;queryRange;previousText;currentSuggestion;completionRequestId;ghostTextElement;leftParenthesesIndices;loadCompletions;completionStopCharacters;usesSuggestionBuilder;elementInternal;boundOnKeyDown;boundOnInput;boundOnMouseWheel;boundClearAutocomplete;contentElement;suggestBox;isEditing;focusRestorer;blurListener;oldTabIndex;completeTimeout;disableDefaultSuggestionForEmptyInputInternal;constructor(){super(),this.proxyElementDisplay="inline-block",this.autocompletionTimeout=DefaultAutocompletionTimeout,this.titleInternal="",this.queryRange=null,this.previousText="",this.currentSuggestion=null,this.completionRequestId=0,this.ghostTextElement=document.createElement("span"),this.ghostTextElement.classList.add("auto-complete-text"),this.ghostTextElement.setAttribute("contenteditable","false"),this.leftParenthesesIndices=[],ARIAUtils.markAsHidden(this.ghostTextElement)}initialize(t,e,s){this.loadCompletions=t,this.completionStopCharacters=e||" =:[({;,!+-*/&|^<>.",this.usesSuggestionBuilder=s||!1}setAutocompletionTimeout(t){this.autocompletionTimeout=t}renderAsBlock(){this.proxyElementDisplay="block"}attach(t){return this.attachInternal(t)}attachAndStartEditing(t,e){const s=this.attachInternal(t);return this.startEditing(e),s}attachInternal(t){if(this.proxyElement)throw"Cannot attach an attached TextPrompt";return this.elementInternal=t,this.boundOnKeyDown=this.onKeyDown.bind(this),this.boundOnInput=this.onInput.bind(this),this.boundOnMouseWheel=this.onMouseWheel.bind(this),this.boundClearAutocomplete=this.clearAutocomplete.bind(this),this.proxyElement=t.ownerDocument.createElement("span"),ThemeSupport.ThemeSupport.instance().appendStyle(this.proxyElement,textPromptStyles),this.contentElement=this.proxyElement.createChild("div","text-prompt-root"),this.proxyElement.style.display=this.proxyElementDisplay,t.parentElement&&t.parentElement.insertBefore(this.proxyElement,t),this.contentElement.appendChild(t),this.elementInternal.classList.add("text-prompt"),ARIAUtils.markAsTextBox(this.elementInternal),ARIAUtils.setAutocomplete(this.elementInternal,ARIAUtils.AutocompleteInteractionModel.both),ARIAUtils.setHasPopup(this.elementInternal,"listbox"),this.elementInternal.setAttribute("contenteditable","plaintext-only"),this.element().addEventListener("keydown",this.boundOnKeyDown,!1),this.elementInternal.addEventListener("input",this.boundOnInput,!1),this.elementInternal.addEventListener("wheel",this.boundOnMouseWheel,!1),this.elementInternal.addEventListener("selectstart",this.boundClearAutocomplete,!1),this.elementInternal.addEventListener("blur",this.boundClearAutocomplete,!1),this.suggestBox=new SuggestBox(this,20),this.titleInternal&&Tooltip.install(this.proxyElement,this.titleInternal),this.proxyElement}element(){if(!this.elementInternal)throw new Error("Expected an already attached element!");return this.elementInternal}detach(){this.removeFromElement(),this.focusRestorer&&this.focusRestorer.restore(),this.proxyElement&&this.proxyElement.parentElement&&(this.proxyElement.parentElement.insertBefore(this.element(),this.proxyElement),this.proxyElement.remove()),delete this.proxyElement,this.element().classList.remove("text-prompt"),this.element().removeAttribute("contenteditable"),this.element().removeAttribute("role"),ARIAUtils.clearAutocomplete(this.element()),ARIAUtils.setHasPopup(this.element(),"false")}textWithCurrentSuggestion(){const t=this.text();if(!this.queryRange||!this.currentSuggestion)return t;const e=this.currentSuggestion.text;return t.substring(0,this.queryRange.startColumn)+e+t.substring(this.queryRange.endColumn)}text(){let t=this.element().textContent||"";if(this.ghostTextElement.parentNode){const e=this.ghostTextElement.textContent||"";t=t.substring(0,t.length-e.length)}return t}setText(t){this.clearAutocomplete(),this.element().textContent=t,this.previousText=this.text(),this.element().hasFocus()&&(this.moveCaretToEndOfPrompt(),this.element().scrollIntoView())}setSelectedRange(t,e){if(t<0)throw new RangeError("Selected range start must be a nonnegative integer");const s=this.element().textContent,n=s?s.length:0;e>n&&(e=n),e<t&&(e=t);const i=this.element().childNodes[0],o=new Range;o.setStart(i,t),o.setEnd(i,e);const r=window.getSelection();r&&(r.removeAllRanges(),r.addRange(o))}focus(){this.element().focus()}title(){return this.titleInternal}setTitle(t){this.titleInternal=t,this.proxyElement&&Tooltip.install(this.proxyElement,t)}setPlaceholder(t,e){t?(this.element().setAttribute("data-placeholder",t),ARIAUtils.setPlaceholder(this.element(),e||t)):(this.element().removeAttribute("data-placeholder"),ARIAUtils.setPlaceholder(this.element(),null))}setEnabled(t){t?this.element().setAttribute("contenteditable","plaintext-only"):this.element().removeAttribute("contenteditable"),this.element().classList.toggle("disabled",!t)}removeFromElement(){this.clearAutocomplete(),this.element().removeEventListener("keydown",this.boundOnKeyDown,!1),this.element().removeEventListener("input",this.boundOnInput,!1),this.element().removeEventListener("selectstart",this.boundClearAutocomplete,!1),this.element().removeEventListener("blur",this.boundClearAutocomplete,!1),this.isEditing&&this.stopEditing(),this.suggestBox&&this.suggestBox.hide()}startEditing(t){this.isEditing=!0,this.contentElement&&this.contentElement.classList.add("text-prompt-editing"),this.focusRestorer=new ElementFocusRestorer(this.element()),t&&(this.blurListener=t,this.element().addEventListener("blur",this.blurListener,!1)),this.oldTabIndex=this.element().tabIndex,this.element().tabIndex<0&&(this.element().tabIndex=0),this.text()||this.autoCompleteSoon()}stopEditing(){this.element().tabIndex=this.oldTabIndex,this.blurListener&&this.element().removeEventListener("blur",this.blurListener,!1),this.contentElement&&this.contentElement.classList.remove("text-prompt-editing"),delete this.isEditing}onMouseWheel(t){}onKeyDown(t){let e=!1;const s=t;if(this.isSuggestBoxVisible()&&this.suggestBox&&this.suggestBox.keyPressed(s))s.consume(!0);else{switch(s.key){case"Tab":e=this.tabKeyPressed(s);break;case"ArrowLeft":case"ArrowUp":case"PageUp":case"Home":this.clearAutocomplete();break;case"PageDown":case"ArrowRight":case"ArrowDown":case"End":this.isCaretAtEndOfPrompt()?e=this.acceptAutoComplete():this.clearAutocomplete();break;case"Escape":this.isSuggestBoxVisible()&&(this.clearAutocomplete(),e=!0);break;case" ":!s.ctrlKey||s.metaKey||s.altKey||s.shiftKey||(this.autoCompleteSoon(!0),e=!0)}"Enter"===s.key&&s.preventDefault(),e&&s.consume(!0)}}acceptSuggestionOnStopCharacters(t){if(!(this.currentSuggestion&&this.queryRange&&1===t.length&&this.completionStopCharacters&&this.completionStopCharacters.includes(t)))return!1;const e=this.text().substring(this.queryRange.startColumn,this.queryRange.endColumn);return!(!e||!this.currentSuggestion.text.startsWith(e+t))&&(this.queryRange.endColumn+=1,this.acceptAutoComplete())}onInput(t){const e=t;let s=this.text();const n=e.data;"insertFromPaste"===e.inputType&&s.includes("\n")&&(s=Platform.StringUtilities.stripLineBreaks(s),this.setText(s));const i=this.getCaretPosition();if(")"===n&&i>=0&&this.leftParenthesesIndices.length>0){if(")"===s[i]&&this.tryMatchingLeftParenthesis(i))return s=s.substring(0,i)+s.substring(i+1),void this.setText(s)}if(n&&!this.acceptSuggestionOnStopCharacters(n)){const t=s.startsWith(this.previousText)||this.previousText.startsWith(s);this.queryRange&&t&&(this.queryRange.endColumn+=s.length-this.previousText.length)}this.refreshGhostText(),this.previousText=s,this.dispatchEventToListeners(Events.TextChanged),this.autoCompleteSoon()}acceptAutoComplete(){let t=!1;return this.isSuggestBoxVisible()&&this.suggestBox&&(t=this.suggestBox.acceptSuggestion()),t||(t=this.acceptSuggestionInternal()),this.usesSuggestionBuilder&&t&&this.autoCompleteSoon(),t}clearAutocomplete(){const t=this.textWithCurrentSuggestion();this.isSuggestBoxVisible()&&this.suggestBox&&this.suggestBox.hide(),this.clearAutocompleteTimeout(),this.queryRange=null,this.refreshGhostText(),t!==this.textWithCurrentSuggestion()&&this.dispatchEventToListeners(Events.TextChanged)}refreshGhostText(){this.currentSuggestion&&this.currentSuggestion.hideGhostText?this.ghostTextElement.remove():this.queryRange&&this.currentSuggestion&&this.isCaretAtEndOfPrompt()&&this.currentSuggestion.text.startsWith(this.text().substring(this.queryRange.startColumn))?(this.ghostTextElement.textContent=this.currentSuggestion.text.substring(this.queryRange.endColumn-this.queryRange.startColumn),this.element().appendChild(this.ghostTextElement)):this.ghostTextElement.remove()}clearAutocompleteTimeout(){this.completeTimeout&&(clearTimeout(this.completeTimeout),delete this.completeTimeout),this.completionRequestId++}autoCompleteSoon(t){const e=this.isSuggestBoxVisible()||t;this.completeTimeout||(this.completeTimeout=window.setTimeout(this.complete.bind(this,t),e?0:this.autocompletionTimeout))}async complete(t){this.clearAutocompleteTimeout();const e=this.element().getComponentSelection();if(!e||0===e.rangeCount)return;const s=e.getRangeAt(0);let n;if((t||this.isCaretAtEndOfPrompt()||this.isSuggestBoxVisible())&&e.isCollapsed||(n=!0),n)return void this.clearAutocomplete();const i=Platform.DOMUtilities.rangeOfWord(s.startContainer,s.startOffset,this.completionStopCharacters,this.element(),"backward"),o=i.cloneRange();o.collapse(!0),o.setStartBefore(this.element());const r=++this.completionRequestId,l=await this.loadCompletions.call(null,o.toString(),i.toString(),Boolean(t));this.completionsReady(r,e,i,Boolean(t),l)}disableDefaultSuggestionForEmptyInput(){this.disableDefaultSuggestionForEmptyInputInternal=!0}boxForAnchorAtStart(t,e){const s=t.getRangeAt(0).cloneRange(),n=document.createElement("span");n.textContent="​",e.insertNode(n);const i=n.boxInWindow(window);return n.remove(),t.removeAllRanges(),t.addRange(s),i}additionalCompletions(t){return[]}completionsReady(t,e,s,n,i){if(this.completionRequestId!==t)return;const o=s.toString(),r=new Set;if(i=i.filter((t=>!r.has(t.text)&&Boolean(r.add(t.text)))),(o||n)&&(i=o?i.concat(this.additionalCompletions(o)):this.additionalCompletions(o).concat(i)),!i.length)return void this.clearAutocomplete();const l=e.getRangeAt(0),h=document.createRange();if(h.setStart(s.startContainer,s.startOffset),h.setEnd(l.endContainer,l.endOffset),o+l.toString()!==h.toString())return;const a=document.createRange();a.setStart(this.element(),0),a.setEnd(h.startContainer,h.startOffset),this.queryRange=new TextUtils.TextRange.TextRange(0,a.toString().length,0,a.toString().length+h.toString().length);const u=!this.disableDefaultSuggestionForEmptyInputInternal||Boolean(this.text());this.suggestBox&&this.suggestBox.updateSuggestions(this.boxForAnchorAtStart(e,h),i,u,!this.isCaretAtEndOfPrompt(),this.text())}applySuggestion(t,e){this.currentSuggestion=t,this.refreshGhostText(),e&&this.dispatchEventToListeners(Events.TextChanged)}acceptSuggestion(){this.acceptSuggestionInternal()}acceptSuggestionInternal(){if(!this.queryRange)return!1;const t=this.currentSuggestion?this.currentSuggestion.text.length:0,e=this.currentSuggestion?this.currentSuggestion.selectionRange:null,s=e?e.endColumn:t,n=e?e.startColumn:t;return this.element().textContent=this.textWithCurrentSuggestion(),this.setDOMSelection(this.queryRange.startColumn+n,this.queryRange.startColumn+s),this.updateLeftParenthesesIndices(),this.clearAutocomplete(),this.dispatchEventToListeners(Events.TextChanged),!0}ariaControlledBy(){return this.element()}setDOMSelection(t,e){this.element().normalize();const s=this.element().childNodes[0];if(!s||s===this.ghostTextElement)return;const n=document.createRange();n.setStart(s,t),n.setEnd(s,e);const i=this.element().getComponentSelection();i&&(i.removeAllRanges(),i.addRange(n))}isSuggestBoxVisible(){return void 0!==this.suggestBox&&this.suggestBox.visible()}isCaretInsidePrompt(){const t=this.element().getComponentSelection();if(!t||0===t.rangeCount||!t.isCollapsed)return!1;return t.getRangeAt(0).startContainer.isSelfOrDescendant(this.element())}isCaretAtEndOfPrompt(){const t=this.element().getComponentSelection();if(!t||0===t.rangeCount||!t.isCollapsed)return!1;const e=t.getRangeAt(0);let s=e.startContainer;if(!s.isSelfOrDescendant(this.element()))return!1;if(this.ghostTextElement.isAncestor(s))return!0;if(s.nodeType===Node.TEXT_NODE&&e.startOffset<(s.nodeValue||"").length)return!1;let n=!1;for(;s;){if(s.nodeType===Node.TEXT_NODE&&s.nodeValue&&s.nodeValue.length){if(n&&!this.ghostTextElement.isAncestor(s))return!1;n=!0}s=s.traverseNextNode(this.elementInternal)}return!0}moveCaretToEndOfPrompt(){const t=this.element().getComponentSelection(),e=document.createRange();let s=this.element();for(;s.lastChild;)s=s.lastChild;let n=0;if(s.nodeType===Node.TEXT_NODE){n=(s.textContent||"").length}e.setStart(s,n),e.setEnd(s,n),t&&(t.removeAllRanges(),t.addRange(e))}getCaretPosition(){if(!this.element().hasFocus())return-1;const t=this.element().getComponentSelection();if(!t||0===t.rangeCount||!t.isCollapsed)return-1;const e=t.getRangeAt(0);return e.startOffset!==e.endOffset?-1:e.startOffset}tabKeyPressed(t){return this.acceptAutoComplete()}proxyElementForTests(){return this.proxyElement||null}tryMatchingLeftParenthesis(t){const e=this.leftParenthesesIndices;if(0===e.length||t<0)return!1;for(let s=e.length-1;s>=0;--s)if(e[s]<t)return e.splice(s,1),!0;return!1}updateLeftParenthesesIndices(){const t=this.text(),e=this.leftParenthesesIndices=[];for(let s=0;s<t.length;++s)"("===t[s]&&e.push(s)}suggestBoxForTest(){return this.suggestBox}}const DefaultAutocompletionTimeout=250;export var Events;!function(t){t.TextChanged="TextChanged"}(Events||(Events={}));