|
2 | 2 |
|
3 | 3 | var m = require("mithril"); |
4 | 4 | var FuzzySort = require("fuzzysort"); |
| 5 | +var Tldjs = require("tldjs"); |
5 | 6 | var app = "com.dannyvankooten.browserpass"; |
6 | 7 | var activeTab; |
7 | 8 | var searching = false; |
@@ -45,6 +46,10 @@ function view() { |
45 | 46 |
|
46 | 47 | return m("div.entry", [ |
47 | 48 | m(selector, options, login), |
| 49 | + m("button.launch.url", { |
| 50 | + onclick: launchURL.bind({ entry: login, what: "url" }), |
| 51 | + tabindex: -1 |
| 52 | + }), |
48 | 53 | m("button.copy.username", { |
49 | 54 | onclick: loginToClipboard.bind({ entry: login, what: "username" }), |
50 | 55 | tabindex: -1 |
@@ -76,7 +81,7 @@ function view() { |
76 | 81 | type: "text", |
77 | 82 | id: "search-field", |
78 | 83 | name: "s", |
79 | | - placeholder: "Search passwords..", |
| 84 | + placeholder: "Search passwords...", |
80 | 85 | autocomplete: "off", |
81 | 86 | autofocus: "on", |
82 | 87 | oninput: filterLogins |
@@ -150,7 +155,6 @@ function showFilterHint(show=true) { |
150 | 155 |
|
151 | 156 | function submitSearchForm(e) { |
152 | 157 | e.preventDefault(); |
153 | | - |
154 | 158 | if (fillOnSubmit && logins.length > 0) { |
155 | 159 | // fill using the first result |
156 | 160 | getLoginData.bind(logins[0])(); |
@@ -232,6 +236,50 @@ function getFaviconUrl(domain) { |
232 | 236 | return null; |
233 | 237 | } |
234 | 238 |
|
| 239 | +function launchURL() { |
| 240 | + var what = this.what; |
| 241 | + var entry = this.entry; |
| 242 | + chrome.runtime.sendNativeMessage( |
| 243 | + app, |
| 244 | + { action: "get", entry: this.entry }, |
| 245 | + function(response) { |
| 246 | + if (chrome.runtime.lastError) { |
| 247 | + error = chrome.runtime.lastError.message; |
| 248 | + m.redraw(); |
| 249 | + return; |
| 250 | + } |
| 251 | + // get url from login path if not available in the host app response |
| 252 | + if (!response.hasOwnProperty("url") || response.url.length == 0) { |
| 253 | + var parts = entry.split(/\//).reverse(); |
| 254 | + for (var i in parts) { |
| 255 | + var part = parts[i]; |
| 256 | + var info = Tldjs.parse(part); |
| 257 | + if (info.isValid && info.tldExists && info.domain !== null && info.hostname === part) { |
| 258 | + response.url = part; |
| 259 | + break; |
| 260 | + } |
| 261 | + } |
| 262 | + } |
| 263 | + // if a url is present, then launch a new tab via the background script |
| 264 | + if (response.hasOwnProperty("url") && response.url.length > 0) { |
| 265 | + var url = response.url.match(/^([a-z]+:)?\/\//i) ? response.url : "http://" + response.url; |
| 266 | + chrome.runtime.sendMessage({action: "launch", url: url, username: response.u, password: response.p}); |
| 267 | + window.close(); |
| 268 | + return; |
| 269 | + } |
| 270 | + // no url available |
| 271 | + if (!response.hasOwnProperty("url")) { |
| 272 | + resetWithError( |
| 273 | + "Unable to determine the URL for this entry. If you have defined one in the password file, " + |
| 274 | + "your host application must be at least v2.0.14 for this to be usable." |
| 275 | + ); |
| 276 | + } else { |
| 277 | + resetWithError("Unable to determine the URL for this entry."); |
| 278 | + } |
| 279 | + } |
| 280 | + ); |
| 281 | +} |
| 282 | + |
235 | 283 | function getLoginData() { |
236 | 284 | searching = true; |
237 | 285 | logins = resultLogins = []; |
@@ -298,16 +346,18 @@ function keyHandler(e) { |
298 | 346 | break; |
299 | 347 | case "c": |
300 | 348 | if (e.target.id != "search-field" && e.ctrlKey) { |
301 | | - document.activeElement["nextElementSibling"][ |
302 | | - "nextElementSibling" |
303 | | - ].click(); |
| 349 | + document.activeElement.parentNode.querySelector("button.copy.password").click(); |
304 | 350 | } |
305 | 351 | break; |
306 | 352 | case "C": |
307 | 353 | if (e.target.id != "search-field") { |
308 | | - document.activeElement["nextElementSibling"].click(); |
| 354 | + document.activeElement.parentNode.querySelector("button.copy.username").click(); |
309 | 355 | } |
310 | 356 | break; |
| 357 | + case "g": |
| 358 | + if (e.target.id != "search-field") { |
| 359 | + document.activeElement.parentNode.querySelector("button.launch.url").click(); |
| 360 | + } |
311 | 361 | } |
312 | 362 | } |
313 | 363 |
|
@@ -336,3 +386,18 @@ function oncreate() { |
336 | 386 | document.getElementById("search-field").focus(); |
337 | 387 | }, 100); |
338 | 388 | } |
| 389 | + |
| 390 | +function resetWithError(errMsg) { |
| 391 | + domain = ''; |
| 392 | + logins = resultLogins = []; |
| 393 | + fillOnSubmit = false; |
| 394 | + searching = false; |
| 395 | + var filterSearch = document.getElementById("filter-search"); |
| 396 | + filterSearch.style.display = "none"; |
| 397 | + filterSearch.textContent = ''; |
| 398 | + var searchField = document.getElementById("search-field"); |
| 399 | + searchField.setAttribute("placeholder", "Search passwords..."); |
| 400 | + error = errMsg; |
| 401 | + m.redraw(); |
| 402 | + searchField.focus(); |
| 403 | +} |
0 commit comments