You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
5.4 KiB
JavaScript

export class FileView extends HTMLElement {
icons = {
menu: `
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-three-dots" viewBox="0 0 16 16">
<path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
</svg>
`,
down: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
</svg>
`,
up: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
</svg>
`,
}
textEn = {
addAbove: 'Add above',
addBelow: 'Add below',
delete: 'Delete',
}
textEs = {
addAbove: 'Añadir arriba',
addBelow: 'Añadir abajo',
delete: 'Borrar',
}
constructor() {
super()
this.language = navigator.language
this.attachShadow({mode: 'open'})
this.headerEl = document.createElement('div')
this.headerEl.classList.add('header')
this.contentEl = document.createElement('div')
this.contentEl.classList.add('content')
this.shadowRoot.appendChild(this.headerEl)
this.shadowRoot.appendChild(this.contentEl)
this.nameEl = document.createElement('input')
this.nameEl.classList.add('name')
this.nameEl.setAttribute('spellcheck', 'false')
this.nameEl.addEventListener('input', e => {
this.setFileType(e.target.value)
})
this.headerEl.appendChild(this.nameEl)
this.collapseBtn = document.createElement(
'button'
)
this.collapseBtn.innerHTML = this.icons.up
this.collapseBtn.addEventListener('click', () => {
this.collapsed = !this.collapsed
})
this.headerEl.appendChild(this.collapseBtn)
this.menuBtn = document.createElement('button')
this.menuBtn.innerHTML = this.icons.menu
this.menuBtn.addEventListener('click', () => {
this.openMenu()
})
this.headerEl.appendChild(this.menuBtn)
this.menu = document.createElement(
'm-menu-dropdown'
)
this.shadowRoot.appendChild(this.menu)
}
connectedCallback() {
const style = document.createElement('style')
style.textContent = `
:host {
display: flex;
flex-direction: column;
align-items: stretch;
}
div.header {
display: flex;
flex-direction: row;
align-items: stretch;
background-color: #f2dbd8;
color: #000;
padding: 3px 0;
}
div.header > * {
background: inherit;
color: inherit;
border: none;
}
.name {
flex-grow: 1;
padding: 0 5px;
font: inherit;
font-family: monospace;
outline: none;
}
div.header button svg {
margin-bottom: -3px;
}
div.content {
display: flex;
flex-direction: column;
align-items: stretch;
min-height: 5px;
}
div.content.collapsed > * {
display: none;
}
svg {
height: 20px;
width: 20px;
}
`
this.shadowRoot.appendChild(style)
}
openMenu() {
this.menu.clear()
this.menu.add(this.text.addAbove, () => {
this.dispatchEvent(new CustomEvent(
'click-add-above', {bubbles: true}
))
})
this.menu.add(this.text.addBelow, () => {
this.dispatchEvent(new CustomEvent(
'click-add-below', {bubbles: true}
))
})
if (this.fileCount.value > 1) {
this.menu.add(this.text.delete, () => {
this.remove()
this.fileCount.value -= 1
})
}
this.menu.open(this.menuBtn)
}
set codeMirror(value) {
this._codeMirror = value
const tagName = (
this.codeMirror ?
'm-editor-code-edit' : 'm-editor-text-edit'
)
this.editEl = document.createElement(tagName)
this.contentEl.replaceChildren(this.editEl)
}
get codeMirror() {
return this._codeMirror
}
set name(name) {
this.nameEl.value = name
this.setFileType(name)
}
get name() {
return this.nameEl.value
}
set data(data) {
this.editEl.value = data
}
get data() {
return this.editEl.value
}
set collapsed(value) {
const cl = this.contentEl.classList
if (value) {
cl.add('collapsed')
} else {
cl.remove('collapsed')
}
this.collapseBtn.innerHTML = (
value ?
this.icons.down : this.icons.up
)
}
get collapsed() {
return this.contentEl.classList.contains(
'collapsed'
)
}
setFileType(value) {
if (this.codeMirror && this.editEl) {
let fileType
if (value.endsWith('.js')) {
fileType = 'js'
} else if (value.endsWith('.html')) {
fileType = 'html'
} else if (value.endsWith('.css')) {
fileType = 'css'
} else if (value.endsWith('.json')) {
fileType = 'json'
}
this.editEl.fileType = fileType
}
}
get language() {
return this._language
}
set language(language) {
this._language = language
this.text = this.langEs ? this.textEs : this.textEn
}
get langEs() {
return /^es\b/.test(this.language)
}
}