curls/server/static/dashboard/js/main/container.js

452 lines
11 KiB
JavaScript

/*
This is the main container widget with the vertical items
Most action happens here
*/
class Container {
static wrap_enabled = true
static ls_wrap = `wrap_enabled`
static scroll_step = 100
static setup() {
this.empty_info = [
`Add some curls to the list by using the menu.`,
`These will be monitored for status changes.`,
`Above you can change the status of your own curls.`,
`Each color has its own set of curls.`,
].join(`<br>`)
let outer = this.get_outer()
let container = this.get_container()
DOM.ev(container, `mousedown`, (e) => {
if (e.ctrlKey || e.shiftKey) {
e.preventDefault()
}
})
DOM.ev(container, `click`, (e) => {
let item = this.extract_item(e)
if (!item) {
return
}
if (this.extract_updated(e)) {
Dates.change_mode()
return
}
this.focus()
let is_icon = this.extract_icon(e)
if (e.shiftKey) {
Select.range(item)
e.preventDefault()
}
else if (e.ctrlKey) {
Select.toggle(item)
e.preventDefault()
}
else {
if (is_icon) {
Select.single(item)
e.preventDefault()
}
}
})
DOM.ev(container, `auxclick`, (e) => {
let item = this.extract_item(e)
if (!item) {
return
}
if (e.button == 1) {
let curl = this.extract_curl(item)
Select.check(item)
Curls.remove_selected(curl)
}
})
DOM.ev(container, `contextmenu`, (e) => {
let item = this.extract_item(e)
if (!item) {
return
}
let curl = this.extract_curl(item)
Select.check(item)
Items.show_menu({curl: curl, e: e})
e.preventDefault()
})
DOM.ev(outer, `contextmenu`, (e) => {
let item = this.extract_item(e)
e.preventDefault()
if (item) {
return
}
Menu.show(e)
})
DOM.ev(outer, `click`, (e) => {
this.focus()
})
DOM.ev(outer, `mousedown`, (e) => {
Select.mousedown(e)
})
DOM.ev(outer, `mouseup`, () => {
Select.mouseup()
})
DOM.ev(outer, `mouseover`, (e) => {
Select.mouseover(e)
})
this.wrap_enabled = this.load_wrap_enabled()
this.setup_keyboard()
this.focus()
}
static clear() {
let container = this.get_container()
container.innerHTML = ``
}
static show_empty() {
Infobar.hide()
this.set_info(this.empty_info)
}
static check_empty() {
let els = this.get_items()
if (!els || !els.length) {
this.show_empty()
}
}
static show_loading() {
this.set_info(`Loading...`)
}
static set_info(info) {
let container = this.get_container()
let item = DOM.create(`div`, `info_item`)
item.innerHTML = info
container.innerHTML = ``
container.append(item)
Utils.deselect()
}
static get_items() {
return DOM.els(`#container .item`)
}
static scroll_top() {
let item = this.get_items()[0]
Utils.scroll_element({item: item, behavior: `smooth`, block: `center`})
}
static scroll_bottom() {
let item = Utils.last(this.get_items())
Utils.scroll_element({item: item, behavior: `smooth`, block: `center`})
}
static save_wrap_enabled() {
Utils.save(this.ls_wrap, this.wrap_enabled)
}
static load_wrap_enabled() {
return Utils.load_boolean(this.ls_wrap)
}
static add(items, curls) {
let normal = Items.list.filter(item => !item.missing)
Items.list = [...items]
for (let item of normal) {
if (Items.list.find(x => x.curl === item.curl)) {
continue
}
Items.list.push(item)
}
let missing = Items.find_missing()
Items.list.push(...missing)
Items.fill()
this.update({select: curls})
}
static insert(items) {
Items.list = items
Items.list.map(x => x.missing = false)
let missing = Items.find_missing()
Items.list.push(...missing)
Items.fill()
this.update()
}
static update(args = {}) {
let def_args = {
items: Items.list,
check_filter: true,
select: [],
}
Utils.def_args(def_args, args)
Utils.info(`Updating Container`)
this.clear()
Sort.sort(args.items)
for (let item of args.items) {
this.create_element(item)
}
Utils.deselect()
this.check_empty()
if (args.check_filter) {
Filter.check()
}
if (args.select.length) {
Select.curls(args.select)
}
Infobar.update()
}
static create_element(item) {
let container = this.get_container()
let el = DOM.create(`div`, `item`)
let item_icon = DOM.create(`div`, `item_icon`)
item_icon.draggable = true
let lines = [
`Click to select`,
`Ctrl Click to toggle`,
`Shift Click to select range`,
`Middle Click to remove`,
`Drag to reorder`,
]
item_icon.title = lines.join(`\n`)
let canvas = DOM.create(`canvas`, `item_icon_canvas`)
jdenticon.update(canvas, item.curl)
item_icon.append(canvas)
let item_curl = DOM.create(`div`, `item_curl`)
let item_status = DOM.create(`div`, `item_status`)
if (!this.wrap_enabled) {
item_status.classList.add(`nowrap`)
}
item_curl.textContent = item.curl
item_curl.title = item.curl
let status = item.status || `Not updated yet`
item_status.innerHTML = Utils.sanitize(status)
Utils.urlize(item_status)
let item_updated = DOM.create(`div`, `item_updated glow`)
let dates = [
`Updated: ${item.updated_text}`,
`Added: ${item.added_text}`,
`Created: ${item.created_text}`,
]
let date_text = dates.join(`\n`)
if (Dates.enabled) {
item_status.title = status
if (item.missing) {
item_updated.textContent = `No Date`
item_updated.title = `No date information available`
}
else {
item_updated.textContent = item.updated_text
let lines_2 = [
date_text,
`Click to toggle between 12 and 24 hours`,
]
item_updated.title = lines_2.join(`\n`)
}
}
else {
item_status.title = `${status}\n${date_text}`
item_updated.classList.add(`hidden`)
}
if (!item.missing) {
item_status.title += `\nChanges: ${item.changes}`
}
el.append(item_icon)
el.append(item_curl)
el.append(item_status)
el.append(item_updated)
el.dataset.curl = item.curl
el.dataset.selected_id = 0
container.append(el)
container.append(el)
item.element = el
}
static extract_curl(item) {
return item.dataset.curl
}
static setup_keyboard() {
let container = this.get_container()
DOM.ev(container, `keydown`, (e) => {
if (e.key === `Delete`) {
Curls.remove_selected()
e.preventDefault()
}
else if (e.key === `ArrowUp`) {
if (e.ctrlKey) {
Move.up()
}
else {
Select.vertical(`up`, e.shiftKey)
}
e.preventDefault()
}
else if (e.key === `ArrowDown`) {
if (e.ctrlKey) {
Move.down()
}
else {
Select.vertical(`down`, e.shiftKey)
}
e.preventDefault()
}
else if (e.key === `ArrowLeft`) {
if (e.ctrlKey) {
Colors.prev()
e.preventDefault()
}
}
else if (e.key === `ArrowRight`) {
if (e.ctrlKey) {
Colors.next()
e.preventDefault()
}
}
else if (e.key === `Escape`) {
Select.deselect_all()
e.preventDefault()
}
else if (e.key === `a`) {
if (e.ctrlKey) {
Select.all()
e.preventDefault()
}
}
})
}
static is_visible(item) {
return !item.classList.contains(`hidden`)
}
static get_visible() {
let items = this.get_items()
return items.filter(x => this.is_visible(x))
}
static get_curls() {
let items = this.get_items()
return items.map(item => Container.extract_curl(item))
}
static get_item(curl) {
let items = this.get_items()
return items.find(x => x.dataset.curl === curl)
}
static focus() {
this.get_container().focus()
}
static get_outer() {
return DOM.el(`#container_outer`)
}
static get_container() {
return DOM.el(`#container`)
}
static extract_item(e) {
return e.target.closest(`.item`)
}
static extract_icon(e) {
return e.target.closest(`.item_icon`)
}
static extract_updated(e) {
return e.target.closest(`.item_updated`)
}
static scroll_up() {
let outer = this.get_outer()
outer.scrollBy(0, -this.scroll_step)
}
static scroll_down() {
let outer = this.get_outer()
outer.scrollBy(0, this.scroll_step)
}
static scroller() {
let outer = this.get_outer()
let height = outer.clientHeight
let scroll = outer.scrollHeight
let scrolltop = outer.scrollTop
if (scrolltop < (scroll - height)) {
this.scroll_bottom()
}
else {
this.scroll_top()
}
}
static scroll(e) {
let direction = Utils.wheel_direction(e)
if (direction === `up`) {
Container.scroll_up()
}
else {
Container.scroll_down()
}
}
static save_curls() {
let curls = Container.get_curls()
return Curls.save_curls(curls)
}
}