@webcoder49/code-input 2.1.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +11 -1
- package/README.md +26 -11
- package/code-input.css +126 -29
- package/code-input.d.ts +153 -11
- package/code-input.js +218 -193
- package/code-input.min.css +1 -1
- package/code-input.min.js +1 -1
- package/package.json +1 -1
- package/plugins/README.md +28 -6
- package/plugins/auto-close-brackets.js +61 -0
- package/plugins/auto-close-brackets.min.js +1 -0
- package/plugins/autocomplete.js +21 -12
- package/plugins/autocomplete.min.js +1 -1
- package/plugins/autodetect.js +4 -4
- package/plugins/autodetect.min.js +1 -1
- package/plugins/find-and-replace.css +145 -0
- package/plugins/find-and-replace.js +746 -0
- package/plugins/find-and-replace.min.css +1 -0
- package/plugins/find-and-replace.min.js +1 -0
- package/plugins/go-to-line.css +77 -0
- package/plugins/go-to-line.js +175 -0
- package/plugins/go-to-line.min.css +1 -0
- package/plugins/go-to-line.min.js +1 -0
- package/plugins/indent.js +166 -15
- package/plugins/indent.min.js +1 -1
- package/plugins/prism-line-numbers.css +10 -9
- package/plugins/prism-line-numbers.min.css +1 -1
- package/plugins/select-token-callbacks.js +289 -0
- package/plugins/select-token-callbacks.min.js +1 -0
- package/plugins/special-chars.css +1 -5
- package/plugins/special-chars.js +65 -61
- package/plugins/special-chars.min.css +2 -2
- package/plugins/special-chars.min.js +1 -1
- package/plugins/test.js +1 -2
- package/plugins/test.min.js +1 -1
- package/tests/hljs.html +55 -0
- package/tests/i18n.html +197 -0
- package/tests/prism-match-braces-compatibility.js +215 -0
- package/tests/prism-match-braces-compatibility.min.js +1 -0
- package/tests/prism.html +54 -0
- package/tests/tester.js +593 -0
- package/tests/tester.min.js +21 -0
- package/plugins/debounce-update.js +0 -40
- package/plugins/debounce-update.min.js +0 -1
package/code-input.min.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
code-input{position:relative;top:0;left:0;
|
|
1
|
+
code-input{display:block;overflow-y:auto;overflow-x:auto;position:relative;top:0;left:0;margin:8px;--padding:16px;height:250px;font-size:inherit;font-family:monospace;line-height:1.5;tab-size:2;caret-color:#a9a9a9;white-space:pre;padding:0!important;display:grid;grid-template-columns:100%;grid-template-rows:100%}code-input:not(.code-input_loaded){padding:var(--padding,16px)!important}code-input textarea,code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{margin:0!important;padding:var(--padding,16px)!important;border:0;min-width:calc(100% - var(--padding) * 2);min-height:calc(100% - var(--padding) * 2);overflow:hidden;resize:none;grid-row:1;grid-column:1;display:block}code-input.code-input_pre-element-styled pre,code-input:not(.code-input_pre-element-styled) pre code{height:max-content;width:max-content}code-input.code-input_pre-element-styled pre code,code-input:not(.code-input_pre-element-styled) pre{margin:0!important;padding:0!important;width:100%;height:100%}code-input pre,code-input pre *,code-input textarea{font-size:inherit!important;font-family:inherit!important;line-height:inherit!important;tab-size:inherit!important;text-align:inherit!important}code-input textarea[dir=auto]+pre{unicode-bidi:plaintext}code-input textarea[dir=ltr]+pre{direction:ltr}code-input textarea[dir=rtl]+pre{direction:rtl}code-input pre,code-input textarea{grid-column:1;grid-row:1}code-input textarea{z-index:1}code-input pre{z-index:0}code-input textarea{color:transparent;background:0 0;caret-color:inherit!important}code-input textarea::placeholder{color:#d3d3d3}code-input pre,code-input textarea{white-space:inherit;word-spacing:normal;word-break:normal;word-wrap:normal}code-input textarea{resize:none;outline:0!important}code-input:has(textarea:focus):not(.code-input_mouse-focused){outline:2px solid #000}code-input:not(.code-input_registered){overflow:hidden;display:block;box-sizing:border-box}code-input:not(.code-input_registered)::after{content:"Use codeInput.registerTemplate to set up.";display:block;position:absolute;bottom:var(--padding);left:var(--padding);width:calc(100% - 2 * var(--padding));border-top:1px solid grey;outline:var(--padding) solid #fff;background-color:#fff}code-input:not(.code-input_loaded) pre,code-input:not(.code-input_loaded) textarea{opacity:0}code-input .code-input_dialog-container{z-index:2;position:sticky;grid-row:1;grid-column:1;top:0;left:0;margin:0;padding:0;width:100%;height:0;text-align:inherit}[dir=rtl] code-input .code-input_dialog-container,code-input[dir=rtl] .code-input_dialog-container{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions{top:0;left:0;display:block;position:absolute;background-color:#000;color:#fff;padding:2px;padding-left:10px;margin:0;text-wrap:balance;overflow:hidden;text-overflow:ellipsis;width:calc(100% - 12px);max-height:3em}code-input:has(pre[dir=rtl]) .code-input_dialog-container .code-input_keyboard-navigation-instructions{left:unset;right:0}code-input .code-input_dialog-container .code-input_keyboard-navigation-instructions:empty,code-input.code-input_mouse-focused .code-input_dialog-container .code-input_keyboard-navigation-instructions,code-input:not(:has(textarea:focus)) .code-input_dialog-container .code-input_keyboard-navigation-instructions{display:none}code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused) textarea,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused).code-input_pre-element-styled pre,code-input:not(:has(.code-input_keyboard-navigation-instructions:empty)):has(textarea:focus):not(.code-input_mouse-focused):not(.code-input_pre-element-styled) pre code{padding-top:calc(var(--padding) + 3em)!important}
|
package/code-input.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var codeInput={observedAttributes:["value","placeholder","lang","template"],textareaSyncAttributes:["aria-*","value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Template for "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue){for(let c in codeInput.templateNotYetRegisteredQueue[a])elem=codeInput.templateNotYetRegisteredQueue[a][c],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Added existing elements with template ${a}`)}if(null==codeInput.defaultTemplate){if(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue)for(let a in codeInput.templateNotYetRegisteredQueue[void 0])elem=codeInput.templateNotYetRegisteredQueue[void 0][a],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Set template ${a} as default`)}console.log(`code-input: template: Created template ${a}`)},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!0,isCode:!0,plugins:b}},hljs(a,b=[]){return{includeCodeInputInHighlightFunc:!1,highlight:a.highlightElement,preElementStyled:!1,isCode:!0,plugins:b}},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){console.log("code-input: plugin: Created plugin"),a.forEach(a=>{let b=codeInput.wildcard2regex(a);null==b?codeInput.observedAttributes.push(a):codeInput.observedAttributes.regexp.push(b)})}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}_value="";textareaElement=null;preElement=null;codeElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.template.plugins){let d=this.template.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}update(a){if(!this.ignoreValueUpdate){if(null==this.textareaElement)return void this.addEventListener("code-input_load",()=>{this.update(a)});this.ignoreValueUpdate=!0,this.value=a,this.ignoreValueUpdate=!1,this.textareaElement.value!=a&&(this.textareaElement.value=a);let b=this.codeElement;"\n"==a[a.length-1]&&(a+=" "),b.innerHTML=this.escapeHtml(a),this.pluginEvt("beforeHighlight"),this.template.includeCodeInputInHighlightFunc?this.template.highlight(b,this):this.template.highlight(b),this.pluginEvt("afterHighlight")}}syncScroll(){let a=this.textareaElement,b=this.template.preElementStyled?this.preElement:this.codeElement;b.scrollTop=a.scrollTop,b.scrollLeft=a.scrollLeft}escapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<")}unescapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.template.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");let a=this.getAttribute("lang"),b=this.getAttribute("placeholder")||this.getAttribute("lang")||"",c=this.unescapeHtml(this.innerHTML)||this.getAttribute("value")||"";this.initialValue=c;let d=document.createElement("textarea");d.placeholder=b,""!=c&&(d.value=c),d.innerHTML=this.innerHTML,d.setAttribute("spellcheck","false"),this.innerHTML="",codeInput.textareaSyncAttributes.forEach(a=>{this.hasAttribute(a)&&d.setAttribute(a,this.getAttribute(a))}),codeInput.textareaSyncAttributes.regexp.forEach(a=>{for(const b of this.attributes)b.nodeName.match(a)&&d.setAttribute(b.nodeName,b.nodeValue)}),d.addEventListener("input",()=>{d.parentElement.update(d.value),d.parentElement.sync_scroll()}),d.addEventListener("scroll",()=>d.parentElement.sync_scroll()),this.textareaElement=d,this.append(d);let e=document.createElement("code"),f=document.createElement("pre");f.setAttribute("aria-hidden","true"),this.preElement=f,this.codeElement=e,f.append(e),this.append(f),this.template.isCode&&a!=null&&""!=a&&e.classList.add("language-"+a),this.pluginEvt("afterElementsAdded"),this.update(c),this.dispatchEvent(new CustomEvent("code-input_load"))}sync_scroll(){this.syncScroll()}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}connectedCallback(){this.template=this.getTemplate(),this.template!=null&&(this.classList.add("code-input_registered"),codeInput.runOnceWindowLoaded(()=>{this.setup(),this.classList.add("code-input_loaded")},this)),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0})}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));for(let a=0;a<codeInput.observedAttributes.regexp.length;a++){const c=codeInput.observedAttributes.regexp[a];if(b.attributeName.match(c))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}}disconnectedCallback(){this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"placeholder":this.textareaElement.placeholder=c;break;case"template":this.template=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.template.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.update(this.value);break;case"lang":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),e.placeholder==b&&(e.placeholder=c),this.update(this.value);break;default:codeInput.textareaSyncAttributes.includes(a)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}addEventListener(a,b,c=void 0){let d=b.bind(this);this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)?c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)}):this.textareaElement.addEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)}):this.textareaElement.addEventListener(a,d,c):c===void 0?super.addEventListener(a,d):super.addEventListener(a,d,c)}removeEventListener(a,b,c=null){let d=this.boundEventCallbacks[b];"change"==a?null===c?this.textareaElement.removeEventListener("change",d):this.textareaElement.removeEventListener("change",d,c):"selectionchange"==a?null===c?this.textareaElement.removeEventListener("selectionchange",d):this.textareaElement.removeEventListener("selectionchange",d,c):super.removeEventListener(a,b,c)}get value(){return this._value}set value(a){return(null===a||void 0===a)&&(a=""),this._value=a,this.update(a),a}get placeholder(){return this.getAttribute("placeholder")}set placeholder(a){return this.setAttribute("placeholder",a)}get validity(){return this.textareaElement.validity}get validationMessage(){return this.textareaElement.validationMessage}setCustomValidity(a){return this.textareaElement.setCustomValidity(a)}checkValidity(){return this.textareaElement.checkValidity()}reportValidity(){return this.textareaElement.reportValidity()}pluginData={};formResetCallback(){this.update(this.initialValue)}},arrayWildcards2regex(a){for(let b=0;b<a.length;b++){const c=a[b];0>c.indexOf("*")||(a.regexp.push(new RegExp("^"+c.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")),a.splice(b--,1))}},wildcard2regex(a){return 0>a.indexOf("*")?null:new RegExp("^"+a.replace(/[/\-\\^$+?.()|[\]{}]/g,"\\$&").replace("*",".*")+"$","i")},runOnceWindowLoaded(a){codeInput.windowLoaded?a():window.addEventListener("load",a)},windowLoaded:!1};window.addEventListener("load",function(){codeInput.windowLoaded=!0}),Object.defineProperty(codeInput.textareaSyncAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.observedAttributes=codeInput.observedAttributes.concat(codeInput.textareaSyncAttributes),Object.defineProperty(codeInput.observedAttributes,"regexp",{value:[],writable:!1,enumerable:!1,configurable:!1}),codeInput.arrayWildcards2regex(codeInput.textareaSyncAttributes),codeInput.arrayWildcards2regex(codeInput.observedAttributes),customElements.define("code-input",codeInput.CodeInput);
|
|
1
|
+
var codeInput={observedAttributes:["value","placeholder","language","lang","template"],textareaSyncAttributes:["value","min","max","type","pattern","autocomplete","autocorrect","autofocus","cols","dirname","disabled","form","maxlength","minlength","name","placeholder","readonly","required","rows","spellcheck","wrap"],textareaSyncEvents:["change","selectionchange","invalid","input"],usedTemplates:{},defaultTemplate:void 0,templateNotYetRegisteredQueue:{},registerTemplate:function(a,b){if(!("string"==typeof a||a instanceof String))throw TypeError(`code-input: Name of template "${a}" must be a string.`);if(!("function"==typeof b.highlight||b.highlight instanceof Function))throw TypeError(`code-input: Template for "${a}" invalid, because the highlight function provided is not a function; it is "${b.highlight}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.includeCodeInputInHighlightFunc||b.includeCodeInputInHighlightFunc instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the includeCodeInputInHighlightFunc value provided is not a true or false; it is "${b.includeCodeInputInHighlightFunc}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.preElementStyled||b.preElementStyled instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the preElementStyled value provided is not a true or false; it is "${b.preElementStyled}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!("boolean"==typeof b.isCode||b.isCode instanceof Boolean))throw TypeError(`code-input: Template for "${a}" invalid, because the isCode value provided is not a true or false; it is "${b.isCode}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(!Array.isArray(b.plugins))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin array provided is not an array; it is "${b.plugins}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`);if(b.plugins.forEach((c,d)=>{if(!(c instanceof codeInput.Plugin))throw TypeError(`code-input: Template for "${a}" invalid, because the plugin provided at index ${d} is not valid; it is "${b.plugins[d]}". Please make sure you use one of the constructors in codeInput.templates, and that you provide the correct arguments.`)}),codeInput.usedTemplates[a]=b,a in codeInput.templateNotYetRegisteredQueue){for(let c in codeInput.templateNotYetRegisteredQueue[a])elem=codeInput.templateNotYetRegisteredQueue[a][c],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Added existing elements with template ${a}`)}if(null==codeInput.defaultTemplate){if(codeInput.defaultTemplate=a,void 0 in codeInput.templateNotYetRegisteredQueue)for(let a in codeInput.templateNotYetRegisteredQueue[void 0])elem=codeInput.templateNotYetRegisteredQueue[void 0][a],elem.template=b,codeInput.runOnceWindowLoaded(function(a){a.connectedCallback()}.bind(null,elem),elem);console.log(`code-input: template: Set template ${a} as default`)}console.log(`code-input: template: Created template ${a}`)},Template:class{constructor(a=function(){},b=!0,c=!0,d=!1,e=[]){this.highlight=a,this.preElementStyled=b,this.isCode=c,this.includeCodeInputInHighlightFunc=d,this.plugins=e}highlight=function(){};preElementStyled=!0;isCode=!0;includeCodeInputInHighlightFunc=!1;plugins=[]},templates:{prism(a,b=[]){return new codeInput.Template(a.highlightElement,!0,!0,!1,b)},hljs(a,b=[]){return new codeInput.Template(function(b){b.removeAttribute("data-highlighted"),a.highlightElement(b)},!1,!0,!1,b)},characterLimit(a){return{highlight:function(a,b,c=[]){let d=+b.getAttribute("data-character-limit"),e=b.escapeHtml(b.value.slice(0,d)),f=b.escapeHtml(b.value.slice(d));a.innerHTML=`${e}<mark class="overflow">${f}</mark>`,0<f.length&&(a.innerHTML+=` <mark class="overflow-msg">${b.getAttribute("data-overflow-msg")||"(Character limit reached)"}</mark>`)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,plugins:a}},rainbowText(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return{highlight:function(a,b){let c=[],d=b.value.split(b.template.delimiter);for(let e=0;e<d.length;e++)c.push(`<span style="color: ${b.template.rainbowColors[e%b.template.rainbowColors.length]}">${b.escapeHtml(d[e])}</span>`);a.innerHTML=c.join(b.template.delimiter)},includeCodeInputInHighlightFunc:!0,preElementStyled:!0,isCode:!1,rainbowColors:a,delimiter:b,plugins:c}},character_limit(){return this.characterLimit([])},rainbow_text(a=["red","orangered","orange","goldenrod","gold","green","darkgreen","navy","blue","magenta"],b="",c=[]){return this.rainbowText(a,b,c)},custom(a=function(){},b=!0,c=!0,d=!1,e=[]){return{highlight:a,includeCodeInputInHighlightFunc:d,preElementStyled:b,isCode:c,plugins:e}}},plugins:new Proxy({},{get(a,b){if(a[b]==null)throw ReferenceError(`code-input: Plugin '${b}' is not defined. Please ensure you import the necessary files from the plugins folder in the WebCoder49/code-input repository, in the <head> of your HTML, before the plugin is instatiated.`);return a[b]}}),Plugin:class{constructor(a){console.log("code-input: plugin: Created plugin"),a.forEach(a=>{codeInput.observedAttributes.push(a)})}addTranslations(a,b){for(const c in b)a[c]=b[c]}beforeHighlight(){}afterHighlight(){}beforeElementsAdded(){}afterElementsAdded(){}attributeChanged(){}},CodeInput:class extends HTMLElement{constructor(){super()}textareaElement=null;preElement=null;codeElement=null;dialogContainerElement=null;static formAssociated=!0;boundEventCallbacks={};pluginEvt(a,b){for(let c in this.template.plugins){let d=this.template.plugins[c];a in d&&(b===void 0?d[a](this):d[a](this,...b))}}needsHighlight=!1;handleEventsFromTextarea=!0;originalAriaDescription;scheduleHighlight(){this.needsHighlight=!0}animateFrame(){this.needsHighlight&&(this.update(),this.needsHighlight=!1),window.requestAnimationFrame(this.animateFrame.bind(this))}update(){let a=this.codeElement,b=this.value;b+="\n",a.innerHTML=this.escapeHtml(b),this.pluginEvt("beforeHighlight"),this.template.includeCodeInputInHighlightFunc?this.template.highlight(a,this):this.template.highlight(a),this.syncSize(),this.textareaElement===document.activeElement&&(this.handleEventsFromTextarea=!1,this.textareaElement.blur(),this.textareaElement.focus(),this.handleEventsFromTextarea=!0),this.pluginEvt("afterHighlight")}syncSize(){this.template.preElementStyled?(this.style.backgroundColor=getComputedStyle(this.preElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.preElement).height,this.textareaElement.style.width=getComputedStyle(this.preElement).width):(this.style.backgroundColor=getComputedStyle(this.codeElement).backgroundColor,this.textareaElement.style.height=getComputedStyle(this.codeElement).height,this.textareaElement.style.width=getComputedStyle(this.codeElement).width)}setKeyboardNavInstructions(a,b){this.dialogContainerElement.querySelector(".code-input_keyboard-navigation-instructions").innerText=a,b?this.textareaElement.setAttribute("aria-description",this.originalAriaDescription+". "+a):this.textareaElement.setAttribute("aria-description",a)}escapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<")}unescapeHtml(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}getTemplate(){let a;return a=null==this.getAttribute("template")?codeInput.defaultTemplate:this.getAttribute("template"),a in codeInput.usedTemplates?codeInput.usedTemplates[a]:(a in codeInput.templateNotYetRegisteredQueue||(codeInput.templateNotYetRegisteredQueue[a]=[]),void codeInput.templateNotYetRegisteredQueue[a].push(this))}setup(){if(null!=this.textareaElement)return;this.classList.add("code-input_registered"),this.template.preElementStyled&&this.classList.add("code-input_pre-element-styled"),this.pluginEvt("beforeElementsAdded");let a=this.getAttribute("language")||this.getAttribute("lang"),b=this.getAttribute("placeholder")||this.getAttribute("language")||this.getAttribute("lang")||"",c=this.unescapeHtml(this.innerHTML)||this.getAttribute("value")||"";this.initialValue=c;let d=document.createElement("textarea");d.placeholder=b,""!=c&&(d.value=c),d.innerHTML=this.innerHTML,d.setAttribute("spellcheck","false"),d.setAttribute("tabindex",this.getAttribute("tabindex")||0),this.setAttribute("tabindex",-1),this.originalAriaDescription=this.getAttribute("aria-description")||"Code input field",this.addEventListener("mousedown",()=>{this.classList.add("code-input_mouse-focused")}),d.addEventListener("blur",()=>{this.handleEventsFromTextarea&&this.classList.remove("code-input_mouse-focused")}),this.innerHTML="";for(let a,b=0;b<this.attributes.length;b++)a=this.attributes[b].name,(codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5))&&d.setAttribute(a,this.getAttribute(a));d.addEventListener("input",()=>{this.value=this.textareaElement.value}),this.textareaElement=d,this.append(d);let e=document.createElement("code"),f=document.createElement("pre");f.setAttribute("aria-hidden","true"),f.setAttribute("tabindex","-1"),f.setAttribute("inert",!0),this.preElement=f,this.codeElement=e,f.append(e),this.append(f),this.template.isCode&&a!=null&&""!=a&&e.classList.add("language-"+a.toLowerCase());let g=document.createElement("div");g.classList.add("code-input_dialog-container"),this.append(g),this.dialogContainerElement=g;let h=document.createElement("div");h.classList.add("code-input_keyboard-navigation-instructions"),g.append(h),this.pluginEvt("afterElementsAdded"),this.dispatchEvent(new CustomEvent("code-input_load")),this.value=c,this.animateFrame();const i=new ResizeObserver(()=>{this.syncSize()});i.observe(this)}escape_html(a){return this.escapeHtml(a)}get_template(){return this.getTemplate()}connectedCallback(){this.template=this.getTemplate(),this.template!=null&&(this.classList.add("code-input_registered"),codeInput.runOnceWindowLoaded(()=>{this.setup(),this.classList.add("code-input_loaded")},this)),this.mutationObserver=new MutationObserver(this.mutationObserverCallback.bind(this)),this.mutationObserver.observe(this,{attributes:!0,attributeOldValue:!0})}mutationObserverCallback(a){for(const b of a)if("attributes"===b.type){for(let a=0;a<codeInput.observedAttributes.length;a++)if(b.attributeName==codeInput.observedAttributes[a])return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName));if("aria-"==b.attributeName.substring(0,5))return this.attributeChangedCallback(b.attributeName,b.oldValue,super.getAttribute(b.attributeName))}}disconnectedCallback(){this.mutationObserver.disconnect()}attributeChangedCallback(a,b,c){if(this.isConnected)switch(this.pluginEvt("attributeChanged",[a,b,c]),a){case"value":this.value=c;break;case"template":this.template=codeInput.usedTemplates[c||codeInput.defaultTemplate],this.template.preElementStyled?this.classList.add("code-input_pre-element-styled"):this.classList.remove("code-input_pre-element-styled"),this.scheduleHighlight();break;case"lang":case"language":let d=this.codeElement,e=this.textareaElement;if(null!=c&&(c=c.toLowerCase(),d.classList.contains(`language-${c}`)))break;null!==b&&(b=b.toLowerCase(),d.classList.remove("language-"+b),d.parentElement.classList.remove("language-"+b)),d.classList.remove("language-none"),d.parentElement.classList.remove("language-none"),null!=c&&""!=c&&d.classList.add("language-"+c),e.placeholder==b&&(e.placeholder=c),this.scheduleHighlight();break;default:codeInput.textareaSyncAttributes.includes(a)||"aria-"==a.substring(0,5)?null==c||null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c):codeInput.textareaSyncAttributes.regexp.forEach(b=>{a.match(b)&&(null==c?this.textareaElement.removeAttribute(a):this.textareaElement.setAttribute(a,c))})}}addEventListener(a,b,c=void 0){let d=function(a){"function"==typeof b?b(a):b&&b.handleEvent&&b.handleEvent(a)}.bind(this);if(this.boundEventCallbacks[b]=d,codeInput.textareaSyncEvents.includes(a)){let e=function(a){this.handleEventsFromTextarea&&d(a)}.bind(this);this.boundEventCallbacks[b]=e,void 0===c?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d)}):this.textareaElement.addEventListener(a,e):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.addEventListener(a,d,c)}):this.textareaElement.addEventListener(a,e,c)}else void 0===c?super.addEventListener(a,d):super.addEventListener(a,d,c)}removeEventListener(a,b,c=void 0){let d=this.boundEventCallbacks[b];codeInput.textareaSyncEvents.includes(a)?c===void 0?null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d)}):this.textareaElement.removeEventListener(a,d):null==this.textareaElement?this.addEventListener("code-input_load",()=>{this.textareaElement.removeEventListener(a,d,c)}):this.textareaElement.removeEventListener(a,d,c):c===void 0?super.removeEventListener(a,d):super.removeEventListener(a,d,c)}get value(){return this.textareaElement.value}set value(a){return(null===a||void 0===a)&&(a=""),this.textareaElement.value=a,this.scheduleHighlight(),a}get placeholder(){return this.getAttribute("placeholder")}set placeholder(a){return this.setAttribute("placeholder",a)}get validity(){return this.textareaElement.validity}get validationMessage(){return this.textareaElement.validationMessage}setCustomValidity(a){return this.textareaElement.setCustomValidity(a)}checkValidity(){return this.textareaElement.checkValidity()}reportValidity(){return this.textareaElement.reportValidity()}pluginData={};formResetCallback(){this.value=this.initialValue}},runOnceWindowLoaded(a){"complete"==document.readyState?a():window.addEventListener("load",a)}};customElements.define("code-input",codeInput.CodeInput);
|
package/package.json
CHANGED
package/plugins/README.md
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
### Auto-Close Brackets
|
|
11
|
+
Automatically close pairs of brackets/quotes/other syntaxes in code, but also optionally choose the brackets this
|
|
12
|
+
is activated for.
|
|
13
|
+
|
|
14
|
+
Files: [auto-close-brackets.js](./auto-close-brackets.js)
|
|
15
|
+
|
|
16
|
+
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/qBgGGKR)
|
|
17
|
+
|
|
10
18
|
### Autocomplete
|
|
11
19
|
Display a popup under the caret using the text in the code-input element. This works well with autocomplete suggestions.
|
|
12
20
|
|
|
@@ -21,22 +29,29 @@ Files: [autodetect.js](./autodetect.js)
|
|
|
21
29
|
|
|
22
30
|
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/eYLyMae)
|
|
23
31
|
|
|
24
|
-
###
|
|
25
|
-
|
|
32
|
+
### Find and Replace
|
|
33
|
+
Add Find-and-Replace (Ctrl+F for find, Ctrl+H for replace by default, or when JavaScript triggers it) functionality to the code editor.
|
|
34
|
+
|
|
35
|
+
Files: [find-and-replace.js](./find-and-replace.js) / [find-and-replace.css](./find-and-replace.css)
|
|
36
|
+
|
|
37
|
+
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/oNVVBBz)
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
### Go To Line
|
|
40
|
+
Add a feature to go to a specific line when a line number is given (or column as well, in the format line no:column no) that appears when (optionally) Ctrl+G is pressed or when JavaScript triggers it.
|
|
28
41
|
|
|
29
|
-
[
|
|
42
|
+
Files: [go-to-line.js](./go-to-line.js) / [go-to-line.css](./go-to-line.css)
|
|
43
|
+
|
|
44
|
+
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/YzBMOXP)
|
|
30
45
|
|
|
31
46
|
### Indent
|
|
32
|
-
|
|
47
|
+
Add indentation using the `Tab` key, and auto-indents after a newline, as well as making it possible to indent/unindent multiple lines using Tab/Shift+Tab. **Supports tab characters and custom numbers of spaces as indentation, as well as (optionally) brackets typed affecting indentation.**
|
|
33
48
|
|
|
34
49
|
Files: [indent.js](./indent.js)
|
|
35
50
|
|
|
36
51
|
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/WNgdzar)
|
|
37
52
|
|
|
38
53
|
### Prism Line Numbers
|
|
39
|
-
|
|
54
|
+
Allow code-input elements to be used with the Prism.js line-numbers plugin, as long as the code-input element or a parent element of it has the CSS class `line-numbers`. [Prism.js Plugin Docs](https://prismjs.com/plugins/line-numbers/)
|
|
40
55
|
|
|
41
56
|
Files: [prism-line-numbers.css](./prism-line-numbers.css) (NO JS FILE)
|
|
42
57
|
|
|
@@ -50,6 +65,13 @@ Files: [special-chars.js](./special-chars.js) / [special-chars.css](./special-ch
|
|
|
50
65
|
|
|
51
66
|
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/jOeYJbm)
|
|
52
67
|
|
|
68
|
+
### Select Token Callbacks
|
|
69
|
+
Make tokens in the `<pre><code>` element that are included within the selected text of the `<code-input>` gain a CSS class while selected, or trigger JavaScript callbacks.
|
|
70
|
+
|
|
71
|
+
Files: select-token-callbacks.js
|
|
72
|
+
|
|
73
|
+
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/WNVZXxM)
|
|
74
|
+
|
|
53
75
|
## Using Plugins
|
|
54
76
|
Plugins allow you to add extra features to a template, like [automatic indentation](./indent.js) or [support for highlight.js's language autodetection](./autodetect.js). To use them, just:
|
|
55
77
|
- Import the plugins' JS/CSS files (there may only be one of these; import all of the files that exist) after you have imported `code-input` and before registering the template.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automatically close pairs of brackets/quotes/other syntaxes in code, but also optionally choose the brackets this
|
|
3
|
+
* is activated for.
|
|
4
|
+
* Files: auto-close-brackets.js
|
|
5
|
+
*/
|
|
6
|
+
codeInput.plugins.AutoCloseBrackets = class extends codeInput.Plugin {
|
|
7
|
+
bracketPairs = [];
|
|
8
|
+
bracketsOpenedStack = []; // Each item [closing bracket string, opening bracket location] Innermost at right so can know which brackets should be ignored when retyped
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create an auto-close brackets plugin to pass into a template
|
|
12
|
+
* @param {Object} bracketPairs Opening brackets mapped to closing brackets, default and example {"(": ")", "[": "]", "{": "}", '"': '"'}. All brackets must only be one character.
|
|
13
|
+
*/
|
|
14
|
+
constructor(bracketPairs={"(": ")", "[": "]", "{": "}", '"': '"'}) {
|
|
15
|
+
super([]); // No observed attributes
|
|
16
|
+
|
|
17
|
+
this.bracketPairs = bracketPairs;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Add keystroke events */
|
|
21
|
+
afterElementsAdded(codeInput) {
|
|
22
|
+
codeInput.textareaElement.addEventListener('keydown', (event) => { this.checkBackspace(codeInput, event) });
|
|
23
|
+
codeInput.textareaElement.addEventListener('beforeinput', (event) => { this.checkBrackets(codeInput, event); });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Deal with the automatic creation of closing bracket when opening brackets are typed, and the ability to "retype" a closing
|
|
27
|
+
bracket where one has already been placed. */
|
|
28
|
+
checkBrackets(codeInput, event) {
|
|
29
|
+
if(event.data == codeInput.textareaElement.value[codeInput.textareaElement.selectionStart]) {
|
|
30
|
+
// Check if a closing bracket is typed
|
|
31
|
+
for(let openingBracket in this.bracketPairs) {
|
|
32
|
+
let closingBracket = this.bracketPairs[openingBracket];
|
|
33
|
+
if(event.data == closingBracket) {
|
|
34
|
+
// "Retype" a closing bracket, i.e. just move caret
|
|
35
|
+
codeInput.textareaElement.selectionStart = codeInput.textareaElement.selectionEnd += 1;
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else if(event.data in this.bracketPairs) {
|
|
41
|
+
// Opening bracket typed; Create bracket pair
|
|
42
|
+
let closingBracket = this.bracketPairs[event.data];
|
|
43
|
+
// Insert the closing bracket
|
|
44
|
+
document.execCommand("insertText", false, closingBracket);
|
|
45
|
+
// Move caret before the inserted closing bracket
|
|
46
|
+
codeInput.textareaElement.selectionStart = codeInput.textareaElement.selectionEnd -= 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Deal with cases where a backspace deleting an opening bracket deletes the closing bracket straight after it as well */
|
|
51
|
+
checkBackspace(codeInput, event) {
|
|
52
|
+
if(event.key == "Backspace" && codeInput.textareaElement.selectionStart == codeInput.textareaElement.selectionEnd) {
|
|
53
|
+
let closingBracket = this.bracketPairs[codeInput.textareaElement.value[codeInput.textareaElement.selectionStart-1]];
|
|
54
|
+
if(closingBracket != undefined && codeInput.textareaElement.value[codeInput.textareaElement.selectionStart] == closingBracket) {
|
|
55
|
+
// Opening bracket being deleted so delete closing bracket as well
|
|
56
|
+
codeInput.textareaElement.selectionEnd = codeInput.textareaElement.selectionStart + 1;
|
|
57
|
+
codeInput.textareaElement.selectionStart -= 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
codeInput.plugins.AutoCloseBrackets=class extends codeInput.Plugin{bracketPairs=[];bracketsOpenedStack=[];constructor(a={"(":")","[":"]","{":"}",'"':"\""}){super([]),this.bracketPairs=a}afterElementsAdded(a){a.textareaElement.addEventListener("keydown",b=>{this.checkBackspace(a,b)}),a.textareaElement.addEventListener("beforeinput",b=>{this.checkBrackets(a,b)})}checkBrackets(a,b){if(b.data==a.textareaElement.value[a.textareaElement.selectionStart])for(let c in this.bracketPairs){let d=this.bracketPairs[c];if(b.data==d){a.textareaElement.selectionStart=a.textareaElement.selectionEnd+=1,b.preventDefault();break}}else if(b.data in this.bracketPairs){let c=this.bracketPairs[b.data];document.execCommand("insertText",!1,c),a.textareaElement.selectionStart=a.textareaElement.selectionEnd-=1}}checkBackspace(a,b){if("Backspace"==b.key&&a.textareaElement.selectionStart==a.textareaElement.selectionEnd){let b=this.bracketPairs[a.textareaElement.value[a.textareaElement.selectionStart-1]];b!=null&&a.textareaElement.value[a.textareaElement.selectionStart]==b&&(a.textareaElement.selectionEnd=a.textareaElement.selectionStart+1,a.textareaElement.selectionStart-=1)}}};
|
package/plugins/autocomplete.js
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
|
|
6
6
|
/**
|
|
7
|
-
* Pass in a function to
|
|
8
|
-
* @param {
|
|
7
|
+
* Pass in a function to create a plugin that displays the popup that takes in (popup element, textarea, textarea.selectionEnd).
|
|
8
|
+
* @param {(popupElement: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number) => void} updatePopupCallback a function to display the popup that takes in (popup element, textarea, textarea.selectionEnd).
|
|
9
9
|
*/
|
|
10
10
|
constructor(updatePopupCallback) {
|
|
11
11
|
super([]); // No observed attributes
|
|
12
12
|
this.updatePopupCallback = updatePopupCallback;
|
|
13
13
|
}
|
|
14
|
-
/* When a key is pressed, or scrolling occurs, update the
|
|
14
|
+
/* When a key is pressed, or scrolling occurs, update the popup position */
|
|
15
15
|
updatePopup(codeInput, onlyScrolled) {
|
|
16
16
|
let textarea = codeInput.textareaElement;
|
|
17
17
|
let caretCoords = this.getCaretCoordinates(codeInput, textarea, textarea.selectionEnd, onlyScrolled);
|
|
@@ -23,20 +23,29 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
|
|
|
23
23
|
this.updatePopupCallback(popupElem, textarea, textarea.selectionEnd);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
/*
|
|
26
|
+
/* Create the popup element */
|
|
27
27
|
afterElementsAdded(codeInput) {
|
|
28
28
|
let popupElem = document.createElement("div");
|
|
29
29
|
popupElem.classList.add("code-input_autocomplete_popup");
|
|
30
30
|
codeInput.appendChild(popupElem);
|
|
31
31
|
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
let testPosPre = document.createElement("pre");
|
|
33
|
+
popupElem.setAttribute("inert", true); // Invisible to keyboard navigation
|
|
34
|
+
popupElem.setAttribute("tabindex", -1); // Invisible to keyboard navigation
|
|
35
|
+
testPosPre.setAttribute("aria-hidden", true); // Hide for screen readers
|
|
36
|
+
if(codeInput.template.preElementStyled) {
|
|
37
|
+
testPosPre.classList.add("code-input_autocomplete_testpos");
|
|
38
|
+
codeInput.appendChild(testPosPre); // Styled like first pre, but first pre found to update
|
|
39
|
+
} else {
|
|
40
|
+
let testPosCode = document.createElement("code");
|
|
41
|
+
testPosCode.classList.add("code-input_autocomplete_testpos");
|
|
42
|
+
testPosPre.appendChild(testPosCode);
|
|
43
|
+
codeInput.appendChild(testPosPre); // Styled like first pre, but first pre found to update
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
let textarea = codeInput.textareaElement;
|
|
37
|
-
textarea.addEventListener("
|
|
38
|
-
textarea.addEventListener("click", this.updatePopup
|
|
39
|
-
textarea.addEventListener("scroll", this.updatePopup.bind(this, codeInput, true)); // Override this+args in bind - just scrolling
|
|
47
|
+
textarea.addEventListener("input", () => { this.updatePopup(codeInput, false)});
|
|
48
|
+
textarea.addEventListener("click", () => { this.updatePopup(codeInput, false)});
|
|
40
49
|
}
|
|
41
50
|
/**
|
|
42
51
|
* Return the coordinates of the caret in a code-input
|
|
@@ -44,7 +53,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin {
|
|
|
44
53
|
* @param {HTMLElement} textarea
|
|
45
54
|
* @param {Number} charIndex
|
|
46
55
|
* @param {boolean} onlyScrolled True if no edits have been made to the text and the caret hasn't been repositioned
|
|
47
|
-
* @returns
|
|
56
|
+
* @returns {Object} {"top": CSS top value in pixels, "left": CSS left value in pixels}
|
|
48
57
|
*/
|
|
49
58
|
getCaretCoordinates(codeInput, textarea, charIndex, onlyScrolled) {
|
|
50
59
|
let afterSpan;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
codeInput.plugins.Autocomplete=class extends codeInput.Plugin{constructor(a){super([]),this.updatePopupCallback=a}updatePopup(a,b){let c=a.textareaElement,d=this.getCaretCoordinates(a,c,c.selectionEnd,b),e=a.querySelector(".code-input_autocomplete_popup");e.style.top=d.top+"px",e.style.left=d.left+"px",b||this.updatePopupCallback(e,c,c.selectionEnd)}afterElementsAdded(a){let b=document.createElement("div");b.classList.add("code-input_autocomplete_popup"),a.appendChild(b);let c=document.createElement("pre");c.classList.add("code-input_autocomplete_testpos"),a.appendChild(c);let
|
|
1
|
+
codeInput.plugins.Autocomplete=class extends codeInput.Plugin{constructor(a){super([]),this.updatePopupCallback=a}updatePopup(a,b){let c=a.textareaElement,d=this.getCaretCoordinates(a,c,c.selectionEnd,b),e=a.querySelector(".code-input_autocomplete_popup");e.style.top=d.top+"px",e.style.left=d.left+"px",b||this.updatePopupCallback(e,c,c.selectionEnd)}afterElementsAdded(a){let b=document.createElement("div");b.classList.add("code-input_autocomplete_popup"),a.appendChild(b);let c=document.createElement("pre");if(b.setAttribute("inert",!0),b.setAttribute("tabindex",-1),c.setAttribute("aria-hidden",!0),a.template.preElementStyled)c.classList.add("code-input_autocomplete_testpos"),a.appendChild(c);else{let b=document.createElement("code");b.classList.add("code-input_autocomplete_testpos"),c.appendChild(b),a.appendChild(c)}let d=a.textareaElement;d.addEventListener("input",()=>{this.updatePopup(a,!1)}),d.addEventListener("click",()=>{this.updatePopup(a,!1)})}getCaretCoordinates(a,b,c,d){let e;if(d){let d=a.querySelector(".code-input_autocomplete_testpos").querySelectorAll("span");if(2>d.length)return this.getCaretCoordinates(a,b,c,!1);e=d[1]}else{let d=a.querySelector(".code-input_autocomplete_testpos"),f=document.createElement("span");for(f.textContent=b.value.substring(0,c),e=document.createElement("span"),e.textContent=".";d.firstChild;)d.removeChild(d.firstChild);d.appendChild(f),d.appendChild(e)}return{top:e.offsetTop-b.scrollTop,left:e.offsetLeft-b.scrollLeft}}updatePopupCallback=function(){}};
|
package/plugins/autodetect.js
CHANGED
|
@@ -13,16 +13,16 @@ codeInput.plugins.Autodetect = class extends codeInput.Plugin {
|
|
|
13
13
|
resultElement.className = ""; // CODE
|
|
14
14
|
resultElement.parentElement.className = ""; // PRE
|
|
15
15
|
}
|
|
16
|
-
/* Get new language class and set `
|
|
16
|
+
/* Get new language class and set `language` attribute */
|
|
17
17
|
afterHighlight(codeInput) {
|
|
18
|
-
let
|
|
19
|
-
let langClass = resultElement.className || resultElement.parentElement.className;
|
|
18
|
+
let langClass = codeInput.codeElement.className || codeInput.preElement.className;
|
|
20
19
|
let lang = langClass.match(/lang(\w|-)*/i)[0]; // Get word starting with lang...; Get outer bracket
|
|
21
20
|
lang = lang.split("-")[1];
|
|
22
21
|
if(lang == "undefined") {
|
|
22
|
+
codeInput.removeAttribute("language");
|
|
23
23
|
codeInput.removeAttribute("lang");
|
|
24
24
|
} else {
|
|
25
|
-
codeInput.setAttribute("
|
|
25
|
+
codeInput.setAttribute("language", lang);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
codeInput.plugins.Autodetect=class extends codeInput.Plugin{constructor(){super([])}beforeHighlight(a){let b=a.codeElement;b.className="",b.parentElement.className=""}afterHighlight(a){let b=a.codeElement
|
|
1
|
+
codeInput.plugins.Autodetect=class extends codeInput.Plugin{constructor(){super([])}beforeHighlight(a){let b=a.codeElement;b.className="",b.parentElement.className=""}afterHighlight(a){let b=a.codeElement.className||a.preElement.className,c=b.match(/lang(\w|-)*/i)[0];c=c.split("-")[1],"undefined"==c?(a.removeAttribute("language"),a.removeAttribute("lang")):a.setAttribute("language",c)}};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* Find functionality matches */
|
|
2
|
+
.code-input_find-and-replace_find-match {
|
|
3
|
+
color: inherit;
|
|
4
|
+
text-shadow: none!important;
|
|
5
|
+
background-color: #ffff00!important;
|
|
6
|
+
}
|
|
7
|
+
.code-input_find-and-replace_find-match-focused, .code-input_find-and-replace_find-match-focused * {
|
|
8
|
+
background-color: #ff8800!important;
|
|
9
|
+
color: black!important;
|
|
10
|
+
}
|
|
11
|
+
.code-input_find-and-replace_start-newline::before {
|
|
12
|
+
content: "⤶";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Find-and-replace dialog */
|
|
16
|
+
|
|
17
|
+
@keyframes code-input_find-and-replace_roll-in {
|
|
18
|
+
0% {opacity: 0; transform: translateY(-34px);}
|
|
19
|
+
100% {opacity: 1; transform: translateY(0px);}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@keyframes code-input_find-and-replace_roll-out {
|
|
23
|
+
0% {opacity: 1;top: 0;}
|
|
24
|
+
100% {opacity: 0;top: -34px;}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.code-input_find-and-replace_dialog {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 0;
|
|
30
|
+
right: 14px;
|
|
31
|
+
padding: 6px;
|
|
32
|
+
padding-top: 8px;
|
|
33
|
+
border: solid 1px #00000044;
|
|
34
|
+
background-color: white;
|
|
35
|
+
border-radius: 6px;
|
|
36
|
+
box-shadow: 0 .2em 1em .2em rgba(0, 0, 0, 0.16);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.code-input_find-and-replace_dialog:not(.code-input_find-and-replace_hidden-dialog) {
|
|
40
|
+
animation: code-input_find-and-replace_roll-in .2s;
|
|
41
|
+
opacity: 1;
|
|
42
|
+
pointer-events: all;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.code-input_find-and-replace_dialog.code-input_find-and-replace_hidden-dialog {
|
|
46
|
+
animation: code-input_find-and-replace_roll-out .2s;
|
|
47
|
+
opacity: 0;
|
|
48
|
+
pointer-events: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.code-input_find-and-replace_dialog input::placeholder {
|
|
52
|
+
font-size: 80%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.code-input_find-and-replace_dialog input {
|
|
56
|
+
position: relative;
|
|
57
|
+
width: 240px; height: 32px; top: -3px;
|
|
58
|
+
font-size: large;
|
|
59
|
+
color: #000000aa;
|
|
60
|
+
border: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.code-input_find-and-replace_dialog input:hover {
|
|
64
|
+
outline: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.code-input_find-and-replace_dialog input.code-input_find-and-replace_error {
|
|
68
|
+
color: #ff0000aa;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.code-input_find-and-replace_dialog button, .code-input_find-and-replace_dialog input[type="checkbox"] {
|
|
72
|
+
display: inline-block;
|
|
73
|
+
line-height: 24px;
|
|
74
|
+
font-size: 22px;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
appearance: none;
|
|
77
|
+
width: min-content;
|
|
78
|
+
|
|
79
|
+
margin: 5px;
|
|
80
|
+
padding: 5px;
|
|
81
|
+
border: 0;
|
|
82
|
+
background-color: #dddddd;
|
|
83
|
+
|
|
84
|
+
text-align: center;
|
|
85
|
+
color: black;
|
|
86
|
+
vertical-align: top;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.code-input_find-and-replace_dialog input[type="checkbox"].code-input_find-and-replace_case-sensitive-checkbox::before {
|
|
90
|
+
content: "Aa";
|
|
91
|
+
}
|
|
92
|
+
.code-input_find-and-replace_dialog input[type="checkbox"].code-input_find-and-replace_reg-exp-checkbox::before {
|
|
93
|
+
content: ".*";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.code-input_find-and-replace_dialog button:hover, .code-input_find-and-replace_dialog input[type="checkbox"]:hover {
|
|
97
|
+
background-color: #bbbbbb;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.code-input_find-and-replace_dialog input[type="checkbox"]:checked {
|
|
101
|
+
background-color: #222222;
|
|
102
|
+
color: white;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.code-input_find-and-replace_match-description {
|
|
106
|
+
display: block; /* So not on same line as other */
|
|
107
|
+
color: #444444;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.code-input_find-and-replace_dialog details summary, .code-input_find-and-replace_dialog button {
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
.code-input_find-and-replace_dialog button.code-input_find-and-replace_button-hidden {
|
|
116
|
+
opacity: 0;
|
|
117
|
+
pointer-events: none;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Cancel icon */
|
|
121
|
+
.code-input_find-and-replace_dialog span {
|
|
122
|
+
display: block;
|
|
123
|
+
float: right;
|
|
124
|
+
margin: 5px;
|
|
125
|
+
padding: 5px;
|
|
126
|
+
|
|
127
|
+
width: 24px;
|
|
128
|
+
line-height: 24px;
|
|
129
|
+
font-family: system-ui;
|
|
130
|
+
font-size: 22px;
|
|
131
|
+
font-weight: 500;
|
|
132
|
+
text-align: center;
|
|
133
|
+
border-radius: 50%;
|
|
134
|
+
color: black;
|
|
135
|
+
opacity: 0.6;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.code-input_find-and-replace_dialog span:before {
|
|
139
|
+
content: "\00d7";
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.code-input_find-and-replace_dialog span:hover {
|
|
143
|
+
opacity: .8;
|
|
144
|
+
background-color: #00000018;
|
|
145
|
+
}
|