mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 00:17:58 +01:00
add forgotten files
This commit is contained in:
575
chrome/content/vimperator/commandline.js
Normal file
575
chrome/content/vimperator/commandline.js
Normal file
@@ -0,0 +1,575 @@
|
||||
// XXX: remove!
|
||||
function save_history()
|
||||
{
|
||||
set_pref("comp_history", comp_history.join("\n"));
|
||||
}
|
||||
|
||||
function load_history()
|
||||
{
|
||||
var hist = get_pref("comp_history", "");
|
||||
comp_history = hist.split("\n");
|
||||
}
|
||||
|
||||
function multiliner(line, prev_match, heredoc)
|
||||
{
|
||||
var end = true;
|
||||
var match = tokenize_ex(line, prev_match[4]);
|
||||
if (prev_match[3] === undefined) prev_match[3] = '';
|
||||
if (match[4] === null)
|
||||
{
|
||||
focusContent(false, true); // also sets tab_index to -1
|
||||
execute_command.apply(this, match);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (match[4] === false)
|
||||
{
|
||||
prev_match[3] = prev_match[3].replace(new RegExp('<<\s*' + prev_match[4]), heredoc.replace(/\n$/, ''));
|
||||
focusContent(false, true); // also sets comp_tab_index to -1
|
||||
execute_command.apply(this, prev_match);
|
||||
prev_match = new Array(5);
|
||||
prev_match[3] = '';
|
||||
heredoc = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
end = false;
|
||||
if (!prev_match[3])
|
||||
{
|
||||
prev_match[0] = match[0];
|
||||
prev_match[1] = match[1];
|
||||
prev_match[2] = match[2];
|
||||
prev_match[3] = match[3];
|
||||
prev_match[4] = match[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
heredoc += match[3] + '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
return [prev_match, heredoc, end];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This class is used for prompting of user input and echoing of messages
|
||||
*
|
||||
* it consists of a prompt and command field
|
||||
* be sure to only create objects of this class when the chrome is ready
|
||||
*/
|
||||
function CommandLine ()
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////// PRIVATE SECTION /////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const UNINITIALIZED = -2; // notifies us, if we need to start history/tab-completion from the beginning
|
||||
const HISTORY_SIZE = 500;
|
||||
|
||||
var completionlist = new CompletionList();
|
||||
var completions = new Array();
|
||||
|
||||
var history = new Array();
|
||||
var history_index = UNINITIALIZED;
|
||||
var history_start = "";
|
||||
|
||||
// for the example command "open sometext| othertext" (| is the cursor pos)
|
||||
var completion_start_index = 0; // will be 5 because we want to complete arguments for the :open command
|
||||
var completion_prefix = "" // will be: "open sometext"
|
||||
var completion_postfix = ""; // will be: " othertext"
|
||||
|
||||
var wild_index = 0; // keep track how often we press <Tab> in a row
|
||||
var completion_index = UNINITIALIZED;
|
||||
|
||||
// The prompt for the current command, for example : or /. Can be blank
|
||||
var prompt_widget = document.getElementById('new-vim-commandbar-prompt');
|
||||
// The command bar which contains the current command
|
||||
var command_widget = document.getElementById('new-vim-commandbar');
|
||||
|
||||
function setNormalStyle()
|
||||
{
|
||||
command_widget.inputField.setAttribute("style","font-family: monospace;");
|
||||
}
|
||||
function setErrorStyle()
|
||||
{
|
||||
command_widget.inputField.setAttribute("style", "font-family: monospace; color:white; background-color:red; font-weight: bold");
|
||||
}
|
||||
|
||||
// Sets the prompt - for example, : or /
|
||||
function setPrompt(prompt)
|
||||
{
|
||||
if (typeof(prompt) != "string")
|
||||
prompt = "";
|
||||
|
||||
prompt_widget.value = prompt;
|
||||
if (prompt)
|
||||
{
|
||||
// Initially (in the xul) the prompt is 'collapsed', this makes
|
||||
// sure it's visible, then we toggle the display which works better
|
||||
prompt_widget.style.visibility = 'visible';
|
||||
prompt_widget.style.display = 'inline';
|
||||
prompt_widget.size = prompt.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
prompt_widget.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the command - e.g. 'tabopen', 'open http://example.com/'
|
||||
function setCommand(cmd)
|
||||
{
|
||||
command_widget.value = cmd;
|
||||
}
|
||||
|
||||
function addToHistory(str)
|
||||
{
|
||||
// first remove all old history elements which have this string
|
||||
history = history.filter(function(elem) {
|
||||
return elem != str;
|
||||
});
|
||||
// add string to the command line history
|
||||
if (str.length >= 1 && history.push(str) > HISTORY_SIZE)
|
||||
history.shift();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.getCommand = function()
|
||||
{
|
||||
return command_widget.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* All arguments can be ommited and will be defaulted to ""
|
||||
*/
|
||||
this.open = function(prompt, cmd, minor_mode)
|
||||
{
|
||||
if (!prompt)
|
||||
prompt = "";
|
||||
if (!cmd)
|
||||
cmd = "";
|
||||
if (minor_mode)
|
||||
setCurrentMode(minor_mode);
|
||||
|
||||
setNormalStyle();
|
||||
setPrompt(prompt);
|
||||
setCommand(cmd);
|
||||
history_index = UNINITIALIZED;
|
||||
completion_index = UNINITIALIZED;
|
||||
command_widget.focus();
|
||||
};
|
||||
|
||||
this.echo = function(str)
|
||||
{
|
||||
setNormalStyle();
|
||||
setPrompt("");
|
||||
setCommand(str);
|
||||
};
|
||||
|
||||
this.echoErr = function(str)
|
||||
{
|
||||
setErrorStyle();
|
||||
setPrompt("");
|
||||
setCommand(str);
|
||||
};
|
||||
|
||||
this.clear = function()
|
||||
{
|
||||
setPrompt(" "); // looks faster than an empty string
|
||||
setCommand("");
|
||||
setNormalStyle();
|
||||
};
|
||||
|
||||
|
||||
this.onEvent = function(event)
|
||||
{
|
||||
//var end = false;
|
||||
var command = this.getCommand();
|
||||
|
||||
if(event.type == "blur")
|
||||
{
|
||||
// when we do a command_widget.focus() we get a blur event immediately,
|
||||
// so check if the target is the actualy input field
|
||||
if (event.target == command_widget.inputField)
|
||||
{
|
||||
addToHistory(command);
|
||||
completionlist.hide();
|
||||
}
|
||||
}
|
||||
else if(event.type == "input")
|
||||
{
|
||||
vimperator.triggerCallback("change", command);
|
||||
}
|
||||
else if(event.type == "keypress")
|
||||
{
|
||||
var key = keyToString(event);
|
||||
/* user pressed ENTER to carry out a command */
|
||||
if (key == "<Return>" || key == "<C-j>" || key == "<C-m>")
|
||||
{
|
||||
// try {
|
||||
// [prev_match, heredoc, end] = multiliner(command, prev_match, heredoc);
|
||||
// } catch(e) {
|
||||
// logObject(e);
|
||||
// echoerr(e.name + ": " + e.message);
|
||||
// prev_match = new Array(5);
|
||||
// heredoc = '';
|
||||
// return;
|
||||
// }
|
||||
// if (!end)
|
||||
// command_line.value = "";
|
||||
|
||||
// the command is saved in the blur() handler
|
||||
focusContent();
|
||||
var res = vimperator.triggerCallback("submit", command);
|
||||
return res;
|
||||
}
|
||||
/* user pressed ESCAPE to cancel this prompt */
|
||||
else if (key == "<Esc>" || key == "<C-[>")
|
||||
{
|
||||
var res = vimperator.triggerCallback("cancel");
|
||||
addToHistory(command);
|
||||
this.clear();
|
||||
focusContent(true, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* user pressed UP or DOWN arrow to cycle history completion */
|
||||
else if (key == "<Up>" || key == "<Down>")
|
||||
{
|
||||
//always reset the tab completion if we use up/down keys
|
||||
completion_index = UNINITIALIZED;
|
||||
|
||||
/* save 'start' position for iterating through the history */
|
||||
if (history_index == UNINITIALIZED)
|
||||
{
|
||||
history_index = history.length;
|
||||
history_start = command;
|
||||
}
|
||||
|
||||
while (history_index >= -1 && history_index <= history.length)
|
||||
{
|
||||
key == "<Up>" ? history_index-- : history_index++;
|
||||
if (history_index == history.length) // user pressed DOWN when there is no newer history item
|
||||
{
|
||||
setCommand(history_start);
|
||||
return;
|
||||
}
|
||||
// cannot go past history start/end
|
||||
if (history_index <= -1)
|
||||
{
|
||||
history_index = 0;
|
||||
beep();
|
||||
break;
|
||||
}
|
||||
if (history_index >= history.length + 1)
|
||||
{
|
||||
history_index = history.length;
|
||||
beep();
|
||||
break;
|
||||
}
|
||||
|
||||
if (history[history_index].indexOf(history_start) == 0)
|
||||
{
|
||||
setCommand(history[history_index]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
beep();
|
||||
}
|
||||
|
||||
/* user pressed TAB to get completions of a command */
|
||||
else if (key == "<Tab>" || key == "<S-Tab>")
|
||||
{
|
||||
//always reset our completion history so up/down keys will start with new values
|
||||
history_index = UNINITIALIZED;
|
||||
|
||||
// we need to build our completion list first
|
||||
if (completion_index == UNINITIALIZED)
|
||||
{
|
||||
// FIXME: completions.clear();
|
||||
completion_start_index = 0;
|
||||
|
||||
completion_index = -1;
|
||||
wild_index = 0;
|
||||
|
||||
completion_prefix = command.substring(0, command_widget.selectionStart);
|
||||
completion_postfix = command.substring(command_widget.selectionStart);
|
||||
var res = vimperator.triggerCallback("complete", completion_prefix);
|
||||
if (res)
|
||||
[completion_start_index, completions] = res;
|
||||
|
||||
// Sort the completion list
|
||||
if (get_pref('wildoptions').match(/\bsort\b/))
|
||||
{
|
||||
completions.sort(function(a, b) {
|
||||
if (a[0] < b[0])
|
||||
return -1;
|
||||
else if (a[0] > b[0])
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
// we could also return when no completion is found
|
||||
// but we fall through to the cleanup anyway
|
||||
if (completions.length == 0)
|
||||
{
|
||||
beep();
|
||||
// prevent tab from moving to the next field
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
var wim = get_pref('wildmode').split(/,/);
|
||||
var has_list = false;
|
||||
var longest = false;
|
||||
var full = false;
|
||||
var wildtype = wim[wild_index++] || wim[wim.length - 1];
|
||||
if (wildtype == 'list' || wildtype == 'list:full' || wildtype == 'list:longest')
|
||||
has_list = true;
|
||||
else if (wildtype == 'longest' || wildtype == 'list:longest')
|
||||
longest = true;
|
||||
else if (wildtype == 'full' || wildtype == 'list:full')
|
||||
full = true;
|
||||
|
||||
// show the list
|
||||
if (has_list)
|
||||
{
|
||||
completionlist.show(completions);
|
||||
}
|
||||
|
||||
if (full)
|
||||
{
|
||||
if (event.shiftKey)
|
||||
{
|
||||
completion_index--;
|
||||
if(completion_index < -1)
|
||||
completion_index = completions.length -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
completion_index++;
|
||||
if(completion_index >= completions.length)
|
||||
completion_index = -1;
|
||||
}
|
||||
|
||||
showStatusbarMessage("match " + (completion_index+1).toString() + " of " + completions.length.toString(), STATUSFIELD_PROGRESS);
|
||||
// if the list is hidden, this function does nothing
|
||||
completionlist.selectItem(completion_index);
|
||||
}
|
||||
|
||||
|
||||
// if (longest && completions.length == 1)
|
||||
// {
|
||||
// completion_index=0;
|
||||
// }
|
||||
|
||||
if (completion_index == -1 && !longest) // wrapped around matches, reset command line
|
||||
{
|
||||
if (full && completions.length > 1)
|
||||
{
|
||||
setCommand(completion_prefix + completion_postfix);
|
||||
//completion_list.selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (longest && completions.length > 1)
|
||||
var compl = get_longest_substring();
|
||||
if (full)
|
||||
var compl = completions[completion_index][0];
|
||||
if (completions.length == 1)
|
||||
var compl = completions[COMMANDS][0];
|
||||
//alert(compl)
|
||||
if (compl)
|
||||
{
|
||||
setCommand(command.substring(0, completion_start_index) + compl + completion_postfix);
|
||||
command_widget.selectionStart = command_widget.selectionEnd = completion_start_index + compl.length;
|
||||
|
||||
// XXX: needed?
|
||||
// // Start a new completion in the next iteration. Useful for commands like :source
|
||||
// if (completions.length == 1 && !full) // RFC: perhaps the command can indicate whether the completion should be restarted
|
||||
// completion_index = UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
// prevent tab from moving to the next field
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
else if (key == "<BS>")
|
||||
{
|
||||
// reset the tab completion
|
||||
completion_index = history_index = UNINITIALIZED;
|
||||
|
||||
// and blur the command line if there is no text left
|
||||
if(command.length == 0)
|
||||
{
|
||||
this.clear();
|
||||
focusContent();
|
||||
}
|
||||
}
|
||||
else // any other key
|
||||
{
|
||||
// reset the tab completion
|
||||
completion_index = history_index = UNINITIALIZED;
|
||||
}
|
||||
}
|
||||
}
|
||||
logMessage("CommandLine initialized.");
|
||||
}
|
||||
|
||||
function CompletionList()
|
||||
{
|
||||
const MAX_ITEMS = 10;
|
||||
const CONTEXT_LINES = 3;
|
||||
|
||||
var completions = null; // a reference to the Array of completions
|
||||
var completion_widget = document.getElementById("vim-completion");
|
||||
var list_offset = 0; // how many items is the displayed list shifted from the internal tab index
|
||||
var list_index = 0; // list_offset + list_index = completions[item]
|
||||
|
||||
// add a single completion item to the list
|
||||
function addItem(completion_item, at_beginning)
|
||||
{
|
||||
var item = document.createElement("listitem");
|
||||
var cell1 = document.createElement("listcell");
|
||||
var cell2 = document.createElement("listcell");
|
||||
|
||||
cell1.setAttribute("label", completion_item[0]);
|
||||
cell2.setAttribute("label", completion_item[1]);
|
||||
cell2.setAttribute("style", "color:green; font-family: sans");
|
||||
|
||||
item.appendChild(cell1);
|
||||
item.appendChild(cell2);
|
||||
if (at_beginning == true)
|
||||
{
|
||||
var items = completion_widget.getElementsByTagName("listitem");
|
||||
if (items.length > 0)
|
||||
completion_widget.insertBefore(item, items[0]);
|
||||
else
|
||||
completion_widget.appendChild(item);
|
||||
}
|
||||
else
|
||||
completion_widget.appendChild(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* uses the entries in completions to fill the listbox
|
||||
* @param startindex: start at this index and show MAX_ITEMS
|
||||
* @returns the number of items
|
||||
*/
|
||||
function fill(startindex)
|
||||
{
|
||||
var complength = completions.length;
|
||||
|
||||
// remove all old items first
|
||||
var items = completion_widget.getElementsByTagName("listitem");
|
||||
while (items.length > 0) { completion_widget.removeChild(items[0]);}
|
||||
|
||||
// find start index
|
||||
if (startindex + MAX_ITEMS > complength)
|
||||
startindex = complength - MAX_ITEMS;
|
||||
if (startindex < 0)
|
||||
startindex = 0;
|
||||
|
||||
list_offset = startindex;
|
||||
list_index = -1;
|
||||
|
||||
for(i = startindex; i < complength && i < startindex + MAX_ITEMS; i++)
|
||||
{
|
||||
addItem(completions[i], false);
|
||||
}
|
||||
|
||||
return (i-startindex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
this.len = function() {alert(completions.length);};
|
||||
this.show = function(compl)
|
||||
{
|
||||
completions = compl;
|
||||
fill(0);
|
||||
|
||||
var length = completions.length;
|
||||
if (length > MAX_ITEMS)
|
||||
length = MAX_ITEMS;
|
||||
if (length > 1)
|
||||
{
|
||||
completion_widget.setAttribute("rows", length.toString());
|
||||
completion_widget.hidden = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
completion_widget.hidden = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.hide = function()
|
||||
{
|
||||
completion_widget.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* select index, refill list if necessary
|
||||
*/
|
||||
this.selectItem = function(index)
|
||||
{
|
||||
if(completion_widget.hidden)
|
||||
return;
|
||||
|
||||
// find start index
|
||||
var new_offset = 0;
|
||||
if (index >= list_offset + MAX_ITEMS - CONTEXT_LINES)
|
||||
new_offset = index - MAX_ITEMS + CONTEXT_LINES + 1;
|
||||
else if (index <= list_offset + CONTEXT_LINES)
|
||||
new_offset = index - CONTEXT_LINES;
|
||||
else
|
||||
new_offset = list_offset;
|
||||
|
||||
if (new_offset + MAX_ITEMS > completions.length)
|
||||
new_offset = completions.length - MAX_ITEMS;
|
||||
if (new_offset < 0)
|
||||
new_offset = 0;
|
||||
|
||||
// for speed reason: just remove old item, and add the new one at the end of the list
|
||||
var items = completion_widget.getElementsByTagName("listitem");
|
||||
if (new_offset == list_offset + 1)
|
||||
{
|
||||
completion_widget.removeChild(items[0]);
|
||||
addItem(completions[index + CONTEXT_LINES], false);
|
||||
}
|
||||
else if (new_offset == list_offset - 1)
|
||||
{
|
||||
completion_widget.removeChild(items[items.length-1]);
|
||||
addItem(completions[index - CONTEXT_LINES], true);
|
||||
}
|
||||
else if (new_offset == list_offset)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
fill(new_offset);
|
||||
|
||||
list_offset = new_offset;
|
||||
completion_widget.selectedIndex = index - list_offset;
|
||||
}
|
||||
}
|
||||
|
||||
// function PreviewWindow()
|
||||
// {
|
||||
// var completion_widget = document.getElementById("vim-preview_window");
|
||||
// }
|
||||
// PreviewWindow.protoype = new CompletionList;
|
||||
// var pw = new PreviewWindow();
|
||||
472
chrome/content/vimperator/find.js
Normal file
472
chrome/content/vimperator/find.js
Normal file
@@ -0,0 +1,472 @@
|
||||
/***** BEGIN LICENSE BLOCK *****
|
||||
Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
||||
The contents of this file are subject to the Mozilla Public License Version
|
||||
1.1 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
http://www.mozilla.org/MPL/
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS" basis,
|
||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
for the specific language governing rights and limitations under the
|
||||
License.
|
||||
|
||||
The Initial Developer of the Original Code is Shawn Betts.
|
||||
Portions created by the Initial Developer are Copyright (C) 2004,2005
|
||||
by the Initial Developer. All Rights Reserved.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
use your version of this file under the terms of the MPL, indicate your
|
||||
decision by deleting the provisions above and replace them with the notice
|
||||
and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the MPL, the GPL or the LGPL.
|
||||
***** END LICENSE BLOCK *****/
|
||||
|
||||
// Finder for vimperator
|
||||
// Author: Nigel McNie <http://nigel.mcnie.name/>
|
||||
// Original Author: Shawn Betts
|
||||
//
|
||||
// The algorithm was taken from conkeror <http://conkeror.mozdev.net/>, but
|
||||
// extensively refactored and changed to behave like vim (naturally!)
|
||||
|
||||
// The window to search in (which frame)
|
||||
//var gWin = null;
|
||||
//var gSelCtrl = null;
|
||||
|
||||
//function highlight(range, node) {
|
||||
// var startContainer = range.startContainer;
|
||||
// var startOffset = range.startOffset;
|
||||
// var endOffset = range.endOffset;
|
||||
// var docfrag = range.extractContents();
|
||||
// var before = startContainer.splitText(startOffset);
|
||||
// var parent = before.parentNode;
|
||||
// node.appendChild(docfrag);
|
||||
// parent.insertBefore(node, before);
|
||||
// return node;
|
||||
//}
|
||||
|
||||
// Clears the current selection
|
||||
// @todo this should be in vimperator.js, and not depend on searcher.gSelCtrl
|
||||
function clearSelection() {
|
||||
//var selctrl = gSelCtrl;
|
||||
var selctrl = vimperator.search.gSelCtrl;
|
||||
var sel = selctrl.getSelection(Components.interfaces.nsISelectionController.SELECTION_NORMAL);
|
||||
sel.removeAllRanges();
|
||||
}
|
||||
|
||||
// Sets what is currently selected
|
||||
// @todo as for clearSelection
|
||||
function setSelection(range) {
|
||||
try {
|
||||
var selctrlcomp = Components.interfaces.nsISelectionController;
|
||||
//var selctrl = gSelCtrl;
|
||||
var selctrl = vimperator.search.gSelCtrl;
|
||||
var sel = selctrl.getSelection(selctrlcomp.SELECTION_NORMAL);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range.cloneRange());
|
||||
|
||||
selctrl.scrollSelectionIntoView(selctrlcomp.SELECTION_NORMAL,
|
||||
selctrlcomp.SELECTION_FOCUS_REGION,
|
||||
true);
|
||||
}
|
||||
catch (e) {
|
||||
alert("setSelection: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight find matches and move selection to the first occurrence
|
||||
// starting from pt.
|
||||
// @todo move into searcher and clean up
|
||||
function highlightFind(str, color, wrapped, dir, pt)
|
||||
{
|
||||
try {
|
||||
var gWin = vimperator.search.gWin;//document.commandDispatcher.focusedWindow;
|
||||
if (!gWin) {
|
||||
alert('gWin does not exist here...');
|
||||
alert(vimperator.search.gWin);
|
||||
}
|
||||
var doc = gWin.document;
|
||||
var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance()
|
||||
.QueryInterface(Components.interfaces.nsIFind);
|
||||
var searchRange;
|
||||
var startPt;
|
||||
var endPt;
|
||||
var body = doc.body;
|
||||
|
||||
finder.findBackwards = !dir;
|
||||
|
||||
searchRange = doc.createRange();
|
||||
startPt = doc.createRange();
|
||||
endPt = doc.createRange();
|
||||
|
||||
var count = body.childNodes.length;
|
||||
|
||||
// Search range in the doc
|
||||
searchRange.setStart(body,0);
|
||||
searchRange.setEnd(body, count);
|
||||
|
||||
if (!dir) {
|
||||
if (pt == null) {
|
||||
startPt.setStart(body, count);
|
||||
startPt.setEnd(body, count);
|
||||
} else {
|
||||
startPt.setStart(pt.startContainer, pt.startOffset);
|
||||
startPt.setEnd(pt.startContainer, pt.startOffset);
|
||||
}
|
||||
endPt.setStart(body, 0);
|
||||
endPt.setEnd(body, 0);
|
||||
} else {
|
||||
if (pt == null) {
|
||||
startPt.setStart(body, 0);
|
||||
startPt.setEnd(body, 0);
|
||||
} else {
|
||||
startPt.setStart(pt.endContainer, pt.endOffset);
|
||||
startPt.setEnd(pt.endContainer, pt.endOffset);
|
||||
}
|
||||
endPt.setStart(body, count);
|
||||
endPt.setEnd(body, count);
|
||||
}
|
||||
// search the doc
|
||||
var retRange = null;
|
||||
var selectionRange = null;
|
||||
|
||||
if (!wrapped) {
|
||||
do {
|
||||
retRange = finder.Find(str, searchRange, startPt, endPt);
|
||||
var keepSearching = false;
|
||||
if (retRange) {
|
||||
var sc = retRange.startContainer;
|
||||
var ec = retRange.endContainer;
|
||||
var scp = sc.parentNode;
|
||||
var ecp = ec.parentNode;
|
||||
var sy1 = abs_point(scp).y;
|
||||
var ey2 = abs_point(ecp).y + ecp.offsetHeight;
|
||||
|
||||
startPt = retRange.startContainer.ownerDocument.createRange();
|
||||
if (!dir) {
|
||||
startPt.setStart(retRange.startContainer, retRange.startOffset);
|
||||
startPt.setEnd(retRange.startContainer, retRange.startOffset);
|
||||
} else {
|
||||
startPt.setStart(retRange.endContainer, retRange.endOffset);
|
||||
startPt.setEnd(retRange.endContainer, retRange.endOffset);
|
||||
}
|
||||
// We want to find a match that is completely
|
||||
// visible, otherwise the view will scroll just a
|
||||
// bit to fit the selection in completely.
|
||||
// alert ("sy1: " + sy1 + " scry: " + gWin.scrollY);
|
||||
// alert ("ey2: " + ey2 + " bot: " + (gWin.scrollY + gWin.innerHeight));
|
||||
keepSearching = (dir && sy1 < gWin.scrollY)
|
||||
|| (!dir && ey2 >= gWin.scrollY + gWin.innerHeight);
|
||||
}
|
||||
} while (retRange && keepSearching);
|
||||
} else {
|
||||
retRange = finder.Find(str, searchRange, startPt, endPt);
|
||||
}
|
||||
|
||||
if (retRange) {
|
||||
setSelection(retRange);
|
||||
selectionRange = retRange.cloneRange();
|
||||
// highlightAllBut(str, retRange, color);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return selectionRange;
|
||||
} catch(e) { alert('highlightFind:'+e); }
|
||||
}
|
||||
|
||||
function clearHighlight()
|
||||
{
|
||||
var win = window._content;
|
||||
var doc = win.document;
|
||||
if (!document)
|
||||
return;
|
||||
|
||||
var elem = null;
|
||||
while ((elem = doc.getElementById("__vimperator-findbar-search-id"))) {
|
||||
var child = null;
|
||||
var docfrag = doc.createDocumentFragment();
|
||||
var next = elem.nextSibling;
|
||||
var parent = elem.parentNode;
|
||||
while((child = elem.firstChild)) {
|
||||
docfrag.appendChild(child);
|
||||
}
|
||||
parent.removeChild(elem);
|
||||
parent.insertBefore(docfrag, next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the absolute X and Y co-ordinates of a given node from the top left of
|
||||
* the document
|
||||
*
|
||||
* Taken from conkeror utils.js
|
||||
*/
|
||||
function abs_point (node) {
|
||||
var orig = node;
|
||||
var pt = {};
|
||||
try {
|
||||
pt.x = node.offsetLeft;
|
||||
pt.y = node.offsetTop;
|
||||
|
||||
// Find imagemap's coordinates
|
||||
if (node.tagName == "AREA") {
|
||||
var coords = node.getAttribute("coords").split(",");
|
||||
pt.x += Number(coords[0]);
|
||||
pt.y += Number(coords[1]);
|
||||
}
|
||||
|
||||
node = node.offsetParent;
|
||||
|
||||
while (node.tagName != "BODY") {
|
||||
pt.x += node.offsetLeft;
|
||||
pt.y += node.offsetTop;
|
||||
node = node.offsetParent;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
// Vimperator searcher
|
||||
// make sure you only create this object when the "vimperator" object is ready
|
||||
//Vimperator.prototype.search = new function()
|
||||
function Search()
|
||||
{
|
||||
var self = this; // needed for callbacks since "this" is the "vimperator" object in a callback
|
||||
this.gWin = null;
|
||||
this.gSelCtrl = null;
|
||||
this.gFindState = [];
|
||||
|
||||
// Event handlers for search - closure is needed
|
||||
vimperator.registerCallback("change", MODE_SEARCH, function(command){ self.searchKeyPressed(command); });
|
||||
vimperator.registerCallback("submit", MODE_SEARCH, function(command){ self.searchSubmitted(command); });
|
||||
vimperator.registerCallback("cancel", MODE_SEARCH, function(){ self.searchCancelled(); });
|
||||
|
||||
|
||||
// Called when the search dialog is asked for. Sets up everything necessary
|
||||
// for this round of searching
|
||||
this.openSearchDialog = function() {
|
||||
// Get a reference to the focused window if necessary
|
||||
if (this.gWin == null) this.gWin = document.commandDispatcher.focusedWindow;
|
||||
|
||||
// Change the currently selected text to not be the attention colour
|
||||
// @todo: check what this REALLY does
|
||||
try {
|
||||
this.gSelCtrl = this.getFocusedSelCtrl();
|
||||
this.gSelCtrl.setDisplaySelection(Components.interfaces.nsISelectionController.SELECTION_ATTENTION);
|
||||
this.gSelCtrl.repaintSelection(Components.interfaces.nsISelectionController.SELECTION_NORMAL);
|
||||
}
|
||||
catch (e) {
|
||||
alert('Could not change the colour of the current selection:' + e);
|
||||
}
|
||||
|
||||
// Initialize the state list for this attempt at searching
|
||||
var state = this.createInitialFindState();
|
||||
this.gFindState = [];
|
||||
this.gFindState.push(state);
|
||||
this.resumeFindState(state);
|
||||
|
||||
vimperator.commandline.open('/', '', MODE_SEARCH);
|
||||
}
|
||||
|
||||
// Called when the current search needs to be repeated in the forward
|
||||
// direction
|
||||
// @todo will need re-jigging when reverse search comes in
|
||||
this.findNext = function() {
|
||||
this.find(this.lastFindState()["search-str"], true, this.lastFindState()["range"]);
|
||||
this.resumeFindState(this.lastFindState());
|
||||
// if there is still a search result
|
||||
if (this.lastFindState()["range"]) {
|
||||
if (this.lastFindState()["wrapped"]) {
|
||||
vimperator.echoerr("search hit BOTTOM, continuing at TOP");
|
||||
this.lastFindState()["wrapped"] = false;
|
||||
}
|
||||
else {
|
||||
// TODO: this could probably be done in a nicer way - perhaps
|
||||
// echoErr could not clobber all of this information somehow?
|
||||
vimperator.echo('/' + this.lastFindState()["search-str"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the current search needs to be repeated in the backward
|
||||
// direction
|
||||
this.findPrevious = function() {
|
||||
this.find(this.lastFindState()["search-str"], false, this.lastFindState()["range"]);
|
||||
this.resumeFindState(this.lastFindState());
|
||||
// if there is still a search result
|
||||
if (this.lastFindState()["range"]) {
|
||||
if (this.lastFindState()["wrapped"]) {
|
||||
vimperator.echoerr("search hit TOP, continuing at BOTTOM");
|
||||
this.lastFindState()["wrapped"] = false;
|
||||
}
|
||||
else {
|
||||
vimperator.echo('/' + this.lastFindState()["search-str"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the user types a key in the search dialog. Triggers a find attempt
|
||||
this.searchKeyPressed = function(command) {
|
||||
//this.find(command_line.value, true, this.lastFindState()["point"]);
|
||||
if (command != "") {
|
||||
this.find(vimperator.commandline.getCommand(), true, this.lastFindState()["point"]);
|
||||
this.resumeFindState(this.lastFindState());
|
||||
}
|
||||
else {
|
||||
clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the enter key is pressed to trigger a search
|
||||
this.searchSubmitted = function(command) {
|
||||
removeMode(MODE_SEARCH);
|
||||
if (this.lastFindState()["range"] == null) {
|
||||
vimperator.echoerr("E492: Pattern not found: " + this.lastFindState()["search-str"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the search is cancelled - for example if someone presses
|
||||
// escape while typing a search
|
||||
this.searchCancelled = function() {
|
||||
removeMode(MODE_SEARCH);
|
||||
clearSelection();
|
||||
focusContent(true, true);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Helper methods
|
||||
//
|
||||
|
||||
// Turn on the selection in all frames
|
||||
// @todo to tell the truth, I have no idea what this does
|
||||
this.getFocusedSelCtrl = function() {
|
||||
var ds = getBrowser().docShell;
|
||||
var dsEnum = ds.getDocShellEnumerator(Components.interfaces.nsIDocShellTreeItem.typeContent,
|
||||
Components.interfaces.nsIDocShell.ENUMERATE_FORWARDS);
|
||||
while (dsEnum.hasMoreElements()) {
|
||||
ds = dsEnum.getNext().QueryInterface(Components.interfaces.nsIDocShell);
|
||||
if (ds.hasFocus) {
|
||||
var display = ds.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsISelectionDisplay);
|
||||
if (!display) return null;
|
||||
return display.QueryInterface(Components.interfaces.nsISelectionController);
|
||||
}
|
||||
}
|
||||
|
||||
// One last try
|
||||
return getBrowser().docShell
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsISelectionDisplay)
|
||||
.QueryInterface(Components.interfaces.nsISelectionController);
|
||||
}
|
||||
|
||||
// Creates a default find state
|
||||
this.createInitialFindState = function() {
|
||||
var state = new Array();
|
||||
state["screenx"] = this.gWin.scrollX;
|
||||
state["screeny"] = this.gWin.scrollY;
|
||||
state["search-str"] = "";
|
||||
state["wrapped"] = false;
|
||||
state["point"] = null;
|
||||
state["range"] = document.createRange();
|
||||
state["selection"] = null;
|
||||
state["direction"] = true;
|
||||
return state;
|
||||
}
|
||||
|
||||
// Given a find state, moves the browser to the way it should be in the
|
||||
// state - highlighting the correct thing and the screen scrolled to the
|
||||
// correct location
|
||||
this.resumeFindState = function(state) {
|
||||
if (state["selection"]) {
|
||||
setSelection(state["selection"]);
|
||||
}
|
||||
else {
|
||||
clearSelection();
|
||||
}
|
||||
this.gWin.scrollTo(state["screenx"], state["screeny"]);
|
||||
}
|
||||
|
||||
// Retrieves the current find state that we're in
|
||||
// @todo rename to currentFindState?
|
||||
this.lastFindState = function() {
|
||||
return this.gFindState[this.gFindState.length - 1];
|
||||
}
|
||||
|
||||
// Adds a find state to the stack of such states. This is done every time a find is successful
|
||||
this.addFindState = function(screenX, screenY, searchStr, wrapped, point, range, selection, direction) {
|
||||
var state = new Array();
|
||||
state["screenx"] = screenX;
|
||||
state["screeny"] = screenY;
|
||||
state["search-str"] = searchStr;
|
||||
state["wrapped"] = wrapped;
|
||||
state["point"] = point;
|
||||
state["range"] = range;
|
||||
state["selection"] = selection;
|
||||
state["direction"] = direction;
|
||||
this.gFindState.push(state);
|
||||
}
|
||||
|
||||
// Finds text in a page
|
||||
this.find = function(str, dir, pt) {
|
||||
var norecurse = arguments[3];
|
||||
|
||||
var matchRange;
|
||||
clearHighlight();
|
||||
|
||||
// Should we wrap this time?
|
||||
var wrapped = this.lastFindState()["wrapped"];
|
||||
var point = pt;
|
||||
if (this.lastFindState()["wrapped"] == false
|
||||
&& this.lastFindState()["range"] == null
|
||||
&& this.lastFindState()["search-str"] == str
|
||||
&& this.lastFindState()["direction"] == dir) {
|
||||
wrapped = true;
|
||||
point = null;
|
||||
}
|
||||
matchRange = highlightFind(str, "lightblue", wrapped, dir, point);
|
||||
if (matchRange == null) {
|
||||
// No more matches in this direction. So add the state and then find
|
||||
// again to wrap around. But only find again once to prevent infinite
|
||||
// recursion if an error occurs
|
||||
this.addFindState(this.gWin.scrollX, this.gWin.scrollY, str, wrapped, point,
|
||||
matchRange, this.lastFindState()["selection"], dir);
|
||||
if (!norecurse)
|
||||
this.find(str, dir, pt, true);
|
||||
}
|
||||
else {
|
||||
this.addFindState(this.gWin.scrollX, this.gWin.scrollY, str, wrapped,
|
||||
point, matchRange, matchRange, dir);
|
||||
}
|
||||
}
|
||||
|
||||
//logObject(vimperator);
|
||||
logMessage("Search initialized.");
|
||||
}
|
||||
|
||||
//searcher = new searcher();
|
||||
//vimperator.registerCallback("submit", MODE_SEARCH, function(command) { /*vimperator.*/alert(command); } );
|
||||
//vimperator.registerCallback("change", MODE_SEARCH, function(command) { /*vimperator.*/alert(command); } );
|
||||
|
||||
// @todo nicer way to register commands?
|
||||
g_commands.push(
|
||||
[
|
||||
["nohilight", "noh"],
|
||||
["noh[ilight]"],
|
||||
"Clear the current selection",
|
||||
"",
|
||||
clearSelection,
|
||||
null
|
||||
]
|
||||
);
|
||||
Reference in New Issue
Block a user