1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 22:47:59 +01:00
Files
pentadactyl-pm/common/content/statusline.js
Kris Maglione 6a25312c7d Recfactoring:
* Standard module format. All modules are explicitly declared
   as modules, they're created via a constructor and
   instantiated automatically. They're dependency aware. They
   stringify properly.

 * Classes are declared the same way (rather like Structs
   already were). They also stringify properly. Plus, each
   instance has a rather nifty closure member that closes all
   of its methods around 'this', so you can pass them to map,
   forEach, setTimeout, etc. Modules are themselves classes,
   with a special metaclass, as it were.

 * Doug Crockford is dead, metaphorically speaking.
   Closure-based classes just don't fit into any of the common
   JavaScript frameworks, and they're inefficient and
   confusing. Now, all class and module members are accessed
   explicitly via 'this', which makes it very clear that
   they're class members and not (e.g.) local variables,
   without anything nasty like Hungarian notation.

 * Strictly one module per file. Classes that belong to a
   module live in the same file.

 * For the moment, there are quite a few utility functions
   sitting in base.c, because my class implementation used
   them, and I haven't had the time or inclination to sort them
   out. I plan to reconcile them with the current mess that is
   the util namespace.

 * Changed bracing style.
2009-11-08 20:54:31 -05:00

246 lines
9.2 KiB
JavaScript

// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
/** @scope modules */
const StatusLine = Module("statusline", {
init: function () {
this._statusBar = document.getElementById("status-bar");
this._statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0
// our status bar fields
this._statuslineWidget = document.getElementById("liberator-statusline");
this._urlWidget = document.getElementById("liberator-statusline-field-url");
this._inputBufferWidget = document.getElementById("liberator-statusline-field-inputbuffer");
this._progressWidget = document.getElementById("liberator-statusline-field-progress");
this._tabCountWidget = document.getElementById("liberator-statusline-field-tabcount");
this._bufferPositionWidget = document.getElementById("liberator-statusline-field-bufferposition");
},
/**
* Update the status bar to indicate how secure the website is:
* extended - Secure connection with Extended Validation(EV) certificate.
* secure - Secure connection with valid certificate.
* broken - Secure connection with invalid certificate, or
* mixed content.
* insecure - Insecure connection.
*
* @param {'extended'|'secure'|'broken'|'insecure'} type
*/
setClass: function setClass(type) {
const highlightGroup = {
extended: "StatusLineExtended",
secure: "StatusLineSecure",
broken: "StatusLineBroken",
insecure: "StatusLine"
};
this._statusBar.setAttributeNS(NS.uri, "highlight", highlightGroup[type]);
},
// update all fields of the statusline
update: function update() {
this.updateUrl();
this.updateInputBuffer();
this.updateProgress();
this.updateTabCount();
this.updateBufferPosition();
},
/**
* Update the URL displayed in the status line. Also displays status
* icons, [+-♥], when there are next and previous pages in the
* current tab's history, and when the current URL is bookmarked,
* respectively.
*
* @param {string} url The URL to display.
* @default buffer.URL
*/
updateUrl: function updateUrl(url) {
// ripped from Firefox; modified
function losslessDecodeURI(url) {
// 1. decodeURI decodes %25 to %, which creates unintended
// encoding sequences.
url = url.split("%25").map(decodeURI).join("%25");
// 2. Re-encode whitespace so that it doesn't get eaten away
// by the location bar (bug 410726).
url = url.replace(/[\r\n\t]/g, encodeURIComponent);
// Encode invisible characters (soft hyphen, zero-width space, BOM,
// line and paragraph separator, word joiner, invisible times,
// invisible separator, object replacement character) (bug 452979)
url = url.replace(/[\v\x0c\x1c\x1d\x1e\x1f\u00ad\u200b\ufeff\u2028\u2029\u2060\u2062\u2063\ufffc]/g,
encodeURIComponent);
// Encode bidirectional formatting characters.
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
encodeURIComponent);
return url;
};
if (url == null)
// TODO: this probably needs a more general solution.
url = losslessDecodeURI(buffer.URL);
// make it even more Vim-like
if (url == "about:blank") {
if (!buffer.title)
url = "[No Name]";
}
else {
url = url.replace(RegExp("^liberator://help/(\\S+)#(.*)"), function (m, n1, n2) n1 + " " + decodeURIComponent(n2) + " [Help]")
.replace(RegExp("^liberator://help/(\\S+)"), "$1 [Help]");
}
// when session information is available, add [+] when we can go
// backwards, [-] when we can go forwards
let modified = "";
if (window.getWebNavigation) {
let sh = window.getWebNavigation().sessionHistory;
if (sh && sh.index > 0)
modified += "+";
if (sh && sh.index < sh.count -1)
modified += "-";
}
if (modules.bookmarks) {
if (bookmarks.isBookmarked(buffer.URL))
modified += "\u2764"; // a heart symbol: ❤
//modified += "\u2665"; // a heart symbol: ♥
}
if (modified)
url += " [" + modified + "]";
this._urlWidget.value = url;
},
/**
* Set the contents of the status line's input buffer to the given
* string. Used primarily when a key press requires further input
* before being processed, including mapping counts and arguments,
* along with multi-key mappings.
*
* @param {string} buffer
*/
updateInputBuffer: function updateInputBuffer(buffer) {
if (!buffer || typeof buffer != "string")
buffer = "";
this._inputBufferWidget.value = buffer;
},
/**
* Update the page load progress bar.
*
* @param {string|number} progress The current progress, as follows:
* A string - Displayed literally.
* A ratio 0 < n < 1 - Displayed as a progress bar.
* A number n <= 0 - Displayed as a "Loading" message.
* Any other number - The progress is cleared.
*/
updateProgress: function updateProgress(progress) {
if (!progress)
progress = "";
if (typeof progress == "string")
this._progressWidget.value = progress;
else if (typeof progress == "number") {
let progressStr = "";
if (progress <= 0)
progressStr = "[ Loading... ]";
else if (progress < 1) {
progress = Math.floor(progress * 20);
progressStr = "["
+ "====================".substr(0, progress)
+ ">"
+ " ".substr(0, 19 - progress)
+ "]";
}
this._progressWidget.value = progressStr;
}
},
/**
* Display the correct tabcount (e.g., [1/5]) on the status bar.
*
* @param {bool} delayed When true, update count after a
* brief timeout. Useful in the many cases when an
* event that triggers an update is broadcast before
* the tab state is fully updated.
*/
updateTabCount: function updateTabCount(delayed) {
if (liberator.has("tabs")) {
if (delayed)
return void setTimeout(function () statusline.updateTabCount(false), 0);
// update the ordinal which is used for numbered tabs
if (options.get("guioptions").has("n", "N"))
for (let [i, tab] in util.Array.iteritems(getBrowser().mTabs))
tab.setAttribute("ordinal", i + 1);
this._tabCountWidget.value = "[" + (tabs.index() + 1) + "/" + tabs.count + "]";
}
},
/**
* Display the main content's vertical scroll position in the status
* bar.
*
* @param {number} percent The position, as a percentage. @optional
*/
updateBufferPosition: function updateBufferPosition(percent) {
if (!percent || typeof percent != "number") {
let win = document.commandDispatcher.focusedWindow;
if (!win)
return;
percent = win.scrollMaxY == 0 ? -1 : win.scrollY / win.scrollMaxY;
}
let bufferPositionStr = "";
percent = Math.round(percent * 100);
if (percent < 0)
bufferPositionStr = "All";
else if (percent == 0)
bufferPositionStr = "Top";
else if (percent < 10)
bufferPositionStr = " " + percent + "%";
else if (percent >= 100)
bufferPositionStr = "Bot";
else
bufferPositionStr = percent + "%";
this._bufferPositionWidget.value = bufferPositionStr;
}
}, {
}, {
options: function () {
options.add(["laststatus", "ls"],
"Show the status line",
"number", 2,
{
setter: function setter(value) {
if (value == 0)
document.getElementById("status-bar").collapsed = true;
else if (value == 1)
liberator.echoerr("show status line only with > 1 window not implemented yet");
else
document.getElementById("status-bar").collapsed = false;
return value;
},
completer: function completer(context) [
["0", "Never display status line"],
["1", "Display status line only if there are multiple windows"],
["2", "Always display status line"]
],
validator: Option.validateCompleter
});
},
});
// vim: set fdm=marker sw=4 ts=4 et: