Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 613 lines (525 sloc) 21.863 kB
aff9db2 @philc Initial project commit
philc authored
1 <html>
2 <head>
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
3 <script type="text/javascript" src="commands.js"/>
aff9db2 @philc Initial project commit
philc authored
4 <script type="text/javascript" charset="utf-8">
0b2b70d @philc Add a link to the Options page in the vimium help dialog. Closes #87.
philc authored
5 // Chromium #15242 will make this XHR request to access the manifest unnecessary.
14676a2 Pull the version number from the manifest file instead of hard coding it
Phil Crosby authored
6 var manifestRequest = new XMLHttpRequest();
7 manifestRequest.open("GET", chrome.extension.getURL("manifest.json"), false);
8 manifestRequest.send(null);
9
10 var currentVersion = JSON.parse(manifestRequest.responseText).version;
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
11
961354e @ilya Keep tab queue per-window instead of globally. This mirrors behavior …
ilya authored
12 var tabQueue = {}; // windowId -> Array
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
13 var openTabs = {}; // tabId -> object with various tab properties
e0d5fbd @ilya Some cleanup.
ilya authored
14 var keyQueue = ""; // Queue of keys typed
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
15 var validFirstKeys = {};
4c788df a few style changes per phil's comments
Ilya authored
16 var singleKeyCommands = [];
e0d5fbd @ilya Some cleanup.
ilya authored
17
fbbba41 @ilya Some minor style changes.
ilya authored
18 var hasModifierRegex = /^<[amc]-.>/;
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
19
3f1cdef @philc Make the characters used in link hints a user-configurable option. Fi…
philc authored
20 var defaultSettings = {
21 scrollStepSize: 60,
22 defaultZoomLevel: 100,
5322490 @philc Add two more characters to the pool that link hints pulls from.
philc authored
23 linkHintCharacters: "sadfjklewcmpgh",
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
24 userDefinedLinkHintCss:
25 ".vimiumHintMarker {\n\n}\n" +
26 ".vimiumHintMarker > .matchingCharacter {\n\n}"
3f1cdef @philc Make the characters used in link hints a user-configurable option. Fi…
philc authored
27 };
1d12639 @ilya First pass at a settings page. Hooked up scrollStepSize as our first …
ilya authored
28
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
29 // This is the base internal link hints CSS. It's combined with the userDefinedLinkHintCss before
30 // being sent to the frontend.
31 var linkHintCss =
32 '.internalVimiumHintMarker {' +
29d0b9c @philc Add the link hint markers to the DOM all at once instead of piecemeal…
philc authored
33 'position:absolute;' +
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
34 'background-color:yellow;' +
35 'color:black;' +
36 'font-weight:bold;' +
37 'font-size:12px;' +
38 'padding:0 1px;' +
39 'line-height:100%;' +
40 'width:auto;' +
41 'display:block;' +
42 'border:1px solid #E3BE23;' +
43 'z-index:99999999;' +
44 'font-family:"Helvetica Neue", "Helvetica", "Arial", "Sans";' +
c85917a @ilya Small modification to Bill's fix.
ilya authored
45 'top:-1px;' +
46 'left:-1px;' +
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
47 '}' +
48 '.internalVimiumHintMarker > .matchingCharacter {' +
49 'color:#C79F0B;' +
50 '}';
51
52
e0d5fbd @ilya Some cleanup.
ilya authored
53 // Port handler mapping
b1f850a Remove some unnecessary indentation
Phil Crosby authored
54 var portHandlers = {
55 keyDown: handleKeyDown,
56 returnScrollPosition: handleReturnScrollPosition,
376e3a5 Add support for excluded URL patterns; these URL patterns can be conf…
Phil Crosby authored
57 isEnabledForUrl: isEnabledForUrl,
b1f850a Remove some unnecessary indentation
Phil Crosby authored
58 getCurrentTabUrl: getCurrentTabUrl,
59 getZoomLevel: getZoomLevel,
60 saveZoomLevel: saveZoomLevel,
61 getSetting: getSetting
62 };
e0d5fbd @ilya Some cleanup.
ilya authored
63
b00f990 @ilya Expose completion keys via sendRequest interface in background page.
ilya authored
64 var sendRequestHandlers = {
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
65 getCompletionKeys: getCompletionKeys,
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
66 getLinkHintCss: getLinkHintCss,
0b2b70d @philc Add a link to the Options page in the vimium help dialog. Closes #87.
philc authored
67 openOptionsPageInNewTab: openOptionsPageInNewTab,
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
68 upgradeNotificationClosed: upgradeNotificationClosed,
69 updateScrollPosition: handleUpdateScrollPosition
b00f990 @ilya Expose completion keys via sendRequest interface in background page.
ilya authored
70 };
b150643 @ilya Add infrastructure to handle sendRequest calls in the background page.
ilya authored
71
e0d5fbd @ilya Some cleanup.
ilya authored
72 // Event handlers
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
73 var selectionChangedHandlers = [];
abfd4dc @philc Remove space after the "function" keyword.
philc authored
74 var getScrollPositionHandlers = {}; // tabId -> function(tab, scrollX, scrollY);
75 var tabLoadedHandlers = {}; // tabId -> function()
10c33ba @ilya Implement basic tab restore functionality (the 'u' command).
ilya authored
76
aff9db2 @philc Initial project commit
philc authored
77 chrome.extension.onConnect.addListener(function(port, name) {
5e472a0 @philc Set the scroll position of a restored tab once the content script is …
philc authored
78 var senderTabId = port.sender.tab ? port.sender.tab.id : null;
79 // If this is a tab we've been waiting to open, execute any "tab loaded" handlers, e.g. to restore
a1f3e89 @philc Break the content script's initialization into two stages, so we can …
philc authored
80 // the tab's scroll position. Wait until domReady before doing this; otherwise operations like restoring
81 // the scroll position will not be possible.
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
82 if (port.name == "domReady" && senderTabId != null) {
83 if (tabLoadedHandlers[senderTabId]) {
84 var toCall = tabLoadedHandlers[senderTabId];
85 // Delete first to be sure there's no circular events.
86 delete tabLoadedHandlers[senderTabId];
87 toCall.call();
88 }
89
90 // domReady is the appropriate time to show the "vimium has been upgraded" message.
91 if (shouldShowUpgradeMessage())
92 chrome.tabs.sendRequest(senderTabId, { name: "showUpgradeNotification", version: currentVersion });
5e472a0 @philc Set the scroll position of a restored tab once the content script is …
philc authored
93 }
94
e0d5fbd @ilya Some cleanup.
ilya authored
95 if (portHandlers[port.name])
96 port.onMessage.addListener(portHandlers[port.name]);
5e472a0 @philc Set the scroll position of a restored tab once the content script is …
philc authored
97
aff9db2 @philc Initial project commit
philc authored
98 });
6f8fb89 @ilya Add tab create and remove to the new system, disable the old system.
ilya authored
99
b150643 @ilya Add infrastructure to handle sendRequest calls in the background page.
ilya authored
100 chrome.extension.onRequest.addListener(function (request, sender, sendResponse) {
101 var senderTabId = sender.tab ? sender.tab.id : null;
102 if (sendRequestHandlers[request.handler])
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
103 sendResponse(sendRequestHandlers[request.handler](request, sender));
b150643 @ilya Add infrastructure to handle sendRequest calls in the background page.
ilya authored
104 });
105
0d8394d @ilya Save scroll position for removed tabs.
ilya authored
106 function handleReturnScrollPosition(args) {
615a5d9 @philc Make the style consistent in a few places.
philc authored
107 if (getScrollPositionHandlers[args.currentTab.id]) {
0d8394d @ilya Save scroll position for removed tabs.
ilya authored
108 // Delete first to be sure there's no circular events.
109 var toCall = getScrollPositionHandlers[args.currentTab.id];
110 delete getScrollPositionHandlers[args.currentTab.id];
9e37412 @philc Use window.scrollX and window.scrollY instead of document.scrollLeft/…
philc authored
111 toCall(args.currentTab, args.scrollX, args.scrollY);
0d8394d @ilya Save scroll position for removed tabs.
ilya authored
112 }
113 }
114
be17ec6 @ilya Implement 'gf' -- toggle view source for the current page.
ilya authored
115 /*
116 * Used by the content scripts to get their full URL. This is needed for URLs like "view-source:http:// .."
117 * because window.location doesn't know anything about the Chrome-specific "view-source:".
118 */
9262eaa @ilya Get rid of chrome.tabs.getSelected in getCurrentTabUrl.
ilya authored
119 function getCurrentTabUrl(args, port) {
120 var returnPort = chrome.tabs.connect(port.tab.id, { name: "returnCurrentTabUrl" });
121 returnPort.postMessage({ url: port.tab.url });
be17ec6 @ilya Implement 'gf' -- toggle view source for the current page.
ilya authored
122 }
123
1d12639 @ilya First pass at a settings page. Hooked up scrollStepSize as our first …
ilya authored
124 /*
376e3a5 Add support for excluded URL patterns; these URL patterns can be conf…
Phil Crosby authored
125 * Checks the user's preferences in local storage to determine if Vimium is enabled for the given URL.
126 */
127 function isEnabledForUrl(args, port) {
128 var returnPort = chrome.tabs.connect(port.tab.id, { name: "returnIsEnabledForUrl" });
129 // excludedUrls are stored as a series of URL expressions separated by newlines.
130 var excludedUrls = (localStorage["excludedUrls"] || "").split("\n");
131 var isEnabled = true;
132 for (var i = 0; i < excludedUrls.length; i++) {
133 // The user can add "*" to the URL which means ".*"
134 var regexp = new RegExp("^" + excludedUrls[i].replace(/\*/g, ".*") + "$");
135 if (args.url.match(regexp))
136 isEnabled = false;
137 }
138 returnPort.postMessage({ isEnabledForUrl: isEnabled });
139 }
140
141 /*
6042b7f @philc Persist the current zoom level to local storage, and restore the page…
philc authored
142 * Returns the previously saved zoom level for the current tab, or the default zoom level
143 */
b04b032 @philc Avoid using getSelected in getSetting and getZoomLevel, because the t…
philc authored
144 function getZoomLevel(args, port) {
145 var returnPort = chrome.tabs.connect(port.tab.id, { name: "returnZoomLevel" });
146 var localStorageKey = "zoom" + args.domain;
147 var zoomLevelForDomain = (localStorage[localStorageKey] || "").split(",")[1];
f24f6e5 @philc Have the Options page use the default settings hash defined in backgr…
philc authored
148 var zoomLevel = parseInt(zoomLevelForDomain || localStorage["defaultZoomLevel"] ||
8028cfb @philc Fix a reference error over the default settings in the background page.
philc authored
149 defaultSettings.defaultZoomLevel);
b04b032 @philc Avoid using getSelected in getSetting and getZoomLevel, because the t…
philc authored
150 returnPort.postMessage({ zoomLevel: zoomLevel });
6042b7f @philc Persist the current zoom level to local storage, and restore the page…
philc authored
151 }
152
70b8c39 Show a help dialog when pressing ? which displays all of the current …
Phil Crosby authored
153 function showHelp() {
154 chrome.tabs.getSelected(null, function(tab) {
155 chrome.tabs.sendRequest(tab.id, { name: "showHelpDialog", dialogHtml: helpDialogHtml() });
156 });
157 }
158
159 /*
160 * Retrieves the help dialog HTML template from a file, and populates it with the latest keybindings.
161 */
3a73fdc @ilya Add a dialog to show all available commands for key mappings under th…
ilya authored
162 function helpDialogHtml(showUnboundCommands, showCommandNames, customTitle) {
70b8c39 Show a help dialog when pressing ? which displays all of the current …
Phil Crosby authored
163 var commandsToKey = {};
164 for (var key in keyToCommandRegistry) {
165 var command = keyToCommandRegistry[key].command;
166 commandsToKey[command] = (commandsToKey[command] || []).concat(key);
167 }
168 var dialogHtml = fetchFileContents("helpDialog.html");
169 for (var group in commandGroups)
170 dialogHtml = dialogHtml.replace("{{" + group + "}}",
3a73fdc @ilya Add a dialog to show all available commands for key mappings under th…
ilya authored
171 helpDialogHtmlForCommandGroup(group, commandsToKey, availableCommands,
172 showUnboundCommands, showCommandNames));
c1a94a8 Display the current version in the help dialog. Hide link to homepage.
Phil Crosby authored
173 dialogHtml = dialogHtml.replace("{{version}}", currentVersion);
3a73fdc @ilya Add a dialog to show all available commands for key mappings under th…
ilya authored
174 dialogHtml = dialogHtml.replace("{{title}}", customTitle || "Help");
70b8c39 Show a help dialog when pressing ? which displays all of the current …
Phil Crosby authored
175 return dialogHtml;
176 }
177
178 /*
179 * Generates HTML for a given set of commands. commandGroups are defined in commands.js
180 */
3a73fdc @ilya Add a dialog to show all available commands for key mappings under th…
ilya authored
181 function helpDialogHtmlForCommandGroup(group, commandsToKey, availableCommands,
182 showUnboundCommands, showCommandNames) {
70b8c39 Show a help dialog when pressing ? which displays all of the current …
Phil Crosby authored
183 var html = [];
184 for (var i = 0; i < commandGroups[group].length; i++) {
185 var command = commandGroups[group][i];
3a73fdc @ilya Add a dialog to show all available commands for key mappings under th…
ilya authored
186 bindings = (commandsToKey[command] || [""]).join(", ")
187 if (showUnboundCommands || commandsToKey[command])
188 {
189 html.push("<tr><td>", escapeHtml(bindings),
190 "</td><td>:</td><td>", availableCommands[command].description);
191
192 if (showCommandNames)
193 html.push("<span class='commandName'>(" + command + ")</span>");
194
195 html.push("</td></tr>");
196 }
70b8c39 Show a help dialog when pressing ? which displays all of the current …
Phil Crosby authored
197 }
198 return html.join("\n");
199 }
200
201 function escapeHtml(string) { return string.replace(/</g, "&lt;").replace(/>/g, "&gt;"); }
202
203 /*
204 * Fetches the contents of a file bundled with this extension.
205 */
206 function fetchFileContents(extensionFileName) {
207 var req = new XMLHttpRequest();
208 req.open("GET", chrome.extension.getURL(extensionFileName), false); // false => synchronous
209 req.send();
210 return req.responseText;
211 }
212
b00f990 @ilya Expose completion keys via sendRequest interface in background page.
ilya authored
213 /**
214 * Returns the keys that can complete a valid command given the current key queue.
215 */
216 function getCompletionKeys(request) {
217 return {completionKeys: generateCompletionKeys()};
218 }
219
6042b7f @philc Persist the current zoom level to local storage, and restore the page…
philc authored
220 /*
0dfae3a @philc Move the link hints CSS to the background page, and create a setting …
philc authored
221 * Returns the core CSS used for link hints, along with any user-provided overrides.
222 */
223 function getLinkHintCss(request) {
224 return { linkHintCss: linkHintCss + (localStorage['userDefinedLinkHintCss'] || "") };
225 }
226
227 /*
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
228 * Called when the user has clicked the close icon on the "Vimium has been updated" message.
229 * We should now dismiss that message in all tabs.
230 */
231 function upgradeNotificationClosed(request) {
232 localStorage.previousVersion = currentVersion;
233 sendRequestToAllTabs({ name: "hideUpgradeNotification" });
234 }
235
236 /*
1d12639 @ilya First pass at a settings page. Hooked up scrollStepSize as our first …
ilya authored
237 * Used by the content scripts to get settings from the local storage.
238 */
b04b032 @philc Avoid using getSelected in getSetting and getZoomLevel, because the t…
philc authored
239 function getSetting(args, port) {
1d12639 @ilya First pass at a settings page. Hooked up scrollStepSize as our first …
ilya authored
240 var value = localStorage[args.key] ? localStorage[args.key] : defaultSettings[args.key];
241
b04b032 @philc Avoid using getSelected in getSetting and getZoomLevel, because the t…
philc authored
242 var returnPort = chrome.tabs.connect(port.tab.id, { name: "returnSetting" });
243 returnPort.postMessage({ key: args.key, value: value });
1d12639 @ilya First pass at a settings page. Hooked up scrollStepSize as our first …
ilya authored
244 }
245
6042b7f @philc Persist the current zoom level to local storage, and restore the page…
philc authored
246 /*
247 * Persists the current zoom level for a given domain
248 */
249 function saveZoomLevel(args) {
250 var localStorageKey = "zoom" + args.domain;
251 // TODO(philc): We might want to consider expiring these entries after X months as NoSquint does.
252 // Note(philc): We might also want to jsonify this hash instead of polluting our local storage keyspace.
253 localStorage[localStorageKey] = [getCurrentTimeInSeconds(), args.zoomLevel].join(",");
254 }
255
256 function getCurrentTimeInSeconds() { Math.floor((new Date()).getTime() / 1000); }
257
258 chrome.tabs.onSelectionChanged.addListener(function(tabId, selectionInfo) {
e0d5fbd @ilya Some cleanup.
ilya authored
259 if (selectionChangedHandlers.length > 0) { selectionChangedHandlers.pop().call(); }
260 });
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
261
262 function repeatFunction(func, totalCount, currentCount) {
263 if (currentCount < totalCount)
6042b7f @philc Persist the current zoom level to local storage, and restore the page…
philc authored
264 func(function() { repeatFunction(func, totalCount, currentCount + 1); });
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
265 }
266
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
267 // Returns the scroll coordinates of the given tab. Pass in a callback of the form:
abfd4dc @philc Remove space after the "function" keyword.
philc authored
268 // function(tab, scrollX, scrollY) { .. }
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
269 function getScrollPosition(tab, callback) {
270 getScrollPositionHandlers[tab.id] = callback;
271 var scrollPort = chrome.tabs.connect(tab.id, { name: "getScrollPosition" });
272 scrollPort.postMessage({currentTab: tab});
0d8394d @ilya Save scroll position for removed tabs.
ilya authored
273 }
274
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
275 // Start action functions
276 function createTab(callback) {
615a5d9 @philc Make the style consistent in a few places.
philc authored
277 chrome.tabs.create({}, function(tab) { callback(); });
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
278 }
279
b9bf74f @ilya Fix chaining of previousTab/nextTab commands. This closes #93.
ilya authored
280 function nextTab(callback) { selectTab(callback, "next"); }
281 function previousTab(callback) { selectTab(callback, "previous"); }
10c0d5b @philc Add commands for selecting the next tab and previous tab.
philc authored
282
283 /*
284 * Selects a tab before or after the currently selected tab. Direction is either "next" or "previous".
285 */
b9bf74f @ilya Fix chaining of previousTab/nextTab commands. This closes #93.
ilya authored
286 function selectTab(callback, direction) {
10c0d5b @philc Add commands for selecting the next tab and previous tab.
philc authored
287 chrome.tabs.getAllInWindow(null, function(tabs) {
288 if (tabs.length <= 1)
289 return;
290 for (var i = 0; i < tabs.length; i++) {
291 if (tabs[i].selected) {
292 var delta = (direction == "next") ? 1 : -1;
293 var toSelect = tabs[(i + delta + tabs.length) % tabs.length];
b9bf74f @ilya Fix chaining of previousTab/nextTab commands. This closes #93.
ilya authored
294 selectionChangedHandlers.push(callback);
10c0d5b @philc Add commands for selecting the next tab and previous tab.
philc authored
295 chrome.tabs.update(toSelect.id, { selected: true });
296 break;
297 }
298 }
299 });
300 }
301
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
302 function removeTab(callback) {
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
303 chrome.tabs.getSelected(null, function(tab) {
b1f850a Remove some unnecessary indentation
Phil Crosby authored
304 chrome.tabs.remove(tab.id);
305 // We can't just call the callback here because we actually need to wait
306 // for the selection to change to consider this action done.
307 selectionChangedHandlers.push(callback);
308 });
10c33ba @ilya Implement basic tab restore functionality (the 'u' command).
ilya authored
309 }
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
310
7f87e20 Ensure Restore Tab works immediately upon extension install
unknown authored
311 function updateOpenTabs(tab) {
312 openTabs[tab.id] = { url: tab.url, positionIndex: tab.index, windowId: tab.windowId };
313 }
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
314
315 function handleUpdateScrollPosition(request, sender) {
316 updateScrollPosition(sender.tab, request.scrollX, request.scrollY);
317 }
318
319 function updateScrollPosition(tab, scrollX, scrollY) {
320 openTabs[tab.id].scrollX = scrollX;
321 openTabs[tab.id].scrollY = scrollY;
322 }
14676a2 Pull the version number from the manifest file instead of hard coding it
Phil Crosby authored
323
10c33ba @ilya Implement basic tab restore functionality (the 'u' command).
ilya authored
324
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
325 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
326 if (changeInfo.status != "loading") { return; } // only do this once per URL change
7f87e20 Ensure Restore Tab works immediately upon extension install
unknown authored
327 updateOpenTabs(tab);
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
328 });
329
330 chrome.tabs.onAttached.addListener(function(tabId, attachedInfo) {
15ca22e @ilya Add more robust support for keeping track of positions/windows when t…
ilya authored
331 // We should update all the tabs in the old window and the new window.
332 if (openTabs[tabId]) {
333 updatePositionsAndWindowsForAllTabsInWindow(openTabs[tabId].windowId);
334 }
335 updatePositionsAndWindowsForAllTabsInWindow(attachedInfo.newWindowId);
336 });
337
338 chrome.tabs.onMoved.addListener(function(tabId, moveInfo) {
339 updatePositionsAndWindowsForAllTabsInWindow(moveInfo.windowId);
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
340 });
341
342 chrome.tabs.onRemoved.addListener(function(tabId) {
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
343 var openTabInfo = openTabs[tabId];
c05ffa7 @int3 Another fix for tab positioning
int3 authored
344 updatePositionsAndWindowsForAllTabsInWindow(openTabInfo.windowId);
345
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
346 // If we restore chrome:// pages, they'll ignore Vimium keystrokes when they reappear.
347 // Pretend they never existed and adjust tab indices accordingly.
348 // Could possibly expand this into a blacklist in the future
349 if (/^chrome[^:]*:\/\/.*/.test(openTabInfo.url)) {
72f0705 @int3 Undo 'Keep tab queue indices updated when a tab is detached'.
int3 authored
350 for (var i in tabQueue[openTabInfo.windowId]) {
351 if (tabQueue[openTabInfo.windowId][i].positionIndex > openTabInfo.positionIndex)
352 tabQueue[openTabInfo.windowId][i].positionIndex--;
353 }
d53e4b0 @ilya Apply saving of scroll positions to all tabs, no matter how they are …
ilya authored
354 return;
bdd0690 @int3 Maintain accurate tab indices while ignoring chrome://newtab
int3 authored
355 }
3d6236c @ilya Don't put the new tab page into the tab restoration queue.
ilya authored
356
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
357 if (tabQueue[openTabInfo.windowId])
a6fb613 @ilya Avoid creating a separate tabQueueEntry object when we can just reuse…
ilya authored
358 tabQueue[openTabInfo.windowId].push(openTabInfo);
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
359 else
a6fb613 @ilya Avoid creating a separate tabQueueEntry object when we can just reuse…
ilya authored
360 tabQueue[openTabInfo.windowId] = [openTabInfo];
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
361
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
362 delete openTabs[tabId];
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
363 });
f8a4d24 @ilya whitespace
ilya authored
364
e773a00 Fix memory leak from tabQueue
unknown authored
365 chrome.windows.onRemoved.addListener(function(windowId) {
366 delete tabQueue[windowId];
367 });
9b7d707 Restore Tab now recreates the tab in its old position.
unknown authored
368
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
369 function restoreTab(callback) {
961354e @ilya Keep tab queue per-window instead of globally. This mirrors behavior …
ilya authored
370 // TODO(ilya): Should this be getLastFocused instead?
abfd4dc @philc Remove space after the "function" keyword.
philc authored
371 chrome.windows.getCurrent(function(window) {
961354e @ilya Keep tab queue per-window instead of globally. This mirrors behavior …
ilya authored
372 if (tabQueue[window.id] && tabQueue[window.id].length > 0)
373 {
374 var tabQueueEntry = tabQueue[window.id].pop();
375
376 // Clean out the tabQueue so we don't have unused windows laying about.
377 if (tabQueue[window.id].length == 0)
378 delete tabQueue[window.id];
379
380 // We have to chain a few callbacks to set the appropriate scroll position. We can't just wait until the
381 // tab is created because the content script is not available during the "loading" state. We need to
382 // wait until that's over before we can call setScrollPosition.
ece6bc7 @ilya Clean up naming/style in the previous commit and small bugs.
ilya authored
383 chrome.tabs.create({ url: tabQueueEntry.url, index: tabQueueEntry.positionIndex }, function(tab) {
961354e @ilya Keep tab queue per-window instead of globally. This mirrors behavior …
ilya authored
384 tabLoadedHandlers[tab.id] = function() {
385 var scrollPort = chrome.tabs.connect(tab.id, {name: "setScrollPosition"});
386 scrollPort.postMessage({ scrollX: tabQueueEntry.scrollX, scrollY: tabQueueEntry.scrollY });
387 };
388
389 callback();
390 });
391 }
392 });
6f8fb89 @ilya Add tab create and remove to the new system, disable the old system.
ilya authored
393 }
db7450b @ilya String together some callbacks to properly execute multiple actions t…
ilya authored
394 // End action functions
6f8fb89 @ilya Add tab create and remove to the new system, disable the old system.
ilya authored
395
15ca22e @ilya Add more robust support for keeping track of positions/windows when t…
ilya authored
396 function updatePositionsAndWindowsForAllTabsInWindow(windowId) {
397 chrome.tabs.getAllInWindow(windowId, function (tabs) {
398 for (var i = 0; i < tabs.length; i++) {
399 var tab = tabs[i];
400 var openTabInfo = openTabs[tab.id];
401 if (openTabInfo) {
402 openTabInfo.positionIndex = tab.index;
403 openTabInfo.windowId = tab.windowId;
404 }
405 }
406 });
407 }
408
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
409 function splitKeyIntoFirstAndSecond(key) {
fbbba41 @ilya Some minor style changes.
ilya authored
410 if (key.search(hasModifierRegex) == 0)
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
411 return { first: key.slice(0, 5), second: key.slice(5) };
412 else
413 return { first: key[0], second: key.slice(1) };
414 }
415
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
416 function getActualKeyStrokeLength(key) {
fbbba41 @ilya Some minor style changes.
ilya authored
417 if (key.search(hasModifierRegex) == 0)
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
418 return 1 + getActualKeyStrokeLength(key.slice(5));
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
419 else
420 return key.length;
421 }
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
422
423 function populateValidFirstKeys() {
424 for (var key in keyToCommandRegistry)
425 {
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
426 if (getActualKeyStrokeLength(key) == 2)
427 validFirstKeys[splitKeyIntoFirstAndSecond(key).first] = true;
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
428 }
429 }
430
4c788df a few style changes per phil's comments
Ilya authored
431 function populateSingleKeyCommands() {
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
432 for (var key in keyToCommandRegistry)
433 {
434 if (getActualKeyStrokeLength(key) == 1)
4c788df a few style changes per phil's comments
Ilya authored
435 singleKeyCommands.push(key);
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
436 }
437 }
438
201e52b @ilya Refresh completion keys on all tabs and associated data structures af…
ilya authored
439 function refreshCompletionKeysAfterMappingSave() {
440 validFirstKeys = {};
441 singleKeyCommands = [];
442
443 populateValidFirstKeys();
444 populateSingleKeyCommands();
445
446 sendRequestToAllTabs({ name: "refreshCompletionKeys", completionKeys: generateCompletionKeys() });
447 }
448
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
449 /*
450 * Generates a list of keys that can complete a valid command given the current key queue or the one passed
451 * in.
452 */
453 function generateCompletionKeys(keysToCheck) {
454 var splitHash = splitKeyQueue(keysToCheck || keyQueue);
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
455 command = splitHash.command;
456 count = splitHash.count;
457
4c788df a few style changes per phil's comments
Ilya authored
458 var completionKeys = singleKeyCommands.slice(0);
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
459
460 if (getActualKeyStrokeLength(command) == 1)
461 {
462 for (var key in keyToCommandRegistry)
463 {
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
464 var splitKey = splitKeyIntoFirstAndSecond(key);
465 if (splitKey.first == command)
466 completionKeys.push(splitKey.second);
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
467 }
468 }
469
470 return completionKeys;
471 }
472
4c788df a few style changes per phil's comments
Ilya authored
473 function splitKeyQueue(queue) {
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
474 var match = /([0-9]*)(.*)/.exec(queue);
475 var count = parseInt(match[1]);
476 var command = match[2];
477
478 return {count: count, command: command};
479 }
480
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
481 function handleKeyDown(key, port) {
26ddb06 @lack ESC clears the keyQueue
lack authored
482 if (key == "<ESC>") {
483 console.log("clearing keyQueue");
484 keyQueue = ""
485 }
486 else {
487 console.log("checking keyQueue: [", keyQueue + key, "]");
488 keyQueue = checkKeyQueue(keyQueue + key, port.tab.id);
489 console.log("new KeyQueue: " + keyQueue);
490 }
1bb0d3b @ilya First pass at a better framework for mapping keys to commands.
ilya authored
491 }
492
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
493 function checkKeyQueue(keysToCheck, tabId) {
494 var refreshedCompletionKeys = false;
a4ef493 @ilya Add logic to the background page to calculate the keys that will comp…
ilya authored
495 var splitHash = splitKeyQueue(keysToCheck);
496 command = splitHash.command;
497 count = splitHash.count;
5114f02 @ilya Initial support for counts. Commands like '5j' and '5t' work pretty w…
ilya authored
498
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
499 if (command.length == 0) { return keysToCheck; }
5114f02 @ilya Initial support for counts. Commands like '5j' and '5t' work pretty w…
ilya authored
500 if (isNaN(count)) { count = 1; }
501
615a5d9 @philc Make the style consistent in a few places.
philc authored
502 if (keyToCommandRegistry[command]) {
5114f02 @ilya Initial support for counts. Commands like '5j' and '5t' work pretty w…
ilya authored
503 registryEntry = keyToCommandRegistry[command];
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
504 console.log("command found for [", keysToCheck, "],", registryEntry.command);
1bb0d3b @ilya First pass at a better framework for mapping keys to commands.
ilya authored
505
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
506 if (!registryEntry.isBackgroundCommand) {
46ffdfd @ilya Get rid of chrome.tabs.getSelected in checkKeyQueue.
ilya authored
507 var port = chrome.tabs.connect(tabId, { name: "executePageCommand" });
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
508 port.postMessage({ command: registryEntry.command, count: count,
46ffdfd @ilya Get rid of chrome.tabs.getSelected in checkKeyQueue.
ilya authored
509 completionKeys: generateCompletionKeys("") });
510
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
511 refreshedCompletionKeys = true;
615a5d9 @philc Make the style consistent in a few places.
philc authored
512 } else {
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
513 repeatFunction(this[registryEntry.command], count, 0);
1bb0d3b @ilya First pass at a better framework for mapping keys to commands.
ilya authored
514 }
5e472a0 @philc Set the scroll position of a restored tab once the content script is …
philc authored
515
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
516 newKeyQueue = "";
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
517 } else if (getActualKeyStrokeLength(command) > 1) {
518 var splitKey = splitKeyIntoFirstAndSecond(command);
519
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
520 // The second key might be a valid command by its self.
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
521 if (keyToCommandRegistry[splitKey.second])
522 newKeyQueue = checkKeyQueue(splitKey.second);
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
523 else
8bb111d @ilya Fix a bunch of key handling related bugs in one swoop.
ilya authored
524 newKeyQueue = (validFirstKeys[splitKey.second] ? splitKey.second : "");
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
525 } else {
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
526 newKeyQueue = (validFirstKeys[command] ? count.toString() + command : "");
527 }
528
529 // If we haven't sent the completion keys piggybacked on executePageCommand,
530 // send them by themselves.
531 if (!refreshedCompletionKeys)
532 {
533 var port = chrome.tabs.connect(tabId, { name: "refreshCompletionKeys" });
534 port.postMessage({ completionKeys: generateCompletionKeys(newKeyQueue) });
615a5d9 @philc Make the style consistent in a few places.
philc authored
535 }
0140985 @ilya Refresh the completion keys on every keystroke sent to the background…
ilya authored
536
537 return newKeyQueue;
1bb0d3b @ilya First pass at a better framework for mapping keys to commands.
ilya authored
538 }
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
539
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
540 /*
541 * Message all tabs. Args should be the arguments hash used by the Chrome sendRequest API.
542 */
543 function sendRequestToAllTabs(args) {
544 chrome.windows.getAll({ populate: true }, function(windows) {
545 for (var i = 0; i < windows.length; i++)
546 for (var j = 0; j < windows[i].tabs.length; j++)
547 chrome.tabs.sendRequest(windows[i].tabs[j].id, args, null);
548 });
549 }
550
551 // Compares two version strings (e.g. "1.1" and "1.5") and returns
552 // -1 if versionA is < versionB, 0 if they're equal, and 1 if versionA is > versionB.
553 function compareVersions(versionA, versionB) {
554 versionA = versionA.split(".");
555 versionB = versionB.split(".");
556 for (var i = 0; i < Math.max(versionA.length, versionB.length); i++) {
557 var a = parseInt(versionA[i] || 0);
558 var b = parseInt(versionB[i] || 0);
559 if (a < b) return -1;
560 else if (a > b) return 1;
561 }
562 return 0;
563 }
564
565 /*
566 * Returns true if the current extension version is greater than the previously recorded version in
567 * localStorage, and false otherwise.
568 */
569 function shouldShowUpgradeMessage() {
570 // Avoid showing the upgrade notification when localStorage.previousVersion is undefined, which is the
571 // case for new installs.
572 if (!localStorage.previousVersion)
573 localStorage.previousVersion = currentVersion;
574 return compareVersions(currentVersion, localStorage.previousVersion) == 1;
575 }
576
0b2b70d @philc Add a link to the Options page in the vimium help dialog. Closes #87.
philc authored
577 function openOptionsPageInNewTab() {
578 chrome.tabs.getSelected(null, function(tab) {
579 chrome.tabs.create({ url: chrome.extension.getURL("options.html"), index: tab.index + 1 });
580 });
581 }
582
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
583 function init() {
ca0622f @ilya Fix a bug where if you add a mapping, save, and then remove it -- it …
ilya authored
584 clearKeyMappingsAndSetDefaults();
585
419f7cc @ilya Key Mapping - Don't try to parse key mappings unless there's actually…
ilya authored
586 if (localStorage["keyMappings"])
587 parseCustomKeyMappings(localStorage["keyMappings"]);
588
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
589 populateValidFirstKeys();
4c788df a few style changes per phil's comments
Ilya authored
590 populateSingleKeyCommands();
781da8b @philc Save the current version to localStorage, and when an update arrives,…
philc authored
591 if (shouldShowUpgradeMessage())
592 sendRequestToAllTabs({ name: "showUpgradeNotification", version: currentVersion });
70f2a92 @ilya Move some code into init() so that it's clear that it executes once a…
ilya authored
593
594 // Ensure that openTabs is populated when Vimium is installed.
595 chrome.windows.getAll({ populate: true }, function(windows) {
596 for (var i in windows) {
597 for (var j in windows[i].tabs) {
598 var tab = windows[i].tabs[j];
599 updateOpenTabs(tab);
600 getScrollPosition(tab, function(tab, scrollX, scrollY) {
601 // Not using the tab defined in the for loop because
602 // it might have changed by the time this callback is activated.
603 updateScrollPosition(tab, scrollX, scrollY);
604 });
605 }
606 }
607 });
066ed27 @ilya Refactor the command parser to not store invalid keys in the two-key …
ilya authored
608 }
609 init();
aff9db2 @philc Initial project commit
philc authored
610 </script>
611 </head>
7c2cb40 @ilya Key Mapping - Create an available commands structure and factor out t…
ilya authored
612 </html>
Something went wrong with that request. Please try again.