kopher

A simple Gopher client for KaiOS
git clone git://git.luxferre.top/kopher.git
Log | Files | Refs | README | LICENSE

commit 28359eb8894be37d43b66c16fd119c5a67fe963b
parent 5ce5069a70685d5789a3eb5a530b8f8cb1c29139
Author: Luxferre <lux@ferre>
Date:   Sat,  1 Apr 2023 15:08:55 +0300

Implemented Unflow for plaintext content

Diffstat:
MREADME.md | 2+-
Mjs/app.js | 10+++++++++-
Mjs/hi01379.js | 24+++++++++++++++++++++++-
Mmanifest.webapp | 2+-
4 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md @@ -61,7 +61,7 @@ Note that currently, Kopher and hi01379.js assume that the search request from a - Minimalistic but easy and quick WAP-like navigation (see "Controls") - The `gopher://` scheme is assumed by default (no need to enter it manually), same for the port 70 - One-key light/dark theme toggle -- One-key switching the line wrapping mode between off (default) and on (for comfortable reading) +- One-key switching the line wrapping mode between off (default) and on (for comfortable reading even the hard-wrapped documents) - Unlimited navigation history (doesn't persist between sessions) - Up to 10 numbered bookmarks plus customizable homepage - Binary blob downloads (see "Downloads") diff --git a/js/app.js b/js/app.js @@ -99,6 +99,8 @@ addEventListener('DOMContentLoaded', function() { return bmArray[index] } + var activeContent={'prop': 'textContent', 'nowrap': '', 'wrap': ''} // placeholder to hold the wrapped and non-wrapped content + function loadURL(url, noNavUpdate) { // wrapper to openURL that actually updates all the UI and history logoStatus.textContent = logoLoadingChar statusBar.textContent = 'Loading ' + url @@ -108,14 +110,18 @@ addEventListener('DOMContentLoaded', function() { var updateHistory = !('updateAddr' in res && res.updateAddr === false), // true by default updateContent = !(res.content === null) // true by default if(updateContent) { // update the content zone + activeContent.nowrap = res.content + activeContent.wrap = res.contentWf || res.content contentZone.innerHTML = '' contentZone.textContent = '' contentZone.dataset.wrap = 0 // reset line wrapping if(res.contentType === 'text/plain') { + activeContent.prop = 'textContent' contentZone.dataset.format='plain' - contentZone.textContent = res.content + contentZone.textContent = activeContent.nowrap } else { contentZone.dataset.format='native' + activeContent.prop='innerHTML' contentZone.innerHTML = res.content var contentLinks = contentZone.querySelectorAll('a'), l = contentLinks.length, i for(i=0;i<l;i++) { // dynamically index all the links in the rendered content @@ -203,6 +209,8 @@ addEventListener('DOMContentLoaded', function() { break case '6': // toggle line wrapping contentZone.dataset.wrap = 1 - parseInt(contentZone.dataset.wrap) + if(activeContent.wrap != activeContent.nowrap) // only update contentZone if they differ + contentZone[activeContent.prop] = activeContent[parseInt(contentZone.dataset.wrap) ? 'wrap' : 'nowrap'] break case 'Call': // refresh loadURL(currentUrl, true) diff --git a/js/hi01379.js b/js/hi01379.js @@ -10,6 +10,24 @@ Hi01379 = (function(psGopherRequest) { return str.replace(/[&<>]/g, function(tag) {return tagsToReplace[tag] || tag}) } + function unphlow(str) { // Unphlow algorithm implementation + var lines=str.split('\n'), line, l = lines.length, i, buf = '', out = [] + for(i=0;i<l;i++) { + line = lines[i].trim() // remove all leading/trailing whitespace-class chars + if(line.length) // if the line is not empty, just append it and a whitespace to the buffer + buf += line + ' ' + else { // output logic + out.push(buf, '') + buf = '' + } + } + if(buf.length) // process the remaining output + out.push(buf) + return out.map(function(s) { // final whitespace sanitation + return s.replace(/\s+/g, ' ').trim() + }).join('\n') + } + function gophermapToHTML(gmap, chost, cport) { if(!cport) cport = 70 if(!chost) chost = 'localhost' @@ -98,13 +116,17 @@ Hi01379 = (function(psGopherRequest) { }) } else { // assuming text content otherwise - var output = (new TextDecoder).decode(rawdata), ctype = 'text/plain' // defaulting to type 0 + var output = (new TextDecoder).decode(rawdata), ctype = 'text/plain', // defaulting to type 0 + wo = '' // wrapper-friendly output if(type == '1' || type == '7') { // gophermap output = gophermapToHTML(output, resource[2], resource[3]) ctype = 'text/html' + wo = output } + else wo = unphlow(output) successCb({ content: output, + contentWf: wo, contentType: ctype, serviceMsg: type + ' ' + resource[1] }) diff --git a/manifest.webapp b/manifest.webapp @@ -1,5 +1,5 @@ { - "version": "0.0.3", + "version": "0.0.4", "name": "Kopher", "description": "A Gopher client for KaiOS", "launch_path": "/index.html",