ebrowser to use alt+<- / -> for page backward/forward

This commit is contained in:
James Feng Cao 2024-06-24 09:58:02 +08:00
parent 052cb9dad1
commit d28fe3eed2
8 changed files with 191 additions and 31 deletions

View file

@ -41,8 +41,8 @@ Mirror urls could be used like ":update https://uwebzh.netlify.app/misc/ebrowser
- CTRL+TAB: switch to next tab - CTRL+TAB: switch to next tab
- CTRL+SHIFT+TAB: switch to previous tab - CTRL+SHIFT+TAB: switch to previous tab
- CTRL+W: close Tab - CTRL+W: close Tab
- CTRL+<-: go backward - ALT+<-: go backward
- CTRL+->: go forward - ALT+->: go forward
- CTRL+SHIFT+R: enable global redirection ("gredirect.json") - CTRL+SHIFT+R: enable global redirection ("gredirect.json")
- CTRL+R: disable global redirection - CTRL+R: disable global redirection
- ESC: remove focus. similar to vi normal mode. - ESC: remove focus. similar to vi normal mode.
@ -64,6 +64,7 @@ Mirror urls could be used like ":update https://uwebzh.netlify.app/misc/ebrowser
- {[options](https://www.electronjs.org/docs/latest/api/session#sescleardataoptions)} - {[options](https://www.electronjs.org/docs/latest/api/session#sescleardataoptions)}
- ext [extension path]: load unpacked Chrome extension. - ext [extension path]: load unpacked Chrome extension.
- gr [gredirect index]: global redirection with corresponding index. Use the first global redirection url if no argument. Disable global redirection with any index out of the range. - gr [gredirect index]: global redirection with corresponding index. Use the first global redirection url if no argument. Disable global redirection with any index out of the range.
- js [js code] : execute JS code at OS level. Note: "javascript:..." is special url and thus works in the current web page, while ":js ..." commands can do any OS operations.
- nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection. - nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection.
- nh/uh for No/Use url history. - nh/uh for No/Use url history.
- nj/uj for No/Use external Javascript files. - nj/uj for No/Use external Javascript files.
@ -74,7 +75,7 @@ Mirror urls could be used like ":update https://uwebzh.netlify.app/misc/ebrowser
- update [updateurl] : update the app. updateurl is optional. - update [updateurl] : update the app. updateurl is optional.
- pdf [filename w/o extension] {[options](https://www.electronjs.org/docs/latest/api/web-contents#contentsprinttopdfoptions)} : print to PDF file. All arguments are optional; empty option "{}" to capture long screenshot as vector graphics. - pdf [filename w/o extension] {[options](https://www.electronjs.org/docs/latest/api/web-contents#contentsprinttopdfoptions)} : print to PDF file. All arguments are optional; empty option "{}" to capture long screenshot as vector graphics.
- "!" address bar commands - "!" address bar commands
"!xx ..." evaluates "xx.js" with the whole address bar text as arguments[0]. "!xx ..." evaluates "xx.js" with the whole text as arguments[0].
#### Commands in no-focus mode (this mode is similar to vi Normal mode) #### Commands in no-focus mode (this mode is similar to vi Normal mode)
Pressing "ESC" to enter no-focus mode if not sure. Pressing "ESC" to enter no-focus mode if not sure.
@ -94,6 +95,11 @@ The other commands are defined in "mapkeys.json", which will map keys to address
- "proxy.json": name-[ProxyConfig](https://www.electronjs.org/docs/latest/api/structures/proxy-config) pairs - "proxy.json": name-[ProxyConfig](https://www.electronjs.org/docs/latest/api/structures/proxy-config) pairs
- "uas.json" : name-useragent pairs - "uas.json" : name-useragent pairs
#### Javascript at three levels
- Web page: urls like "javascript:" or bookmarklet command ":bml" run in web page.
- Browser (or renderer process) : "!xx" evaluates "xx.js", which could manipulate address bar etc.
- OS level (or main process) : ":js" to execute the following js code with all OS APIs available.
#### New usages #### New usages
- Vector designing with web tech to replace Adobe Illustrator/Inkscape. - Vector designing with web tech to replace Adobe Illustrator/Inkscape.
- Design with web tech. - Design with web tech.

View file

@ -79,8 +79,8 @@ npm install ebrowser
<li>CTRL+TAB: switch to next tab</li> <li>CTRL+TAB: switch to next tab</li>
<li>CTRL+SHIFT+TAB: switch to previous tab</li> <li>CTRL+SHIFT+TAB: switch to previous tab</li>
<li>CTRL+W: close Tab</li> <li>CTRL+W: close Tab</li>
<li>CTRL+&lt;-: go backward</li> <li>ALT+&lt;-: go backward</li>
<li>CTRL+-&gt;: go forward</li> <li>ALT+-&gt;: go forward</li>
<li>CTRL+SHIFT+R: enable global redirection (&quot;gredirect.json&quot;)</li> <li>CTRL+SHIFT+R: enable global redirection (&quot;gredirect.json&quot;)</li>
<li>CTRL+R: disable global redirection</li> <li>CTRL+R: disable global redirection</li>
<li>ESC: remove focus. similar to vi normal mode.</li> <li>ESC: remove focus. similar to vi normal mode.</li>
@ -107,6 +107,7 @@ npm install ebrowser
</li> </li>
<li>ext [extension path]: load unpacked Chrome extension.</li> <li>ext [extension path]: load unpacked Chrome extension.</li>
<li>gr [gredirect index]: global redirection with corresponding index. Use the first global redirection url if no argument. Disable global redirection with any index out of the range.</li> <li>gr [gredirect index]: global redirection with corresponding index. Use the first global redirection url if no argument. Disable global redirection with any index out of the range.</li>
<li>js [js code] : execute JS code at OS level. Note: &quot;javascript:...&quot; is special url and thus works in the current web page, while &quot;:js ...&quot; commands can do any OS operations.</li>
<li>nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection.</li> <li>nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection.</li>
<li>nh/uh for No/Use url history.</li> <li>nh/uh for No/Use url history.</li>
<li>nj/uj for No/Use external Javascript files.</li> <li>nj/uj for No/Use external Javascript files.</li>
@ -119,7 +120,7 @@ npm install ebrowser
</ul> </ul>
</li> </li>
<li>&quot;!&quot; address bar commands<br> <li>&quot;!&quot; address bar commands<br>
&quot;!xx ...&quot; evaluates &quot;xx.js&quot; with the whole address bar text as arguments[0].</li> &quot;!xx ...&quot; evaluates &quot;xx.js&quot; with the whole text as arguments[0].</li>
</ul> </ul>
<h4 id="commands-in-no-focus-mode-this-mode-is-similar-to-vi-normal-mode">Commands in no-focus mode (this mode is similar to vi Normal mode)</h4> <h4 id="commands-in-no-focus-mode-this-mode-is-similar-to-vi-normal-mode">Commands in no-focus mode (this mode is similar to vi Normal mode)</h4>
<p>Pressing &quot;ESC&quot; to enter no-focus mode if not sure.</p> <p>Pressing &quot;ESC&quot; to enter no-focus mode if not sure.</p>
@ -140,6 +141,12 @@ npm install ebrowser
<li>&quot;proxy.json&quot;: name-<a href="https://www.electronjs.org/docs/latest/api/structures/proxy-config">ProxyConfig</a> pairs</li> <li>&quot;proxy.json&quot;: name-<a href="https://www.electronjs.org/docs/latest/api/structures/proxy-config">ProxyConfig</a> pairs</li>
<li>&quot;uas.json&quot; : name-useragent pairs</li> <li>&quot;uas.json&quot; : name-useragent pairs</li>
</ul> </ul>
<h4 id="javascript-at-three-levels">Javascript at three levels</h4>
<ul>
<li>Web page: urls like &quot;javascript:&quot; or bookmarklet command &quot;:bml&quot; run in web page.</li>
<li>Browser (or renderer process) : &quot;!xx&quot; evaluates &quot;xx.js&quot;, which could manipulate address bar etc.</li>
<li>OS level (or main process) : &quot;:js&quot; to execute the following js code with all OS APIs available.</li>
</ul>
<h4 id="new-usages">New usages</h4> <h4 id="new-usages">New usages</h4>
<ul> <ul>
<li> <li>
@ -166,7 +173,7 @@ npm install ebrowser
<p>You can copy or modify the code/program under the terms of the GPL3.0 or later versions.</p> <p>You can copy or modify the code/program under the terms of the GPL3.0 or later versions.</p>
</div> </div>
<p>Last Modified: 19 June 2024<br> <p>Last Modified: 24 June 2024<br>
<br> <br>
<pre></pre> <pre></pre>
</p> </p>

View file

@ -6,7 +6,7 @@
<description>Recent content on uweb browser: unlimited power</description> <description>Recent content on uweb browser: unlimited power</description>
<generator>Hugo</generator> <generator>Hugo</generator>
<language>en</language> <language>en</language>
<lastBuildDate>Wed, 19 Jun 2024 09:41:18 +0800</lastBuildDate> <lastBuildDate>Mon, 24 Jun 2024 09:46:43 +0800</lastBuildDate>
<atom:link href="/en/index.xml" rel="self" type="application/rss+xml" /> <atom:link href="/en/index.xml" rel="self" type="application/rss+xml" />
<item> <item>
<title>Text selection/processing</title> <title>Text selection/processing</title>

View file

@ -71,7 +71,7 @@
/> />
</url><url> </url><url>
<loc>/en/</loc> <loc>/en/</loc>
<lastmod>2024-06-19T09:41:18+08:00</lastmod> <lastmod>2024-06-24T09:46:43+08:00</lastmod>
<xhtml:link <xhtml:link
rel="alternate" rel="alternate"
hreflang="zh" hreflang="zh"
@ -508,7 +508,7 @@
/> />
</url><url> </url><url>
<loc>/en/ebrowserreadme/</loc> <loc>/en/ebrowserreadme/</loc>
<lastmod>2024-06-19T09:41:18+08:00</lastmod> <lastmod>2024-06-24T09:46:43+08:00</lastmod>
</url><url> </url><url>
<loc>/en/mirrors/</loc> <loc>/en/mirrors/</loc>
<lastmod>2024-06-18T23:17:17+08:00</lastmod> <lastmod>2024-06-18T23:17:17+08:00</lastmod>
@ -539,7 +539,7 @@
/> />
</url><url> </url><url>
<loc>/en/unlist/</loc> <loc>/en/unlist/</loc>
<lastmod>2024-06-19T09:41:18+08:00</lastmod> <lastmod>2024-06-24T09:46:43+08:00</lastmod>
<xhtml:link <xhtml:link
rel="alternate" rel="alternate"
hreflang="zh" hreflang="zh"

View file

@ -1,5 +1,10 @@
<!-- <!--
Copyright (C) 2024 Richard Hao Cao 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"> <!DOCTYPE html><html><head><meta charset="UTF-8">
<style> <style>
@ -20,6 +25,34 @@ Copyright (C) 2024 Richard Hao Cao
} }
webview{display: none;width:100%;height:100%} webview{display: none;width:100%;height:100%}
.curWV{display: inherit !important;} .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;
}
.autocomplete-items div:hover {
background-color: #e9e9e9;
}
</style> </style>
<script> <script>
const fs = require('fs'); const fs = require('fs');
@ -30,7 +63,10 @@ Copyright (C) 2024 Richard Hao Cao
var engines = {}; var engines = {};
var mapKeys = {}; var mapKeys = {};
var closedUrls = []; var closedUrls = [];
var autocStrArray = [];
var defaultSE = "https://www.bing.com/search?q=%s"; var defaultSE = "https://www.bing.com/search?q=%s";
var bQueryHistory = false;
var autocMode = 0; //0 for substring, 1 for startsWith
let lastKeys; let lastKeys;
let lastKeys_millis = 0; let lastKeys_millis = 0;
@ -134,14 +170,11 @@ Copyright (C) 2024 Richard Hao Cao
}); });
for await (const line of readInterface) { for await (const line of readInterface) {
let opt = document.createElement('option');
let iS; let iS;
if(delimit && (iS=line.lastIndexOf(delimit))>0){ if(delimit && (iS=line.lastIndexOf(delimit))>0){
opt.value = line.substring(iS+1); autocStrArray.push(line.substring(iS+1));
opt.textContent = line.substring(0,iS);
}else }else
opt.value = line; autocStrArray.push(line);
document.forms[0].children[0].appendChild(opt);
} }
}catch(e){return;} }catch(e){return;}
} }
@ -171,9 +204,11 @@ Copyright (C) 2024 Richard Hao Cao
tabs.children[iTab].src = "javascript:window.scrollBy(0,-3*document.documentElement.clientHeight/4)"; tabs.children[iTab].src = "javascript:window.scrollBy(0,-3*document.documentElement.clientHeight/4)";
return; return;
case "ArrowDown": case "ArrowDown":
if(inputE !== document.activeElement || 0==inputE.nextElementSibling.children.length)
tabs.children[iTab].src="javascript:window.scrollBy(0,32)"; tabs.children[iTab].src="javascript:window.scrollBy(0,32)";
return; return;
case "ArrowUp": case "ArrowUp":
if(inputE !== document.activeElement || 0==inputE.nextElementSibling.children.length)
tabs.children[iTab].src="javascript:window.scrollBy(0,-32)"; tabs.children[iTab].src="javascript:window.scrollBy(0,-32)";
return; return;
@ -183,7 +218,6 @@ Copyright (C) 2024 Richard Hao Cao
} }
return; return;
} }
if(1!=key.length) return;
var curMillis = Date.now(); var curMillis = Date.now();
if(curMillis-lastKeys_millis>1000) if(curMillis-lastKeys_millis>1000)
lastKeys = null; lastKeys = null;
@ -246,7 +280,17 @@ Copyright (C) 2024 Richard Hao Cao
} }
function autoc(args){ function autoc(args){
if(2!=args.length) return; if(2!=args.length) return;
appendAutoc_rec(path.join(__dirname,args[1]+".rec"),' '); let fpath = path.join(__dirname,args[1]);
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){ function bml(args){
if(2!=args.length) return; if(2!=args.length) return;
@ -305,12 +349,17 @@ Copyright (C) 2024 Richard Hao Cao
}); });
} }
} }
function recQueryHistory(q){
if(bQueryHistory)
fs.appendFile(path.join(__dirname,"history.autoc"), q, (err)=>{});
}
function handleQuery(q){ function handleQuery(q){
if(q.length>1){ if(q.length>1){
let c0=q.charCodeAt(0); let c0=q.charCodeAt(0);
switch(c0){ switch(c0){
case 33://"!" case 33://"!"
bangcommand(q); bangcommand(q);
recQueryHistory(q);
return; return;
case 47://"/" case 47://"/"
tabs.children[iTab].findInPage(q.substring(1)); tabs.children[iTab].findInPage(q.substring(1));
@ -321,6 +370,7 @@ Copyright (C) 2024 Richard Hao Cao
coloncommand(q); coloncommand(q);
else else
coloncommand_render(q); coloncommand_render(q);
recQueryHistory(q);
return; return;
} }
} }
@ -336,6 +386,7 @@ Copyright (C) 2024 Richard Hao Cao
break; break;
}else if(q.startsWith("javascript:")){ }else if(q.startsWith("javascript:")){
tabs.children[iTab].executeJavaScript(q.substring(11),false); tabs.children[iTab].executeJavaScript(q.substring(11),false);
recQueryHistory(q);
return; return;
}else if(q.startsWith("view-source:")) break; }else if(q.startsWith("view-source:")) break;
else if(q.startsWith("data:")) break; else if(q.startsWith("data:")) break;
@ -350,23 +401,110 @@ Copyright (C) 2024 Richard Hao Cao
break; break;
} }
url = defaultSE.replace('%s',q); url = defaultSE.replace('%s',q);
recQueryHistory(q);
break; break;
} }
url = bang(q, iS); url = bang(q, iS);
recQueryHistory(q);
}while(false); }while(false);
tabs.children[iTab].src=url; tabs.children[iTab].src=url;
} }
function autocomplete(inp,container,arr) {
var currentFocus;
function clickItem(e){inp.value = e.target.dataset.str;}
function appendElement(el,dataindex){
el.dataset.str = arr[dataindex];
el.addEventListener("click", clickItem);
container.appendChild(el);
}
inp.addEventListener("input", function(e) {
const MAXITEMS = 10;
var b, i, val = this.value;
closeAllLists();
if (!val) { return false;}
currentFocus = -1;
switch(autocMode){
case 0:
for (i = 0; i < arr.length; i++) {
let iStr = arr[i].indexOf(val);
if(iStr<0) continue;
{
b = document.createElement("DIV");
b.innerHTML = arr[i].substr(0,iStr);
b.innerHTML += "<strong>" + arr[i].substr(iStr, val.length) + "</strong>";
b.innerHTML += arr[i].substr(iStr+val.length);
appendElement(b,i);
if(container.children.length>MAXITEMS) break;
}
}
return;
case 1://startsWith
for (i = 0; i < arr.length; i++) {
if (arr[i].substr(0, val.length) === val) {
b = document.createElement("DIV");
b.innerHTML = "<strong>" + arr[i].substr(0, val.length) + "</strong>";
b.innerHTML += arr[i].substr(val.length);
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();
}
});
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> </script>
</head> </head>
<body> <body>
<form action="javascript:handleQuery(getQ())"> <form class="autocomplete" autocomplete="off" action="javascript:handleQuery(getQ())">
<datalist id="autoc"></datalist> <input type="text" name=q style="width:100%" autofocus>
<input type="text" list="autoc" name=q style="width:100%" autofocus></form> <div class="autocomplete-items"></div>
</form>
<div class="webviews"> <div class="webviews">
<webview class="curWV" allowpopups></webview> <webview class="curWV" allowpopups></webview>
</div> </div>
<script> <script>
tabs = document.body.children[1]; tabs = document.body.children[1];
{
let inp = document.forms[0].q;
autocomplete(inp,inp.nextElementSibling,autocStrArray);
}
document.addEventListener('keydown', keyPress); document.addEventListener('keydown', keyPress);
</script> </script>
</body></html> </body></html>

View file

@ -1,4 +1,4 @@
{"version":"1.0.29", {"version":"1.0.30",
"name": "ebrowser", "name": "ebrowser",
"description": "The keyboard-friendly minimal suckless web browser", "description": "The keyboard-friendly minimal suckless web browser",
"main": "webview.js", "main": "webview.js",

View file

@ -1,4 +1,9 @@
/* Copyright (C) 2024 Richard Hao Cao /* 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/>.
*/ */
const { const {
app, BrowserWindow, Menu, shell, clipboard, app, BrowserWindow, Menu, shell, clipboard,
@ -24,7 +29,7 @@ else {
} }
topMenu(); topMenu();
const repositoryurl = "https://gitlab.com/jamesfengcao/uweb/-/raw/master/misc/ebrowser/"; var repositoryurl = "https://gitlab.com/jamesfengcao/uweb/-/raw/master/misc/ebrowser/";
const fs = require('fs'); const fs = require('fs');
const readline = require('readline'); const readline = require('readline');
const path = require('path') const path = require('path')
@ -204,9 +209,13 @@ function addrCommand(cmd){
forwardCookie(); forwardCookie();
return; return;
case "nh": case "nh":
bHistory = false; return; bHistory = false;
win.webContents.executeJavaScript("bQueryHistory=false",false);
return;
case "uh": case "uh":
bHistory = true; return; bHistory = true;
win.webContents.executeJavaScript("bQueryHistory=true",false);
return;
case "nj": case "nj":
bJS = false; return; bJS = false; return;
case "uj": case "uj":
@ -422,11 +431,11 @@ function topMenu(){
win.setTitle(r); win.setTitle(r);
}); });
}}, }},
{ label: 'Go backward', accelerator: 'Ctrl+Left', click: ()=>{ { label: 'Go backward', accelerator: 'Alt+Left', click: ()=>{
let js="tabs.children[iTab].goBack()"; let js="tabs.children[iTab].goBack()";
win.webContents.executeJavaScript(js,false); win.webContents.executeJavaScript(js,false);
}}, }},
{ label: 'Go forward', accelerator: 'Ctrl+Right', click: ()=>{ { label: 'Go forward', accelerator: 'Alt+Right', click: ()=>{
let js="tabs.children[iTab].goForward()"; let js="tabs.children[iTab].goForward()";
win.webContents.executeJavaScript(js,false); win.webContents.executeJavaScript(js,false);
}}, }},

View file

@ -4,7 +4,7 @@
<sitemap> <sitemap>
<loc>/en/sitemap.xml</loc> <loc>/en/sitemap.xml</loc>
<lastmod>2024-06-19T09:41:18+08:00</lastmod> <lastmod>2024-06-24T09:46:43+08:00</lastmod>
</sitemap> </sitemap>