1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-22 20:57:58 +01:00

* initial frame support for hints, slightly buggy

* numbers can now be escaped with \ to be treated as text (thanks calmar)
This commit is contained in:
Martin Stubenschrott
2007-11-09 14:09:21 +00:00
parent 87ecebd815
commit f2b6db3b72

View File

@@ -37,10 +37,13 @@ vimperator.Hints = function() //{{{
var hints = [];
var valid_hints = []; // store the indices of the "hints" array with valid elements
var escapeNumbers = false ; // escape mode for numbers. true -> treated as hint-text
var activeTimeout = null; // needed for hinttimeout > 0
var canUpdate = false;
var hintsGenerated = false;
var docs = []; // keep track of the documents which we display the hints for
// keep track of the documents which we generated the hints for
// docs = { doc: document, start: start_index in hints[], end: end_index in hints[] }
var docs = [];
// reset all important variables
function reset()
@@ -52,13 +55,21 @@ vimperator.Hints = function() //{{{
hints = [];
valid_hints = [];
canUpdate = false;
hintsGenerated = false;
docs = [];
escapeNumbers = false;
if (activeTimeout)
clearTimeout(activeTimeout);
activeTimeout = null;
}
function updateStatusline()
{
vimperator.statusline.updateInputBuffer((escapeNumbers ? "\\ ": "" ) + // sign for escapeNumbers
(hintString ? "\"" + hintString + "\"" : "") +
(hintNumber > 0 ? " <" + hintNumber + ">" : ""));
}
// this function 'click' an element, which also works
// for javascript links
function openHint(new_tab, new_window)
@@ -71,7 +82,7 @@ vimperator.Hints = function() //{{{
var elemTagName = elem.localName.toLowerCase();
elem.focus();
if (elemTagName == "frame" || elemTagName == "iframe")
return 0;
return false;
// for imagemap
if (elemTagName == "area")
@@ -105,7 +116,7 @@ vimperator.Hints = function() //{{{
if (elemTagName == "frame" || elemTagName == "iframe")
{
elem.contentWindow.focus();
return;
return false;
}
else
{
@@ -165,18 +176,12 @@ vimperator.Hints = function() //{{{
function generate(win)
{
if (hintsGenerated)
return;
var startDate = Date.now();
hints = [];
if (!win)
win = window.content;
var doc = win.document;
docs.push(doc);
var height = win.innerHeight;
var width = win.innerWidth;
var scrollX = doc.defaultView.scrollX;
@@ -199,8 +204,10 @@ vimperator.Hints = function() //{{{
vimperator.log("evaluated XPath after: " + (Date.now() - startDate) + "ms");
var fragment = doc.createDocumentFragment();
var start = hints.length;
while ((elem = res.iterateNext()) != null)
{
// TODO: for frames, this calculation is wrong
rect = elem.getBoundingClientRect();
if (!rect || rect.top > height || rect.bottom < 0 || rect.left > width || rect.right < 0)
continue;
@@ -209,6 +216,7 @@ vimperator.Hints = function() //{{{
if (!rect)
continue;
// TODO: mozilla docs recommend localName instead of tagName
tagname = elem.tagName.toLowerCase();
if (tagname == "input" || tagname == "textarea")
text = elem.value.toLowerCase();
@@ -229,10 +237,15 @@ vimperator.Hints = function() //{{{
hints.push([elem, text, span, null, elem.style.backgroundColor, elem.style.color]);
}
doc.body.appendChild(fragment);
docs.push({ doc: doc, start: start, end: hints.length - 1});
// also generate hints for frames
for (var i = 0; i < win.frames.length; i++)
generate(win.frames[i]);
vimperator.log("hints.generate() completed after: " + (Date.now() - startDate) + "ms");
hintsGenerated = true;
return true;
}
@@ -248,109 +261,102 @@ vimperator.Hints = function() //{{{
newElem.style.backgroundColor = "#88FF00";
}
function showHints(win, start_idx)
function showHints()
{
var startDate = Date.now();
if (!win)
win = window.content;
if (win.document.body.localName.toLowerCase() == "frameset")
{
// for (i = 0; i < win.frames.length; i++)
// removeHints(win.frames[i]);
vimperator.echo("hint support for frameset pages not fully implemented yet");
}
var win = window.content;
var height = win.innerHeight;
var width = win.innerWidth;
vimperator.log("Show hints matching: " + hintString, 7);
var doc = win.document;
var scrollX = doc.defaultView.scrollX;
var scrollY = doc.defaultView.scrollY;
var elem, tagname, text, rect, span, imgspan;
var hintnum = start_idx > 0 ? start_idx : 1;
var height = window.content.innerHeight;
var width = window.content.innerWidth;
var hintnum = 1;
var find_tokens = hintString.split(/ +/);
var activeHint = hintNumber || 1;
valid_hints = [];
outer:
for (var i = 0; i < hints.length; i++)
for (var j = 0; j < docs.length; j++)
{
elem = hints[i][0];
text = hints[i][1];
span = hints[i][2];
imgspan = hints[i][3];
var doc = docs[j].doc;
var start = docs[j].start;
var end = docs[j].end;
var scrollX = doc.defaultView.scrollX;
var scrollY = doc.defaultView.scrollY;
for (var k = 0; k < find_tokens.length; k++)
outer:
for (var i = start; i <= end; i++)
{
if (text.indexOf(find_tokens[k]) < 0)
elem = hints[i][0];
text = hints[i][1];
span = hints[i][2];
imgspan = hints[i][3];
for (var k = 0; k < find_tokens.length; k++)
{
span.style.display = "none";
if (imgspan)
imgspan.style.display = "none";
if (text.indexOf(find_tokens[k]) < 0)
{
span.style.display = "none";
if (imgspan)
imgspan.style.display = "none";
// reset background color
elem.style.backgroundColor = hints[i][4];
elem.style.color = hints[i][5];
continue outer;
// reset background color
elem.style.backgroundColor = hints[i][4];
elem.style.color = hints[i][5];
continue outer;
}
}
if (text == "" && elem.firstChild && elem.firstChild.tagName == "IMG")
{
if (!imgspan)
{
rect = elem.firstChild.getBoundingClientRect();
if (!rect)
continue;
imgspan = doc.createElementNS("http://www.w3.org/1999/xhtml", "span");
imgspan.style.position = "absolute";
imgspan.style.opacity = 0.5;
imgspan.style.zIndex = "10000000";
imgspan.style.left = (rect.left + scrollX) + "px";
imgspan.style.top = (rect.top + scrollY) + "px";
imgspan.style.width = (rect.right - rect.left) + "px";
imgspan.style.height = (rect.bottom - rect.top) + "px";
imgspan.className = "vimperator-hint";
hints[i][3] = imgspan;
doc.body.appendChild(imgspan);
}
imgspan.style.backgroundColor = (activeHint == hintnum) ? "#88FF00" : "yellow";
imgspan.style.display = "inline";
}
}
if (text == "" && elem.firstChild && elem.firstChild.tagName == "IMG")
{
if (!imgspan)
{
rect = elem.firstChild.getBoundingClientRect();
if (!rect)
continue;
imgspan = doc.createElementNS("http://www.w3.org/1999/xhtml", "span");
imgspan.style.position = "absolute";
imgspan.style.opacity = 0.5;
imgspan.style.zIndex = "10000000";
imgspan.style.left = (rect.left + scrollX) + "px";
imgspan.style.top = (rect.top + scrollY) + "px";
imgspan.style.width = (rect.right - rect.left) + "px";
imgspan.style.height = (rect.bottom - rect.top) + "px";
imgspan.className = "vimperator-hint";
hints[i][3] = imgspan;
doc.body.appendChild(imgspan);
}
imgspan.style.backgroundColor = (activeHint == hintnum) ? "#88FF00" : "yellow";
imgspan.style.display = "inline";
elem.style.backgroundColor = (activeHint == hintnum) ? "#88FF00" : "yellow";
elem.style.color = "black";
span.textContent = "" + (hintnum++);
span.style.display = "inline";
valid_hints.push(elem);
}
if (!imgspan)
elem.style.backgroundColor = (activeHint == hintnum) ? "#88FF00" : "yellow";
elem.style.color = "black";
span.textContent = "" + (hintnum++);
span.style.display = "inline";
valid_hints.push(elem);
}
vimperator.log("showHints() completed after: " + (Date.now() - startDate) + "ms");
return true;
}
function removeHints(doc, timeout)
function removeHints(timeout)
{
if (!doc)
{
vimperator.log("Argument doc is required for internal removeHints() method", 9);
return;
}
var firstElem = valid_hints[0] || null;
var firstElemBgColor = "";
var firstElemColor = "";
try
for (var j = 0; j < docs.length; j++)
{
for (var i = 0; i < hints.length; i++)
var doc = docs[j].doc;
var start = docs[j].start;
var end = docs[j].end;
for (var i = start; i <= end; i++)
{
// remove the span for the numeric display part
doc.body.removeChild(hints[i][2]);
@@ -374,38 +380,37 @@ outer:
// animate the disappearance of the first hint
if (timeout && firstElem)
{
// USE THIS FOR MAKING THE SELECTED ELEM RED
// firstElem.style.backgroundColor = "red";
// firstElem.style.color = "white";
// setTimeout(function() {
// firstElem.style.backgroundColor = firstElemBgColor;
// firstElem.style.color = firstElemColor;
// }, 200);
// OR USE THIS FOR BLINKING:
// var counter = 0;
// var id = setInterval(function() {
// firstElem.style.backgroundColor = "red";
// if (counter % 2 == 0)
// firstElem.style.backgroundColor = "yellow";
// else
// firstElem.style.backgroundColor = "#88FF00";
//
// if (counter++ >= 2)
// {
// firstElem.style.backgroundColor = firstElemBgColor;
// firstElem.style.color = firstElemColor;
// clearTimeout(id);
// }
// }, 100);
// USE THIS FOR MAKING THE SELECTED ELEM RED
// firstElem.style.backgroundColor = "red";
// firstElem.style.color = "white";
// setTimeout(function() {
// firstElem.style.backgroundColor = firstElemBgColor;
// firstElem.style.color = firstElemColor;
// }, 200);
// OR USE THIS FOR BLINKING:
// var counter = 0;
// var id = setInterval(function() {
// firstElem.style.backgroundColor = "red";
// if (counter % 2 == 0)
// firstElem.style.backgroundColor = "yellow";
// else
// firstElem.style.backgroundColor = "#88FF00";
//
// if (counter++ >= 2)
// {
// firstElem.style.backgroundColor = firstElemBgColor;
// firstElem.style.color = firstElemColor;
// clearTimeout(id);
// }
// }, 100);
setTimeout(function() {
firstElem.style.backgroundColor = firstElemBgColor;
firstElem.style.color = firstElemColor;
}, timeout);
}
}
catch (e) { vimperator.log("Error hiding hints, probably wrong window"); }
vimperator.log("removeHints() done");
reset();
}
@@ -449,7 +454,7 @@ outer:
}
var timeout = followFirst ? 0 : 500;
removeHints(docs.pop(), timeout);
removeHints(timeout);
if (vimperator.modes.extended & vimperator.modes.ALWAYS_HINT)
{
@@ -491,13 +496,14 @@ outer:
canUpdate = false;
generate();
// get all keys from the input queue
var mt = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
while (mt.hasPendingEvents())
mt.processNextEvent(true);
canUpdate = true;
showHints(null);
showHints();
if (valid_hints.length == 0)
{
@@ -516,12 +522,7 @@ outer:
this.hide = function()
{
if (!hintsGenerated)
return;
var doc = docs.pop();
if (doc);
removeHints(doc, 0);
removeHints(0);
};
this.onEvent = function(event)
@@ -544,6 +545,7 @@ outer:
case "<Space>":
hintString += " ";
escapeNumbers = false;
break;
case "<Tab>":
@@ -592,6 +594,14 @@ outer:
hintNumber = 0;
break;
case "\\":
escapeNumbers = !escapeNumbers;
if (escapeNumbers && usedTabKey) // hintNumber not used normally, but someone may wants to toggle
hintNumber = 0; // <tab>s ? reset. Prevent to show numbers not entered.
updateStatusline();
return;
default:
// pass any special or ctrl- etc. prefixed key back to the main vimperator loop
if (/^<./.test(key) || key == ":")
@@ -608,7 +618,7 @@ outer:
return;
}
if (/^[0-9]$/.test(key))
if (/^[0-9]$/.test(key) && !escapeNumbers)
{
var oldHintNumber = hintNumber;
if (hintNumber == 0 || usedTabKey)
@@ -619,11 +629,12 @@ outer:
else
hintNumber = (hintNumber * 10) + parseInt(key, 10);
vimperator.statusline.updateInputBuffer(hintString + (hintNumber > 0 ? hintNumber : ""));
updateStatusline();
if (!canUpdate)
return;
if (!hintsGenerated)
if (docs.length == 0)
{
generate();
showHints();
@@ -652,18 +663,19 @@ outer:
}
hintString += key;
hintNumber = 0; // after some text input
if (usedTabKey)
{
usedTabKey = false;
showActiveHint(1, hintNumber);
hintNumber = 1;
}
}
vimperator.statusline.updateInputBuffer(hintString + (hintNumber > 0 ? hintNumber : ""));
updateStatusline();
if (canUpdate)
{
if (!hintsGenerated && hintString.length > 0)
if (docs.length == 0 && hintString.length > 0)
generate();
showHints();
@@ -672,22 +684,16 @@ outer:
return;
}
// FIXME: add resize support
//window.addEventListener("resize", onResize, null);
// window.addEventListener("resize", onResize, null);
// getBrowser().addEventListener("DOMContentLoaded", function(event) {
// if (vimperator.options["autohints"])
// vimperator.hints.show(event.target);
// }, false);
// function onResize(event)
// {
// if (event)
// doc = event.originalTarget;
// else
// doc = window.content.document;
// }
// function onResize(event)
// {
// if (event)
// doc = event.originalTarget;
// else
// doc = window.content.document;
// }
} //}}}