Sync label changes
This commit is contained in:
@ -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 <li> item before the <li><input item
|
||||
const lastItem =
|
||||
labelsInput.closest('#label-entry-item').previousElementSibling
|
||||
if (lastItem) {
|
||||
const backspaced = lastItem.getAttribute('data-label-backspaced')
|
||||
if (backspaced) {
|
||||
removeLabel(
|
||||
labelsInput.closest('#label-list'),
|
||||
lastItem.getAttribute('data-label-id')
|
||||
)
|
||||
} else {
|
||||
lastItem.setAttribute('data-label-backspaced', 'on')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function labelEditorClickHandler(event) {
|
||||
const input = event.target.querySelector('#omnivore-edit-label-input')
|
||||
if (input && event.target != input) {
|
||||
input.focus()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function clearBackspacedLabels(form) {
|
||||
const selected = form.querySelectorAll('.label[data-label-backspaced="on"]')
|
||||
selected.forEach((node) => {
|
||||
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 = `
|
||||
<span style="width: 10px; height: 10px; border-radius: 1000px; background-color: ${labelColor};"></span>
|
||||
${labelValue}
|
||||
<button class="label-remove-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="#6A6968" viewBox="0 0 256 256">
|
||||
<rect width="256" height="256" fill="none"></rect><line x1="200" y1="56" x2="56" y2="200" stroke="#6A6968" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line>
|
||||
<line x1="200" y1="200" x2="56" y2="56" stroke="#6A6968" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line>
|
||||
</svg>
|
||||
</button>
|
||||
`
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
@ -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 @@
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.label-editor {
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
|
||||
display: inline-block;
|
||||
background-color: var(--colors-thBackground2);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
padding: 5px;
|
||||
line-height: 2;
|
||||
cursor: text;
|
||||
font-size: 12px;
|
||||
width: calc(100% - 10px);
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.label-list {
|
||||
flex-wrap: wrap;
|
||||
justify-content: start;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
padding: 0px;
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
flex: 0 0 auto;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
#omnivore-toast-container .omnivore-toast-func-row .label-remove-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: transparent;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#omnivore-edit-labels-row .label-input {
|
||||
box-sizing: content-box;
|
||||
font-size: 16px;
|
||||
min-width: 2px;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 0px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-table;
|
||||
padding: 1px;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
border: 1px solid rgb(222, 222, 222);
|
||||
background-color: rgb(249, 249, 249);
|
||||
}
|
||||
|
||||
#omnivore-toast-container .omnivore-toast-func-row .label button {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
.label[data-label-backspaced="on"] {
|
||||
border: 1px solid rgb(255, 234, 159);
|
||||
}
|
||||
|
||||
.label[data-item-highlighted="on"] {
|
||||
border: 1px solid black;
|
||||
transition: border-color 0.25s linear;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="omnivore-toast-container">
|
||||
<div id="omnivore-toast-button-row">
|
||||
@ -421,14 +506,16 @@
|
||||
</form>
|
||||
</div>
|
||||
<div id="omnivore-edit-labels-row" class="omnivore-toast-func-row" data-state="closed">
|
||||
<span id="omnivore-edit-labels-status" class="omnivore-toast-func-status"></span>
|
||||
|
||||
<form id="omnivore-edit-labels-form">
|
||||
<input type="text" id="omnivore-edit-label-text" placeholder="Filter for labels" tabindex="0"> </input>
|
||||
<div id="omnivore-edit-labels-list">
|
||||
|
||||
<div id="omnivore-edit-label-editor" class="label-editor">
|
||||
<ul id="label-list" class="label-list">
|
||||
<li id="label-entry-item">
|
||||
<input type="text" id="omnivore-edit-label-input" placeholder="Add a label..." maxlength="48" class="label-input">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="omnivore-save-button">Save</button>
|
||||
<span id="omnivore-edit-labels-status" class="omnivore-toast-func-status"></span>
|
||||
<div id="omnivore-edit-labels-list"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user