123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 |
- <!--
- Copyright (C) 2024 Richard Hao Cao
- Ebrowser is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- Ebrowser is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
- -->
- <!DOCTYPE html><html><head><meta charset="UTF-8">
- <style>
- html{
- height: 100%;
- overflow: hidden;
- }
- body{
- display: flex;
- flex-direction: column;
- height: 100%;
- margin-top: 1px;
- }
- div.webviews{
- display: flex;
- flex-direction: column;
- flex-grow:1;
- }
- webview{display: none;width:100%;height:100%}
- .curWV{display: inherit !important;}
- .autocomplete-active {
- background-color: DodgerBlue !important;
- color: #ffffff;
- }
- .invis{display: none}
- /*the container must be positioned relative:*/
- .autocomplete {
- position: relative;
- display: inline-block;
- width:100%;
- }
- .autocomplete-items {
- position: absolute;
- border: 1px solid #d4d4d4;
- border-bottom: none;
- border-top: none;
- z-index: 99;
- /*position the autocomplete items to be the same width as the container:*/
- top: 100%;
- left: 0;
- right: 0;
- }
- .autocomplete-items div {
- cursor: pointer;
- background-color: #fff;
- }
- .autocomplete-items div:hover {
- background-color: #e9e9e9;
- }
- </style>
- <script>
- const { ipcRenderer } = require('electron');
- const fs = require('fs');
- const path = require('path');
- const readline = require('readline');
- var iTab = 0;
- var tabs;
- var engines = {};
- var mapKeys = {};
- var closedUrls = [];
- var autocStrArray = [];
- var defaultSE = "https://www.bing.com/search?q=%s";
- var historyFile = path.join(__dirname,'history.rec');
- var bHistory = false;
- var bQueryHistory = false;
- let sitecssP = path.join(__dirname,"sitecss");
- let sitejsP = path.join(__dirname,"sitejs");
- let gjsA = [];
- let gcssA = [];
- let gcssJSA = [];
- var bDomainJS = fs.existsSync(sitejsP);
- var bDomainCSS = fs.existsSync(sitecssP);
- var autocMode = 0; //0 for substring, 1 for startsWith
- const BML_head = "(async ()=>{let d=document;async function _loadJs(u){var a=d.createElement('script');a.type='text/javascript';a.async=false;a.src=u;d.body.appendChild(a);await new Promise(resolve=>a.onload=resolve)}";
- const BML_tail = "})()";
- const BML_md = BML_head + "await _loadJs('https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js');let b=d.body;b.innerHTML=marked.parse(b.textContent)})()";
- let lastKeys;
- let lastKeys_millis = 0;
- var lastVal;
- fs.readFile(path.join(__dirname,'search.json'), 'utf8', (err, jsonString) => {
- if (err) {
- coloncommand(":js fetch2file(repositoryurl,'search.json')");
- return;
- }
- initSearchEngines(jsonString,false);
- });
- fs.readFile(path.join(__dirname,'mapkeys.json'), 'utf8', (err, jsonStr) => {
- if (err) {
- coloncommand(":js fetch2file(repositoryurl,'mapkeys.json')");
- return;
- }
- try {
- mapKeys = JSON.parse(jsonStr);
- }catch(e){}
- });
- appendAutoc_rec(path.join(__dirname,'default.autoc'),null);
- appendAutoc_rec(path.join(__dirname,'bookmark.rec'),' ');
- function initSearchEngines(jsonStr){
- try{
- engines=JSON.parse(jsonStr);
- let match = jsonStr.match(/:"([^"]+)"/);
- if(match) defaultSE=match[1];
- }catch(e){}
- }
- function save(filePath, u8array){
- //alert(Object.prototype.toString.call(u8array))
- fs.writeFile (filePath, u8array, (err) => {
- if (err) {
- console.error (err);
- return;
- }
- });
- }
- function print2PDF(filePath, options){
- tabs.children[iTab].printToPDF(options)
- .then(u8array=>save(filePath,u8array));
- }
- function bookmark(argrest){//b [filenamestem] :bookmark
- let bmFileName = "bookmark.rec";
- let tab = tabs.children[iTab];
- let url = tab.getURL();
- if(argrest)
- bmFileName = argrest+".rec";
- let title = tab.getTitle();
- let line = title + " " + url + "\n";
- fs.appendFile(path.join(__dirname,bmFileName), line, (err)=>{});
- }
- function switchTab(i){
- let tab = tabs.children[iTab];
- if(document.activeElement == tab) tab.blur();
- tab.classList.remove('curWV');
- iTab = i;
- tabs.children[iTab].classList.add('curWV');
- }
- async function loadJSFile(tab,jsF){
- try {
- let js = await fs.promises.readFile(jsF,'utf8');
- tab.executeJavaScript(js,false);
- }catch(e){}
- }
- async function loadCSSFile(tab,jsF){
- try {
- let js = await fs.promises.readFile(jsF,'utf8');
- tab.insertCSS(css);
- }catch(e){}
- }
- function cbStartLoading(e){
- if(!bDomainCSS) return;
- let tab = e.target;
- let domain;
- try{
- domain = new URL(tab.getURL()).hostname;
- }catch(e){return;}
- let jsF = path.join(sitecssP, domain+".js");
- loadJSFile(tab,jsF);
- jsF = path.join(sitecssP, domain+".css");
- loadCSSFile(tab,jsF);
- gcssA.forEach((fname)=>{
- jsF = path.join(__dirname, fname);
- loadCSSFile(tab,jsF);
- });
- gcssJSA.forEach((fname)=>{
- jsF = path.join(__dirname, fname);
- loadJSFile(tab,jsF);
- });
- }
- function cbNavigate(e){
- let url = e.url;
- if(58===url.charCodeAt(1)){
- e.preventDefault();
- if(confirm("Proceed to execute risky operations: "+url))
- internalLink(url);
- else
- document.forms[0].q.value = url;
- }
- }
- function cbFinishLoad(e){
- let tab = e.target;
- let url = tab.getURL();
- if(bHistory){
- let histItem = tab.getTitle()+" "+url+"\n";
- fs.appendFile(historyFile, histItem, (err) => {});
- }
- let js = tab.dataset.jsonce;
- if(js){
- tab.dataset.jsonce = null;
- tab.executeJavaScript(js,false);
- }
- if(bDomainJS){
- let domain = new URL(url).hostname;
- let jsF = path.join(sitejsP, domain+".js");
- loadJSFile(tab,jsF);
- }
- gjsA.forEach((fname)=>{
- let jsF = path.join(__dirname, fname);
- loadJSFile(tab,jsF);
- });
- }
- function initTab(tab){
- tab.allowpopups = true;
- tab.addEventListener('did-finish-load',cbFinishLoad);
- tab.addEventListener('did-start-loading',cbStartLoading);
- tab.addEventListener('will-navigate',cbNavigate);
- }
- function newTab(){
- var tab = document.createElement('webview');
- initTab(tab);
- tabs.appendChild(tab);
- }
- function tabInc(num){
- let nTabs = tabs.children.length;
- if(nTabs<2) return;
- let i = iTab +num;
- if(i>=nTabs) i=0;
- switchTab(i);
- }
- function tabDec(num){
- let nTabs = tabs.children.length;
- if(nTabs<2) return;
- let i = iTab +num;
- if(i<0) i=nTabs-1;
- switchTab(i);
- }
- function tabClose(){
- let nTabs = tabs.children.length;
- if(nTabs<2) return "";//no remain tab
- let tab = tabs.children[iTab];
- closedUrls.push(tab.getURL());
- if(document.activeElement == tab) tab.blur();
- tabs.removeChild(tab);
- nTabs--;
- if(iTab>=nTabs) iTab=iTab-1;
- tabs.children[iTab].classList.add('curWV');
- return getWinTitle();
- }
- function tabJS(js){
- tabs.children[iTab].executeJavaScript(js,false);
- }
- function getWinTitle(){
- let t=tabs.children[iTab];
- let title = (iTab+1) + '/' + tabs.children.length;
- try{title=title+' '+t.getTitle()+' '+t.getURL()}catch(e){}
- return title
- }
- async function appendAutoc_rec(filename, delimit){
- try{
- const readInterface = readline.createInterface ({
- input: fs.createReadStream (filename, 'utf8'),
- });
- for await (const line of readInterface) {
- let iS;
- if(delimit && (iS=line.lastIndexOf(delimit))>0){
- autocStrArray.push(line.substring(iS+1));
- }else
- autocStrArray.push(line);
- }
- lastVal = null; //trigger full search
- }catch(e){return;}
- }
- function keyPress(e){
- var inputE = document.forms[0].q;
- if (e.altKey||e.metaKey)
- return;
- var key = e.key;
- if(e.ctrlKey){
- switch(key){
- case "Home":
- tabJS("window.scrollTo(0,0)");
- return;
- case "End":
- tabJS("window.scrollTo(0,document.body.scrollHeight)");
- return;
- }
- return;
- }
- SCROLL: do {
- let h = -32;
- switch(key){
- case " ":
- if(inputE === document.activeElement) return;
- if(e.shiftKey){
- h = -3*document.documentElement.clientHeight/4;
- break;
- }
- case "PageDown":
- h = 3*document.documentElement.clientHeight/4;
- break;
- case "PageUp":
- h = -3*document.documentElement.clientHeight/4;
- break;
- case "ArrowDown":
- h = 32;
- case "ArrowUp":
- if(inputE === document.activeElement &&
- 0!==inputE.nextElementSibling.children.length)
- return;
- break;
- default:
- break SCROLL;
- }
- let js = `javascript:window.scrollBy(0,${h})`;
- tabJS(js);
- return;
- }while(false);
- if(inputE === document.activeElement){
- if (9===e.keyCode){
- e.preventDefault();
- tabs.children[iTab].focus();
- }
- return;
- }
- var curMillis = Date.now();
- if(curMillis-lastKeys_millis>1000)
- lastKeys = null;
- lastKeys_millis = curMillis;
- switch (key) {
- case "!":
- case "/":
- case ":":
- inputE.value = "";
- inputE.focus();
- lastKeys = null;
- return;
- }
- lastKeys = !lastKeys ? key : lastKeys + key;
- let cmds = mapKeys[lastKeys];
- if(cmds){//try to run cmds
- let keyLen = lastKeys.length;
- setTimeout(()=>{
- if(lastKeys.length != keyLen) return;
- lastKeys = null;
- handleQueries(cmds);
- }, 500);
- }
- }
- function getQ(){return document.forms[0].q.value;}
- function bang(query, iSpace){
- let se=defaultSE;
- {
- let name = query.slice(0,iSpace);
- let engine = engines[name];
- if(engine){
- se = engine;
- query = query.substring(iSpace+1);
- }
- }
- return se.replace('%s',query);
- }
- function coloncommand(q){
- ipcRenderer.send("command",q);
- }
- function coloncommand_render(cmd){
- const delimiter = /\s+/;
- let arg0;
- let argrest = null;
- const match = delimiter.exec(cmd);
- if(match){
- const sIndex = match.index;
- const eIndex = sIndex + match[0].length;
- arg0 = cmd.substring(1,sIndex);
- argrest = cmd.substring(eIndex);
- }else
- arg0 = cmd.substring(1);
- switch(arg0){
- case "ac":
- autoc(argrest);
- return;
- case "b":
- bookmark(argrest);
- return;
- case "bjs":
- eval(argrest);
- return;
- case "bml":
- bangcommand(argrest,0);
- return;
- case "pdf":
- savePdf(argrest);
- return;
- }
- }
- function autoc(argrest){
- if(!argrest) return;
- let fpath = path.join(__dirname,argrest);
- let fname = fpath;
- let delimit = ' ';
- if (!fs.existsSync(fname)){
- fname = fpath+".autoc";
- if (!fs.existsSync(fname))
- fname = fpath+".rec";
- else
- delimit = null;
- }
- appendAutoc_rec(fname,delimit);
- }
- function bml(args){
- if(2!=args.length) return;
- let filename = args[1]+".js";
- fs.readFile(path.join(__dirname,filename), 'utf8', (err,str) => {
- if (err) return;
- tabs.children[iTab].executeJavaScript(str,false);
- });
- }
- function savePdf(argrest){
- let filename = "ebrowser.pdf";
- let options = {};
- if(argrest){
- let c0 = argrest.charCodeAt(0);
- let iOpts = 0;
- if(123!=c0){//not '{' options then it is filename
- let iS = argrest.indexOf(' ');
- let filestem = argrest;
- if(iS>0) {
- filestem = argrest.substring(0,iS);
- iOpts = iS+1;
- }else
- iOpts = argrest.length;
- filename = filestem + ".pdf";
- }
- if(argrest.length>iOpts){//:Pdf [filename] {...}
- if(iOpts+2==argrest.length){// '{}'
- let width = document.body.clientWidth/96;
- tabs.children[iTab].executeJavaScript("document.documentElement.scrollHeight",
- false).then((h)=>{
- let opts = {
- printBackground:true,
- pageSize:{width:width,height:h/96}};
- print2PDF(filename,opts);
- });
- return;
- }else{
- try {
- options = JSON.parse(argrest.substring(iOpts));
- }catch(e){};
- }
- }
- }
- print2PDF(filename,options);
- }
- function bangcommand(q,offset){
- let iS = q.indexOf(' ',offset);
- if(iS<0) iS=q.length;
- let fname = q.substring(offset,iS);
- let fpath = path.join(__dirname,fname+'.js');
- if (fs.existsSync(fpath)) {
- fs.readFile(fpath, 'utf8',(err, js)=>{
- if (err) {
- console.log(err);
- return;
- }
- const prefix = "(function(){";
- const postfix = "})(`";
- const end ="`)";
- const fjs = `${prefix}${js}${postfix}${q}${end}`;
- eval(fjs);
- });
- }
- }
- function recQueryHistory(q){
- if(bQueryHistory)
- fs.appendFile(path.join(__dirname,"history.autoc"), q, (err)=>{});
- }
- function handleQuery(q){
- if(q.length>1){
- let c0=q.charCodeAt(0);
- let c1=q.charCodeAt(1);
- switch(c0){
- case 33://"!"
- if(33!=c1)
- coloncommand(q);
- else
- bangcommand(q,2);
- recQueryHistory(q);
- return;
- case 47://"/"
- tabs.children[iTab].findInPage(q.substring(1));
- return;
- case 58://':'
- if(c1>98 && 112!=c1)
- coloncommand(q);
- else
- coloncommand_render(q);
- recQueryHistory(q);
- return;
- }
- if(58===c1){
- internalLink(q);
- return;
- }
- }
- var url=q;
- NOREC: do{
- do {
- if(q.length>12){
- let c6 = q.charCodeAt(6);
- if(47===c6){// '/'
- let c5 = q.charCodeAt(5);
- if(47===c5 && 58===q.charCodeAt(4))//http/file urls
- break NOREC;
- if(58===c5 && 47===q.charCodeAt(7))//https://
- break NOREC;
- }else if(q.startsWith("javascript:")){
- tabs.children[iTab].executeJavaScript(q.substring(11),false);
- recQueryHistory(q);
- return;
- }else if(q.startsWith("view-source:")) break;
- else if(q.startsWith("data:")) break;
- }
- let iS = q.indexOf(' ');
- if(iS<0){
- if(q.length>5 && 58===q.charCodeAt(5)){// about:
- break;
- }
- if(q.indexOf('.')>0){
- url = 'https://'+q;
- break NOREC;
- }
- url = defaultSE.replace('%s',q);
- break;
- }
- url = bang(q, iS);
- if(58===url.charCodeAt(1)){
- internalLink(url);
- recQueryHistory(q);
- return;
- }
- }while(false);
- recQueryHistory(q);
- }while(false);
- tabs.children[iTab].src=url;
- }
- function internalLink(url){
- let cmd = url.charCodeAt(2);
- let subcmd = url.charCodeAt(3);
- switch(cmd){
- case 48://'0' i:0
- {
- let iColon = url.indexOf(':',5);
- let name = decodeURIComponent(url.slice(4,iColon));
- let rurl = url.substring(iColon+1);
- switch(subcmd){
- case 47://'/' i:0/
- if(106===url.charCodeAt(4) && 115===url.charCodeAt(5) && 47===url.charCodeAt(6)){
- //i:0/js/xx:[url]
- let fname = name;
- let pname = path.join(__dirname,fname);
- if(fs.existsSync(pname)){
- (async ()=>{
- try {
- let js = await fs.promises.readFile(pname,'utf8');
- let t=tabs.children[iTab];
- t.dataset.jsonce=js;
- t.src = rurl;
- }catch(e){}
- })();
- }
- }
- return;
- case 48: //i:00
- {
- let endS;
- let is = url.indexOf('%s',iColon+1);
- if(is<0)
- endS = '%s"\n';
- else
- endS = '"\n';
- let pname = path.join(__dirname,"search.json");
- let str = '"'+name+'":"'+rurl+
- endS;
- jsonAppend(pname,125,str);
- }
- return;
- case 49: //i:01
- {
- let pname = path.join(__dirname,"menu.json");
- let str = '"'+name+'",":bjs handleQuery(`'+
- rurl+'${tabs.children[iTab].getURL()}`)"\n';
- jsonAppend(pname,93,str);
- }
- return;
- case 50: //i:02
- {
- let pname = path.join(__dirname,"uas.json");
- let str = '"'+name+'":"'+rurl+'"\n';
- jsonAppend(pname,125,str);
- }
- return;
- default:
- }
- }
- return;
- case 56: //i:8
- switch(subcmd){
- case 100: //i:8d[url] to download
- tabs.children[iTab].downloadURL(url.substring(4));
- return;
- }
- return;
- case 112: //i:p[url]#[querystring] for http POST
- {
- let iQ = url.indexOf('#',12);
- let data;
- let rurl;
- let headers;
- switch(subcmd){
- case 49: //i:p1
- {
- if(iQ>4) {
- rurl = url.substring(4,iQ);
- data = [{
- type: 'rawData',
- bytes: Buffer.from(url.substring(iQ+1))
- }];
- }else{
- rurl = url.substring(4);
- data = [];
- }
- headers = 'Content-Type: application/x-www-form-urlencoded';
- break;
- }
- case 50: //i:p2[url]#[filePath] post request with local file
- rurl = url.substring(4,iQ);
- data = [{type: 'file', filePath:url.substring(iQ+1)}];
- headers = 'Content-Type: multipart/form-data';
- break;
- default:
- return;
- }
- tabs.children[iTab].loadURL(rurl,{postData:data,extraHeaders:headers});
- return;
- }
- case 113: //i:q for multiple queries
- handleQueries(url.substring(3));
- return;
- }
- }
- function handleQueries(cmds){
- for(var cmd of cmds.split("\n"))
- handleQuery(cmd);
- }
- async function jsonAppend(filePath, charcode, str){
- let fd;
- try{
- fd = await fs.promises.open(filePath, 'r+');
- }catch(e){
- try {
- fd = await fs.promises.open(filePath, 'w+');
- }catch(e1){return}
- }
- try{
- const stats = await fd.stat();
- const fileSize = stats.size;
- const buffer = Buffer.alloc(1);
- let position = fileSize-1;
- while (position >= 0) {
- await fd.read(buffer, 0, 1, position);
- if (buffer[0] === charcode) break;
- position--;
- }
- let endS = String.fromCharCode(charcode);
- if(position<0){//re-write whole file
- str = String.fromCharCode(charcode-2)+str+endS;
- position = 0;
- }else
- str = ","+str+endS;
- await fd.truncate(position);
- const buf = Buffer.from(str);
- await fd.write(buf, 0, buf.length, position);
- await fd.close();
- }catch(e){console.log(e)}
- }
- function autocomplete(inp,container,arr) {
- var currentFocus;
- function clickItem(e){inp.value = arr[e.target.dataset.index];}
- function appendElement(el,dataindex){
- el.dataset.index = dataindex;
- el.addEventListener("click", clickItem);
- container.appendChild(el);
- }
- function itemInnerHTML(b,str,val,iStr){
- b.innerHTML = str.substr(0,iStr);
- b.innerHTML += "<strong>" + str.substr(iStr, val.length) + "</strong>";
- b.innerHTML += str.substr(iStr+val.length);
- }
- inp.addEventListener("input", function(e) {
- const MAXITEMS = 30;
- var b, i, val = this.value;
- if (!val) { return false;}
- currentFocus = -1;
- let items = container.children;
- let iBase = 0;
- let lastV = lastVal;
- lastVal = val;
- if(val.startsWith(lastV)){
- let itemsLen = items.length;
- if(itemsLen<=0) return;
- i = itemsLen -1;
- iBase = items[i].dataset.index +1;
- switch(autocMode){
- case 0:
- for (; i>=0; i--) {
- b = items[i];
- let str = arr[b.dataset.index];
- let iStr = str.indexOf(val);
- if(iStr<0) {
- b.parentNode.removeChild(b);
- continue;
- }
- itemInnerHTML(b,str,val,iStr);
- }
- break;
- case 1:
- for (; i>=0; i--) {
- b = items[i];
- let str = arr[b.dataset.index];
- let oLen = lastval.length;
- if(!str.startsWith(val.substring(oLen),oLen)) {
- b.parentNode.removeChild(b);
- continue;
- }
- itemInnerHTML(b,str,val,0);
- }
- break;
- }
- if(itemsLen<MAXITEMS)
- return;
- else
- if(container.children.length>=MAXITEMS) return;
- }else
- closeAllLists();
- i = iBase;
- switch(autocMode){
- case 0:
- for (; i < arr.length; i++) {
- let iStr = arr[i].indexOf(val);
- if(iStr<0) continue;
- {
- b = document.createElement("DIV");
- itemInnerHTML(b,arr[i],val,iStr);
- appendElement(b,i);
- if(container.children.length>=MAXITEMS) break;
- }
- }
- return;
- case 1://startsWith
- for (; i < arr.length; i++) {
- if (arr[i].startsWith(val)) {
- b = document.createElement("DIV");
- itemInnerHTML(b,arr[i],val,0);
- appendElement(b,i);
- if(container.children.length>=MAXITEMS) break;
- }
- }
- }
- });
- inp.addEventListener("keydown", function(e) {
- var x = container.getElementsByTagName("div");
- if (0===x.length) return false;
- if (e.keyCode == 40) {//downarrow
- currentFocus++;
- addActive(x);
- } else if (e.keyCode == 38) { //up
- currentFocus--;
- addActive(x);
- } else if (e.keyCode == 13) {
- if (currentFocus > -1) {
- e.preventDefault();
- if (x) x[currentFocus].click();
- currentFocus = -1;
- }
- closeAllLists();
- lastVal = null;
- }
- });
- function addActive(x) {
- removeActive(x);
- if (currentFocus >= x.length) currentFocus = 0;
- if (currentFocus < 0) currentFocus = (x.length - 1);
- x[currentFocus].classList.add("autocomplete-active");
- }
- function removeActive(x) {
- for (var i = 0; i < x.length; i++) {
- x[i].classList.remove("autocomplete-active");
- }
- }
- function closeAllLists() {
- container.innerHTML = '';
- }
- inp.addEventListener("blur", function () {
- setTimeout(()=>container.classList.add("invis"),200);
- });
- inp.addEventListener("focus", function () {
- container.classList.remove("invis");
- });
- }
- </script>
- </head>
- <body>
- <form class="autocomplete" autocomplete="off" action="javascript:handleQuery(getQ())">
- <input type="text" name=q style="width:100%" autofocus>
- <div class="autocomplete-items"></div>
- </form>
- <div class="webviews">
- <webview class="curWV" allowpopups></webview>
- </div>
- <script>
- tabs = document.body.children[1];
- initTab(tabs.children[0]);
- {
- let inp = document.forms[0].q;
- autocomplete(inp,inp.nextElementSibling,autocStrArray);
- }
- document.addEventListener('keydown', keyPress);
- </script>
- </body></html>
|