web-firmware-installer-js/dist/base_installer.min.js
2023-03-14 22:02:09 +00:00

12 lines
No EOL
6.9 KiB
JavaScript

"use strict";import{html,render}from"https://unpkg.com/lit-html?module";import{asyncAppend}from"https://unpkg.com/lit-html/directives/async-append?module";import*as esptoolPackage from"https://unpkg.com/esp-web-flasher@5.1.2/dist/web/index.js?module";const ESP_ROM_BAUD=115200;class InstallButton extends HTMLButtonElement{static isSupported="serial"in navigator;static isAllowed=window.isSecureContext;constructor(){super(),this.dialogElements={},this.currentFlow=null,this.currentStep=0,this.currentDialogElement=null,this.port=null,this.espStub=null,this.dialogCssClass="install-dialog",this.connected=this.connectionStates.DISCONNECTED,this.menuTitle="Installer Menu"}init(){this.preloadDialogs()}previousButton={label:"Previous",onClick:this.prevStep,isEnabled:async()=>0<this.currentStep};nextButton={label:"Next",onClick:this.nextStep,isEnabled:async()=>this.currentStep<this.currentFlow.steps.length-1};closeButton={label:"Close",onClick:async t=>{this.closeDialog()}};defaultButtons=[this.previousButton,this.nextButton];connectionStates={DISCONNECTED:"Connect",CONNECTING:"Connecting...",CONNECTED:"Disconnect"};dialogs={notSupported:{preload:!1,closeable:!0,template:t=>html`
Sorry, <b>Web Serial</b> is not supported on your browser at this time. Browsers we expect to work:
<ul>
<li>Google Chrome 89 (and higher)</li>
<li>Microsoft Edge 89 (and higher)</li>
<li>Opera 75 (and higher)</li>
</ul>
`,buttons:[this.closeButton]},menu:{closeable:!0,template:t=>html`
<p>${this.menuTitle}</p>
<ul class="flow-menu">
${asyncAppend(this.generateMenu((t,e)=>html`<li><a href="#" @click=${this.runFlow.bind(this)} id="${t}">${e.label.replace("[version]",this.releaseVersion)}</a></li>`))}
</ul>`,buttons:[this.closeButton]}};flows={};baudRates=[115200,128e3,153600,230400,460800,921600,15e5,2e6];connectedCallback(){InstallButton.isSupported&&InstallButton.isAllowed?this.toggleAttribute("install-supported",!0):this.toggleAttribute("install-unsupported",!0),this.addEventListener("click",async t=>{t.preventDefault(),InstallButton.isSupported?await this.showMenu():await this.showNotSupported()})}getUrlParams(){var e={};return location.hash&&location.hash.substr(1).split("&").forEach(function(t){e[t.split("=")[0]]=t.split("=")[1]}),e}getUrlParam(t){var e=this.getUrlParams();let s=null;return s=t in e?e[t]:s}async enabledFlowCount(){let t=0;for(var[e,s]of Object.entries(this.flows))await s.isEnabled()&&t++;return t}async*generateMenu(t){0==await this.enabledFlowCount()&&(yield html`<li>No installable options available for this board.</li>`);for(var[e,s]of Object.entries(this.flows))await s.isEnabled()&&(yield t(e,s))}preloadDialogs(){for(var[t,e]of Object.entries(this.dialogs))"preload"in e&&!e.preload||(this.dialogElements[t]=this.getDialogElement(e))}createIdFromLabel(t){return t.replace(/^[^a-z]+|[^\w:.-]+/gi,"")}createDialogElement(t,e){var s=this.querySelector("#cp-installer-"+t);s&&this.remove(s);let i=document.createElement("dialog");i.id=t,i.classList.add(this.dialogCssClass);s=document.createElement("button"),s.href="#",s.classList.add("close-button"),s.addEventListener("click",t=>{t.preventDefault(),i.close()}),i.appendChild(s),t=document.createElement("div");t.classList.add("dialog-body"),i.appendChild(t);let n=this.defaultButtons;return e&&e.buttons&&(n=e.buttons),i.appendChild(this.createNavigation(n)),document.body.appendChild(i),i}createNavigation(t){var e=document.createElement("div");e.classList.add("dialog-navigation");for(const i of t){var s=document.createElement("button");s.innerText=i.label,s.id=this.createIdFromLabel(i.label),s.addEventListener("click",async t=>{t.preventDefault(),await i.onClick.bind(this)()}),s.addEventListener("update",async t=>{"onUpdate"in i&&await i.onUpdate.bind(this)(t),"isEnabled"in i&&(t.target.disabled=!await i.isEnabled.bind(this)())}),e.appendChild(s)}return e}getDialogElement(t,e=!1){s=this.dialogs,i=t;var s,i,n=Object.keys(s).find(t=>s[t]===i);return n?n in this.dialogElements&&!e?this.dialogElements[n]:this.createDialogElement(n,t):null}updateButtons(){if(this.currentDialogElement)for(const t of this.currentDialogElement.querySelectorAll(".dialog-navigation button"))t.dispatchEvent(new Event("update"))}showDialog(t,e={}){var s;this.currentDialogElement&&this.closeDialog(),this.currentDialogElement=this.getDialogElement(t),this.currentDialogElement||console.error("Dialog not found"),this.currentDialogElement&&(s=this.currentDialogElement.querySelector(".dialog-body"),"template"in t&&render(t.template(e),s),"closeable"in t&&t.closeable?this.currentDialogElement.querySelector(".close-button").style.display="block":this.currentDialogElement.querySelector(".close-button").style.display="none",this.defaultButtons,"buttons"in t&&t.buttons,this.updateButtons(),this.currentDialogElement.showModal())}closeDialog(){this.currentDialogElement.close(),this.currentDialogElement=null}errorMsg(t){t=this.stripHtml(t),console.error(t),this.showError(t)}logMsg(t,e=!1){console.info(this.stripHtml(t)),e&&console.trace()}updateEspConnected(t){Object.values(this.connectionStates).includes(t)&&(this.connected=t,this.updateButtons())}stripHtml(t){var e=document.createElement("div");return e.innerHTML=t,e.textContent||e.innerText||""}formatMacAddr(t){return t.map(t=>t.toString(16).toUpperCase().padStart(2,"0")).join(":")}async disconnect(){this.espStub&&(await espStub.disconnect(),await espStub.port.close(),this.updateUIConnected(this.connectionStates.DISCONNECTED),this.espStub=null)}async runFlow(t){if(t instanceof Event){if(t.preventDefault(),t.stopImmediatePropagation(),!(t.target.id in this.flows))return;t=this.flows[t.target.id]}this.currentFlow=t,this.currentStep=0,await this.currentFlow.steps[this.currentStep].bind(this)()}async nextStep(){this.currentFlow&&this.currentStep<this.currentFlow.steps.length&&(this.currentStep++,await this.currentFlow.steps[this.currentStep].bind(this)())}async prevStep(){this.currentFlow&&0<this.currentStep&&(this.currentStep--,await this.currentFlow.steps[this.currentStep].bind(this)())}async showMenu(){this.showDialog(this.dialogs.menu)}async showNotSupported(){this.showDialog(this.dialogs.notSupported)}async showError(t){this.showDialog(this.dialogs.error,{message:t})}async setBaudRateIfChipSupports(t,e){e!=ESP_ROM_BAUD&&(t==esptoolPackage.CHIP_FAMILY_ESP32?this.logMsg(`ESP32 Chip only works at 115200 instead of the preferred ${e}. Staying at 115200...`):await this.changeBaudRate(e))}async changeBaudRate(t){this.espStub&&this.baudRates.includes(t)&&await this.espStub.setBaudrate(t)}async espHardReset(t=!1){this.espStub&&await this.espStub.hardReset(t)}async espConnect(t){return this.port=await navigator.serial.requestPort(),t.log("Connecting..."),await this.port.open({baudRate:ESP_ROM_BAUD}),t.log("Connected successfully."),new esptoolPackage.ESPLoader(this.port,t)}}export{ESP_ROM_BAUD,InstallButton};