diff --git a/pkg/extension/src/scripts/content/toast.js b/pkg/extension/src/scripts/content/toast.js index 1751b497f..31a519f41 100644 --- a/pkg/extension/src/scripts/content/toast.js +++ b/pkg/extension/src/scripts/content/toast.js @@ -279,7 +279,6 @@ } function toggleRow(rowId) { - console.log('currentToastEl: ', currentToastEl) const container = currentToastEl.shadowRoot.querySelector(rowId) const initialState = container?.getAttribute('data-state') const rows = currentToastEl.shadowRoot.querySelectorAll( @@ -361,7 +360,7 @@ }) } - function createLabelRow(label, idx) { + function createLabelRow(label) { const element = document.createElement('button') const dot = document.createElement('span') dot.style = 'width:10px;height:10px;border-radius:1000px;' @@ -384,9 +383,8 @@ element.appendChild(check) element.onclick = labelClick - element.onkeydown = labelKeyDown + element.onkeydown = labelEditorKeyDownHandler element.setAttribute('data-label-id', label.id) - element.setAttribute('data-label-idx', idx) element.setAttribute( 'data-label-selected', label['selected'] ? 'on' : 'off' @@ -421,68 +419,117 @@ if (label) { label.selected = toggledValue } + + const labelList = event.target.form.querySelector('#label-list') + const labelInput = event.target.form.querySelector( + '#omnivore-edit-label-input' + ) + if (toggledValue) { + addLabel(labelList, labelInput, label.name) + } else { + removeLabel(labelList, label.id) + } } - function labelKeyDown(event) { + function backspaceOnLastItem(labelsList, labelsInput) { + // Get the last
  • item before the
  • { + node.removeAttribute('data-label-backspaced') + }) + } + + function labelEditorKeyDownHandler(event) { event.cancelBubble = true if (event.stopPropogation) { event.stopPropogation() } + // If any labels have been backspaced into (so they have the selected outline), clear their state + if (event.target.form && event.key.toLowerCase() !== 'backspace') { + clearBackspacedLabels(event.target.form) + } + switch (event.key.toLowerCase()) { case 'arrowup': { - if ( - event.target == - event.target.form.querySelector('#omnivore-edit-label-text') - ) { + if (event.target.id == 'omnivore-edit-label-input') { return } - const idx = event.target.getAttribute('data-label-idx') - let prevIdx = idx && Number(idx) != NaN ? Number(idx) - 1 : 0 - if ( - event.target == - event.target.form.querySelector('#omnivore-save-button') - ) { - // Focus the last label index - const maxItemIdx = Math.max( - ...Array.from( - event.target.form.querySelectorAll(`button[data-label-idx]`) - ).map((b) => Number(b.getAttribute('data-label-idx'))) - ) - if (maxItemIdx != NaN) { - prevIdx = maxItemIdx - } + if (!event.target.getAttribute('data-label-id')) { + return } - const prev = event.target.form.querySelector( - `button[data-label-idx='${prevIdx}']` - ) - if (prev) { + let prev = event.target.previousElementSibling + if (prev && prev.getAttribute('data-label-id')) { prev.focus() } else { - // Focus the text area - event.target.form.querySelector('#omnivore-edit-label-text')?.focus() + event.target.form.querySelector('#omnivore-edit-label-input')?.focus() } event.preventDefault() break } case 'arrowdown': { - const idx = event.target.getAttribute('data-label-idx') - const nextIdx = idx && Number(idx) != NaN ? Number(idx) + 1 : 0 - const next = event.target.form.querySelector( - `button[data-label-idx='${nextIdx}']` - ) - if (next) { - next.focus() + let next = undefined + if (event.target.id == 'omnivore-edit-label-input') { + idx = event.target.getAttribute('data-label-id') + next = event.target + .closest('#omnivore-edit-labels-form') + .querySelector('#omnivore-edit-labels-list') + .querySelector('[data-label-id]') } else { - // Focus the save button - event.target.form.querySelector('.omnivore-save-button')?.focus() + next = event.target.nextElementSibling + } + + if (next && next.getAttribute('data-label-id')) { + next.focus() } event.preventDefault() break } + case 'backspace': { + if ( + event.target.id == 'omnivore-edit-label-input' && + event.target.value.length == 0 + ) { + const labelList = event.target.form.querySelector('#label-list') + backspaceOnLastItem(labelList, event.target) + } + break + } case 'enter': { + if (event.target.id == 'omnivore-edit-label-input') { + if (event.target.value) { + const labelList = event.target.form.querySelector('#label-list') + addLabel(labelList, event.target, event.target.value) + } + event.preventDefault() + return + } const labelId = event.target.getAttribute('data-label-id') toggleLabel(event, labelId) event.preventDefault() @@ -529,7 +576,6 @@ currentToastEl.shadowRoot.querySelector( '#omnivore-add-note-form' ).onsubmit = (event) => { - console.log('submitting form: ', event) updateStatusBox('#omnivore-add-note-status', 'loading', 'Adding note...') browserApi.runtime.sendMessage({ @@ -585,6 +631,143 @@ } } + function getRandomColor() { + const colors = [ + '#FF5D99', + '#7CFF7B', + '#FFD234', + '#7BE4FF', + '#CE88EF', + '#EF8C43', + ] + const randomIndex = Math.floor(Math.random() * colors.length) + return colors[randomIndex] + } + + function getTempUUID() { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + ( + c ^ + (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) + ).toString(16) + ) + } + + function addLabel(labelList, labelInput, labelValue) { + // first check if the label is already entered: + const existingLabel = labels.find((l) => l.name === labelValue) + const labelEntryItem = labelList.querySelector('#label-entry-item') + const inputItem = labelEntryItem.querySelector('#omnivore-edit-label-input') + + // Handle case where label is already selected + if ( + existingLabel && + labelList.querySelector(`[data-label-id='${existingLabel.id}']`) + ) { + const labelItem = labelList.querySelector( + `[data-label-id='${existingLabel.id}']` + ) + labelItem.setAttribute('data-item-highlighted', 'on') + setTimeout(() => { + labelItem.style.borderColor = 'rgb(222, 222, 222)' + }, 500) + + if (inputItem) { + inputItem.value = '' + inputItem.focus() + updateLabels(undefined) + } + return + } + + const labelColor = existingLabel ? existingLabel.color : getRandomColor() + const labelElem = document.createElement('li') + labelElem.classList.add('label') + labelElem.innerHTML = ` + + ${labelValue} + + ` + + labelList.insertBefore(labelElem, labelEntryItem) + labelInput.value = '' + + const form = labelList.closest('#omnivore-edit-labels-form') + if (existingLabel) { + const element = form.querySelector( + `[data-label-id='${existingLabel.id}']` + ) + existingLabel.selected = true + element.setAttribute('data-label-selected', 'on') + labelElem.setAttribute('data-label-id', existingLabel.id) + } else { + // insert a toggle row at the top + const rowList = form.querySelector('#omnivore-edit-labels-list') + const newLabel = { + id: getTempUUID(), + color: labelColor, + name: labelValue, + temporary: true, + selected: true, + } + labels.push(newLabel) + labelElem.setAttribute('data-label-id', newLabel.id) + + // Now prepend a label in the rows at the bottom + const rowHtml = createLabelRow(newLabel) + const firstRow = rowList.querySelector('button[data-label-id]') + rowHtml.setAttribute('data-label-selected', 'on') + rowList.insertBefore(rowHtml, firstRow) + } + + if (inputItem) { + inputItem.focus() + updateLabels(undefined) + } + + syncLabelChanges() + } + + function removeLabel(labelList, labelID) { + const form = labelList.closest('#omnivore-edit-labels-form') + const element = labelList.querySelector(`[data-label-id='${labelID}']`) + if (element) { + element.remove() + } + + const rowElement = form.querySelector(`[data-label-id='${labelID}']`) + if (rowElement) { + rowElement.setAttribute('data-label-selected', 'off') + } + + updateLabels() + } + + function syncLabelChanges() { + console.log('syncLabels') + + updateStatusBox( + '#omnivore-edit-labels-status', + 'loading', + 'Updating Labels...', + undefined + ) + const labelIds = labels.filter((l) => l['selected']).map((l) => l.id) + + // browserApi.runtime.sendMessage({ + // - action: ACTIONS.SetLabels, + // - payload: { + // - ctx: ctx, + // - labelIds: labelIds, + // - }, + // - }) + } + async function editLabels() { cancelAutoDismiss() @@ -594,47 +777,33 @@ toggleRow('#omnivore-edit-labels-row') currentToastEl.shadowRoot - .querySelector('#omnivore-edit-label-text') + .querySelector('#omnivore-edit-label-input') ?.focus() const list = currentToastEl.shadowRoot.querySelector( '#omnivore-edit-labels-list' ) - currentToastEl.shadowRoot - .querySelector('#omnivore-edit-label-text') - .addEventListener('input', function () { - updateLabels(this.value) - }) currentToastEl.shadowRoot.querySelector( - '#omnivore-edit-label-text' - ).onkeydown = labelKeyDown + '#omnivore-edit-label-input' + ).onkeydown = labelEditorKeyDownHandler + + currentToastEl.shadowRoot.querySelector( + '#omnivore-edit-label-editor' + ).onclick = labelEditorClickHandler + + currentToastEl.shadowRoot + .querySelector('#omnivore-edit-label-input') + .addEventListener('input', (event) => { + updateLabels(event.target.value) + }) if (list) { list.innerHTML = '' labels.forEach(function (label, idx) { - const rowHtml = createLabelRow(label, idx) + const rowHtml = createLabelRow(label) list.appendChild(rowHtml) }) } - - currentToastEl.shadowRoot.querySelector( - '#omnivore-edit-labels-form' - ).onsubmit = (event) => { - event.preventDefault() - const statusBox = currentToastEl.shadowRoot.querySelector( - '#omnivore-edit-labels-status' - ) - statusBox.innerText = 'Updating labels...' - const labelIds = labels.filter((l) => l['selected']).map((l) => l.id) - - browserApi.runtime.sendMessage({ - action: ACTIONS.SetLabels, - payload: { - ctx: ctx, - labelIds: labelIds, - }, - }) - } } async function updateLabels(filterValue) { @@ -648,13 +817,13 @@ .filter( (l) => l.name.toLowerCase().indexOf(filterValue.toLowerCase()) > -1 ) - .forEach(function (label, idx) { - const rowHtml = createLabelRow(label, idx) + .forEach(function (label) { + const rowHtml = createLabelRow(label) list.appendChild(rowHtml) }) } else { - labels.forEach(function (label, idx) { - const rowHtml = createLabelRow(label, idx) + labels.forEach(function (label) { + const rowHtml = createLabelRow(label) list.appendChild(rowHtml) }) } diff --git a/pkg/extension/src/views/toast.html b/pkg/extension/src/views/toast.html index 31bf5c65b..3130869be 100644 --- a/pkg/extension/src/views/toast.html +++ b/pkg/extension/src/views/toast.html @@ -68,6 +68,11 @@ line-height: 20px; text-align: center; } + #omnivore-toast-container #omnivore-edit-labels-status { + height: 22px; + padding-top: 10px; + } + #omnivore-toast-button-row { gap: 5px; align-items: center; @@ -228,7 +233,7 @@ max-height: 200px; gap: 5px; color: #3B3A38; - margin-top: 15px; + margin-top: 0px; margin-bottom: 10px; } @@ -331,6 +336,86 @@ } } + +
    @@ -421,14 +506,16 @@
    - -
    - -
    - +
    +
      +
    • + +
    • +
    - + +