Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/bootstrap.min.css

Large diffs are not rendered by default.

228 changes: 193 additions & 35 deletions lib/list.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,120 @@
(function(){
var storedKeys = Object.keys(localStorage).filter(function(key) {
// Filter out special keys that shouldn't be displayed as shortcuts
return key !== 'lastSynced' &&
!key.startsWith('lastSynced_') &&
key !== 'shortcutsMeta' &&
key !== 'deletedShortcuts';
});
Comment on lines +2 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


// Function to export shortcuts to a JSON file
function exportShortcuts() {
// Create an object to hold all shortcuts
var shortcuts = {};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

for (var i = 0; i < localStorage.length; i++) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider reusing the storedKeys array for exporting shortcuts.

Since you already filter and store the shortcut keys in the storedKeys variable for display, using it in exportShortcuts would remove duplicate filtering logic and ensure consistency between displayed and exported shortcuts.

Suggested implementation:

	// Function to export shortcuts to a JSON file
	function exportShortcuts() {
		// Create an object to hold all shortcuts
		var shortcuts = {};
		storedKeys.forEach(function(key) {
			shortcuts[key] = localStorage[key];
		});

Ensure that the storedKeys array is defined and available in the scope where exportShortcuts is declared.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var key = localStorage.key(i);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

// Only export actual shortcuts, not metadata
if (key !== 'lastSynced' &&
!key.startsWith('lastSynced_') &&
key !== 'shortcutsMeta' &&
key !== 'deletedShortcuts') {
var url = localStorage[key];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

shortcuts[key] = url;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring the filtering and conflict-resolution logic into dedicated helper functions to improve code readability and maintainability.

Refactor the filtering and conflict-resolution logic into dedicated helper functions to reduce nesting and duplicate code without changing functionality.

For example, extract the duplicate key filtering into a helper:
```js
function isShortcutKey(key) {
  return key !== 'lastSynced' &&
         !key.startsWith('lastSynced_') &&
         key !== 'shortcutsMeta' &&
         key !== 'deletedShortcuts';
}

Use this helper in both export and storedKeys generation:

var storedKeys = Object.keys(localStorage).filter(isShortcutKey);

Similarly, for the nested conflict resolution in importShortcuts, consider extracting a function:

function resolveImport(key, newUrl, importMode) {
  if (!localStorage[key]) {
    localStorage[key] = newUrl;
    return 'added';
  }
  switch (importMode) {
    case 2:
      localStorage[key] = newUrl;
      return 'updated';
    case 3:
      if (localStorage[key] !== newUrl) {
        let newKey = key + "_imported";
        let counter = 1;
        while (localStorage[newKey]) {
          newKey = key + "_imported_" + counter++;
        }
        localStorage[newKey] = newUrl;
        return 'added';
      }
      return 'skipped';
    default:
      return 'skipped';
  }
}

Then process imports like:

for (var key in shortcuts) {
  var status = resolveImport(key, shortcuts[key], importMode);
  if (status === 'added') added++;
  else if (status === 'updated') updated++;
  else skipped++;
}

These changes centralize duplicate logic and flatten nested conditionals while maintaining current behavior.

}

var storedKeys = Object.keys(localStorage);
// Convert to JSON string
var jsonData = JSON.stringify(shortcuts, null, 2);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


// Create a blob and download link
var blob = new Blob([jsonData], {type: 'application/json'});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var url = URL.createObjectURL(blob);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


// Create a temporary link and trigger download
var a = document.createElement('a');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

a.href = url;
a.download = 'chrome-quick-links-shortcuts.json';
document.body.appendChild(a);
a.click();

// Clean up
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
Comment on lines +11 to +45
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.


// Function to import shortcuts from a JSON file
function importShortcuts(event) {
var file = event.target.files[0];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

if (!file) return;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (!file) return;
if (!file) {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).


var reader = new FileReader();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

reader.onload = function(e) {
try {
var shortcuts = JSON.parse(e.target.result);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


// Ask user how to handle conflicts
var importMode = prompt(
"Choose how to handle existing shortcuts:\n" +
"1: Keep existing shortcuts (only add new ones)\n" +
"2: Overwrite existing shortcuts\n" +
"3: Merge (keep both if URLs differ)\n" +
"Enter 1, 2, or 3:", "1");
Comment on lines +58 to +63
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


if (!importMode) return; // User cancelled
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (!importMode) return; // User cancelled
if (!importMode) {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

importMode = parseInt(importMode);

var added = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var updated = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var skipped = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


for (var key in shortcuts) {
var newUrl = shortcuts[key];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var exists = localStorage[key] !== undefined;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


if (!exists) {
// New shortcut, always add
localStorage[key] = newUrl;
added++;
} else if (importMode === 2) {
// Overwrite mode
localStorage[key] = newUrl;
updated++;
} else if (importMode === 3 && localStorage[key] !== newUrl) {
// Merge mode - if URLs differ, create a new shortcut with a suffix
var newKey = key + "_imported";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var counter = 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


// Find an available key name
while (localStorage[newKey] !== undefined) {
newKey = key + "_imported_" + counter;
counter++;
}

localStorage[key] = newUrl;
added++;
} else if (importMode === 1) {
// Keep existing mode
skipped++;
}
}

// Show results
alert("Import complete!\n" +
"Added: " + added + " new shortcuts\n" +
"Updated: " + updated + " existing shortcuts\n" +
"Skipped: " + skipped + " shortcuts");

// Refresh the page to show updated shortcuts
window.location.reload();

} catch (error) {
alert("Error importing shortcuts: " + error.message);
}
};
reader.readAsText(file);
}
Comment on lines +48 to +117
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.


function buttonTemplate(key){
var html = '<small><span class="btn-group"><span class="btn-mini btn-success btn-inline text-xs tb" id="edit-{tmp}">edit</span>'
Expand Down Expand Up @@ -28,10 +142,11 @@
}
}

for (i=0; i<localStorage.length; i++) {
// Only display actual shortcuts, not metadata
for (i=0; i<storedKeys.length; i++) {
var key = storedKeys[i];
var url = localStorage[key];
newTableRow(url, key, attachEdit );
newTableRow(url, key, attachEdit);
}

var doEdit = function(){
Expand All @@ -47,55 +162,98 @@

var doDelete = function() {
var key = this.id.split('-')[1];
if ( confirm('Are you sure?') ) {
delete localStorage[key];
if(chrome.storage){
chrome.storage.sync.remove(key);
}
window.location = window.location;
}
if (confirm('Are you sure?')) {
delete localStorage[key];
if(chrome.storage){
chrome.storage.sync.remove(key);
}
window.location = window.location;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Assigning a variable to itself has no effect. (dont-self-assign-variables)

Suggested change
window.location = window.location;
;


ExplanationAssigning a variable to itself has no effect, and is therefore either redundant or a mistake.

}
}
Comment on lines 163 to 172
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide


function checkExample(){
var tr = document.getElementsByTagName('tr');
if(tr.length > 1) {
var example = document.getElementById('example');
example.remove();
if (example) {
example.remove();
}
}
}
Comment on lines 174 to 182
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.


window.addEventListener('load', function(){
checkExample();
for (i=0; i<localStorage.length; i++) {
for (i=0; i<storedKeys.length; i++) {
var key = storedKeys[i];
var url = localStorage[key];
document.getElementById("edit-" + key).addEventListener("click", doEdit, false);
document.getElementById("delete-" + key).addEventListener("click", doDelete, false);
var editBtn = document.getElementById("edit-" + key);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use const or let instead of var. (avoid-using-var)

Explanation`const` is preferred as it ensures you cannot reassign references (which can lead to buggy and confusing code). `let` may be used if you need to reassign references - it's preferred to `var` because it is block- rather than function-scoped.

From the Airbnb JavaScript Style Guide

var deleteBtn = document.getElementById("delete-" + key);
if (editBtn) editBtn.addEventListener("click", doEdit, false);
if (deleteBtn) deleteBtn.addEventListener("click", doDelete, false);
}

// Add Export/Import buttons
var container = document.querySelector('.container');
if (container) {
// Create export button
var exportBtn = document.createElement('button');
exportBtn.textContent = 'Export Shortcuts';
exportBtn.className = 'btn btn-primary';
exportBtn.style.marginRight = '10px';
exportBtn.addEventListener('click', exportShortcuts);

// Create import button container (to style it like a button but actually be a file input)
var importContainer = document.createElement('span');
importContainer.className = 'btn btn-primary';
importContainer.style.position = 'relative';
importContainer.style.overflow = 'hidden';
importContainer.style.display = 'inline-block';
importContainer.textContent = 'Import Shortcuts';

// Create actual file input
var importInput = document.createElement('input');
importInput.type = 'file';
importInput.accept = '.json';
importInput.style.position = 'absolute';
importInput.style.fontSize = '100px';
importInput.style.opacity = '0';
importInput.style.right = '0';
importInput.style.top = '0';
importInput.addEventListener('change', importShortcuts);

// Add file input to container
importContainer.appendChild(importInput);

// Create button container
var buttonContainer = document.createElement('div');
buttonContainer.style.marginBottom = '20px';
buttonContainer.appendChild(exportBtn);
buttonContainer.appendChild(importContainer);

// Add buttons to page
container.insertBefore(buttonContainer, container.firstChild);
}
});

//search function
document.getElementById("search").addEventListener('keyup',function() {

var input, filter, table, tr, td, i, txtValue;
var input = document.getElementById("search");
var searchFilter = input.value;
var table = document.getElementById("table-body");
var tr = table.getElementsByTagName("tr");
//search function
document.getElementById("search").addEventListener('keyup',function() {
var input, filter, table, tr, td, i, txtValue;
var input = document.getElementById("search");
var searchFilter = input.value;
var table = document.getElementById("table-body");
var tr = table.getElementsByTagName("tr");

//loop through all rows, and hide those that don't match search query
for (var i=0; i<tr.length; i++) {
var shortcut = tr[i].getElementsByTagName("td")[1];
var url = tr[i].getElementsByTagName("td")[2];
//loop through all rows, and hide those that don't match search query
for (var i=0; i<tr.length; i++) {
var shortcut = tr[i].getElementsByTagName("td")[1];
var url = tr[i].getElementsByTagName("td")[2];
var targetMatch = '';
targetMatch += shortcut.textContent || shortcut.innerText;
targetMatch += url.textContent || url.innerText;
if (targetMatch.indexOf(searchFilter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
})

if (targetMatch.indexOf(searchFilter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
});
})();