@knowark/componarkjs 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +49 -0
- package/README.md +47 -0
- package/knowarkjs.code-workspace +29 -0
- package/lib/base/component/README.rst +113 -0
- package/lib/base/component/component.js +115 -0
- package/lib/base/component/component.test.js +327 -0
- package/lib/base/component/index.js +3 -0
- package/lib/base/index.js +1 -0
- package/lib/base/styles/index.js +3 -0
- package/lib/base/styles/styles.js +320 -0
- package/lib/base/utils/define.js +21 -0
- package/lib/base/utils/define.test.js +62 -0
- package/lib/base/utils/format.js +24 -0
- package/lib/base/utils/format.test.js +19 -0
- package/lib/base/utils/helpers.js +96 -0
- package/lib/base/utils/helpers.test.js +154 -0
- package/lib/base/utils/index.js +5 -0
- package/lib/base/utils/slots.js +18 -0
- package/lib/base/utils/slots.test.js +52 -0
- package/lib/base/utils/uuid.js +9 -0
- package/lib/base/utils/uuid.test.js +19 -0
- package/lib/components/audio/README.md +22 -0
- package/lib/components/audio/components/audio.js +103 -0
- package/lib/components/audio/components/audio.test.js +127 -0
- package/lib/components/audio/index.js +1 -0
- package/lib/components/audio/styles/ark.css.js +83 -0
- package/lib/components/audio/styles/index.js +2 -0
- package/lib/components/camera/README.md +64 -0
- package/lib/components/camera/components/camera.js +85 -0
- package/lib/components/camera/components/camera.test.js +104 -0
- package/lib/components/camera/index.js +1 -0
- package/lib/components/camera/styles/ark.css.js +17 -0
- package/lib/components/camera/styles/index.js +2 -0
- package/lib/components/capture/components/capture.js +54 -0
- package/lib/components/capture/components/capture.test.js +112 -0
- package/lib/components/capture/index.js +1 -0
- package/lib/components/droparea/README.md +51 -0
- package/lib/components/droparea/components/droparea-preview.js +159 -0
- package/lib/components/droparea/components/droparea-preview.test.js +105 -0
- package/lib/components/droparea/components/droparea.js +165 -0
- package/lib/components/droparea/components/droparea.test.js +320 -0
- package/lib/components/droparea/index.js +1 -0
- package/lib/components/droparea/styles/ark.css.js +235 -0
- package/lib/components/droparea/styles/index.js +3 -0
- package/lib/components/emit/components/emit.js +33 -0
- package/lib/components/emit/components/emit.test.js +138 -0
- package/lib/components/emit/index.js +1 -0
- package/lib/components/index.js +9 -0
- package/lib/components/list/README.md +103 -0
- package/lib/components/list/components/item.test.js +93 -0
- package/lib/components/list/components/list.item.js +22 -0
- package/lib/components/list/components/list.js +96 -0
- package/lib/components/list/components/list.test.js +267 -0
- package/lib/components/list/index.js +2 -0
- package/lib/components/paginator/README.md +32 -0
- package/lib/components/paginator/components/paginator.js +110 -0
- package/lib/components/paginator/components/paginator.test.js +131 -0
- package/lib/components/paginator/index.js +1 -0
- package/lib/components/paginator/styles/ark.css.js +196 -0
- package/lib/components/paginator/styles/index.js +2 -0
- package/lib/components/spinner/README.md +41 -0
- package/lib/components/spinner/components/spinner.js +105 -0
- package/lib/components/spinner/components/spinner.test.js +50 -0
- package/lib/components/spinner/index.js +1 -0
- package/lib/components/spinner/styles/ark.css.js +658 -0
- package/lib/components/spinner/styles/index.js +2 -0
- package/lib/components/splitview/README.md +63 -0
- package/lib/components/splitview/components/splitview.detail.js +46 -0
- package/lib/components/splitview/components/splitview.detail.test.js +92 -0
- package/lib/components/splitview/components/splitview.js +69 -0
- package/lib/components/splitview/components/splitview.master.js +26 -0
- package/lib/components/splitview/components/splitview.master.test.js +55 -0
- package/lib/components/splitview/components/splitview.test.js +76 -0
- package/lib/components/splitview/index.js +3 -0
- package/lib/components/translate/README.md +56 -0
- package/lib/components/translate/components/translate.js +100 -0
- package/lib/components/translate/components/translate.test.js +226 -0
- package/lib/components/translate/index.js +1 -0
- package/lib/index.js +2 -0
- package/package.json +68 -0
- package/showcase/design/.htaccess +8 -0
- package/showcase/design/core/factories/development/development.factory.js +5 -0
- package/showcase/design/core/factories/development/index.js +1 -0
- package/showcase/design/core/factories/index.js +11 -0
- package/showcase/design/core/factories/standard.factory.js +19 -0
- package/showcase/design/index.html +22 -0
- package/showcase/design/index.js +7 -0
- package/showcase/design/screens/base/audio/audioDemo.js +32 -0
- package/showcase/design/screens/base/audio/index.js +25 -0
- package/showcase/design/screens/base/camera/cameraDemo.js +83 -0
- package/showcase/design/screens/base/camera/index.js +25 -0
- package/showcase/design/screens/base/droparea/dropareaDemo.js +88 -0
- package/showcase/design/screens/base/droparea/index.js +25 -0
- package/showcase/design/screens/base/index.js +42 -0
- package/showcase/design/screens/base/list/index.js +25 -0
- package/showcase/design/screens/base/list/listDemo.js +89 -0
- package/showcase/design/screens/base/paginator/index.js +25 -0
- package/showcase/design/screens/base/paginator/paginatorDemo.js +82 -0
- package/showcase/design/screens/base/root.component.js +294 -0
- package/showcase/design/screens/base/root.routes.js +28 -0
- package/showcase/design/screens/base/spinner/index.js +25 -0
- package/showcase/design/screens/base/spinner/spinnerDemo.js +55 -0
- package/showcase/design/screens/base/splitview/detailDemo.js +40 -0
- package/showcase/design/screens/base/splitview/index.js +25 -0
- package/showcase/design/screens/base/splitview/splitViewDemo.js +58 -0
- package/showcase/design/screens/base/translate/index.js +20 -0
- package/showcase/design/screens/base/translate/translateDemo.js +43 -0
- package/showcase/design/screens/main.js +12 -0
- package/showcase/design/screens/screens.routes.js +23 -0
- package/showcase/index.html +86 -0
- package/showcase/index.js +5 -0
- package/showcase/locales/en/default.json +5 -0
- package/showcase/locales/es/default.json +5 -0
- package/showcase/locales/fr/default.json +5 -0
- package/tsconfig.json +23 -0
- package/webpack.config.cjs +118 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Component } from '../../../base/component/index.js'
|
|
2
|
+
|
|
3
|
+
const tag = 'ark-splitview-detail'
|
|
4
|
+
export class SplitViewDetail extends Component {
|
|
5
|
+
constructor() {
|
|
6
|
+
super()
|
|
7
|
+
this.addEventListener(
|
|
8
|
+
'close', this.onClose.bind(this))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
init(context = {}) {
|
|
12
|
+
this.binding = 'splitview-detail-listen'
|
|
13
|
+
|
|
14
|
+
const [main] = this.slots['general']
|
|
15
|
+
|
|
16
|
+
this.main = this.main || main
|
|
17
|
+
|
|
18
|
+
if (this.main && this.main.init) {
|
|
19
|
+
this.main.init(context)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return super.init(context)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render () {
|
|
26
|
+
this.content = ''
|
|
27
|
+
this.append(this.main)
|
|
28
|
+
|
|
29
|
+
return super.render()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @param {Event} event */
|
|
33
|
+
onClose (event) {
|
|
34
|
+
event.stopPropagation()
|
|
35
|
+
this.hide()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
show () {
|
|
39
|
+
this.removeAttribute('hidden')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
hide () {
|
|
43
|
+
this.setAttribute('hidden', '')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
Component.define(tag, SplitViewDetail)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Component } from "base/component"
|
|
2
|
+
import "./splitview.detail.js"
|
|
3
|
+
|
|
4
|
+
class MockMain extends Component {
|
|
5
|
+
init(context = {}) {
|
|
6
|
+
this.name = this.name || context.name || null
|
|
7
|
+
return super.init(context)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
if (this.name) {
|
|
12
|
+
this.content = `${this.name}`
|
|
13
|
+
}
|
|
14
|
+
return super.render()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
Component.define("mock-main", MockMain)
|
|
18
|
+
|
|
19
|
+
describe("SplitViewDetail", () => {
|
|
20
|
+
let container = null
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
container = document.createElement("div")
|
|
23
|
+
document.body.appendChild(container)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
container.remove()
|
|
28
|
+
container = null
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it("can be instantiated", () => {
|
|
32
|
+
container.innerHTML = `
|
|
33
|
+
<ark-splitview-detail>
|
|
34
|
+
</ark-splitview-detail>
|
|
35
|
+
`
|
|
36
|
+
const detail = container.querySelector("ark-splitview-detail")
|
|
37
|
+
expect(detail).toBeTruthy()
|
|
38
|
+
|
|
39
|
+
expect(detail).toBe(detail.init())
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it("can be instantiated with an inner main Component", () => {
|
|
43
|
+
container.innerHTML = /*html */`
|
|
44
|
+
<ark-splitview-detail>
|
|
45
|
+
<mock-main>MAIN CONTENT</mock-main>
|
|
46
|
+
</ark-splitview-detail>
|
|
47
|
+
`
|
|
48
|
+
const detail = container.querySelector("ark-splitview-detail")
|
|
49
|
+
|
|
50
|
+
expect(detail.firstElementChild.textContent).toEqual("MAIN CONTENT")
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it("can initialize its main Component", () => {
|
|
54
|
+
container.innerHTML = /* html */`
|
|
55
|
+
<ark-splitview-detail>
|
|
56
|
+
<mock-main></mock-main>
|
|
57
|
+
</ark-splitview-detail>
|
|
58
|
+
`
|
|
59
|
+
const detail = container.querySelector("ark-splitview-detail")
|
|
60
|
+
|
|
61
|
+
detail.init({ name: "Servagro" }).render()
|
|
62
|
+
|
|
63
|
+
expect(detail.firstElementChild.textContent).toEqual("Servagro")
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it("can manipulate its hidden attribute", () => {
|
|
67
|
+
container.innerHTML = /* html */`
|
|
68
|
+
<ark-splitview-detail>
|
|
69
|
+
<mock-main></mock-main>
|
|
70
|
+
</ark-splitview-detail>
|
|
71
|
+
`
|
|
72
|
+
const detail = container.querySelector("ark-splitview-detail")
|
|
73
|
+
|
|
74
|
+
detail.show()
|
|
75
|
+
expect(detail.hasAttribute("hidden")).toBeFalsy()
|
|
76
|
+
|
|
77
|
+
detail.hide()
|
|
78
|
+
expect(detail.hasAttribute("hidden")).toBeTruthy()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it("listens to close events to hide itself", () => {
|
|
82
|
+
container.innerHTML = /* html */`
|
|
83
|
+
<ark-splitview-detail>
|
|
84
|
+
<mock-main></mock-main>
|
|
85
|
+
</ark-splitview-detail>
|
|
86
|
+
`
|
|
87
|
+
const detail = container.querySelector("ark-splitview-detail")
|
|
88
|
+
detail.dispatchEvent(new Event('close'))
|
|
89
|
+
|
|
90
|
+
expect(detail.hasAttribute('hidden')).toBeTruthy()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Component, css } from '../../../base/component/index.js'
|
|
2
|
+
|
|
3
|
+
const tag = 'ark-splitview'
|
|
4
|
+
export class SplitView extends Component {
|
|
5
|
+
constructor() {
|
|
6
|
+
super()
|
|
7
|
+
this.binding = 'splitview-listen'
|
|
8
|
+
this.setDimensions()
|
|
9
|
+
globalThis.addEventListener('resize', this.setDimensions.bind(this))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
setDimensions() {
|
|
13
|
+
this.style.setProperty('--inner-height', `${innerHeight}px`)
|
|
14
|
+
this.style.setProperty('--inner-width', `${innerWidth}px`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get master () {
|
|
18
|
+
return this.select('ark-splitview-master')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get detail () {
|
|
22
|
+
return this.select('ark-splitview-detail')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render () {
|
|
26
|
+
this.renderDetail()
|
|
27
|
+
if (this.master) {
|
|
28
|
+
this.master.addEventListener(
|
|
29
|
+
'master-change', this.onMasterChange.bind(this))
|
|
30
|
+
}
|
|
31
|
+
return super.render()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** @param {Object} context */
|
|
35
|
+
renderDetail (context = {}) {
|
|
36
|
+
if (!this.detail || !this.detail.init) return
|
|
37
|
+
|
|
38
|
+
this.detail.init(context).render()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** @param {CustomEvent} event */
|
|
42
|
+
onMasterChange (event) {
|
|
43
|
+
event.stopPropagation()
|
|
44
|
+
|
|
45
|
+
const context = event.detail
|
|
46
|
+
this.renderDetail(context)
|
|
47
|
+
this.detail["show"]()
|
|
48
|
+
|
|
49
|
+
this.emit('detail-change', context)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const styles = css`
|
|
54
|
+
@media (max-width: 960px) {
|
|
55
|
+
.ark-splitview-detail {
|
|
56
|
+
position: fixed;
|
|
57
|
+
overflow: auto;
|
|
58
|
+
inset: 0 auto auto 0;
|
|
59
|
+
height: var(--inner-height, 100vh);
|
|
60
|
+
width: var(--inner-width, 100vh); ;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ark-splitview-detail[hidden] {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`
|
|
68
|
+
|
|
69
|
+
Component.define(tag, SplitView, styles)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Component } from '../../../base/component/index.js'
|
|
2
|
+
|
|
3
|
+
const tag = 'ark-splitview-master'
|
|
4
|
+
export class SplitViewMaster extends Component {
|
|
5
|
+
constructor () {
|
|
6
|
+
super()
|
|
7
|
+
this.addEventListener(
|
|
8
|
+
this['masterEvent'], this.onMasterEvent.bind(this))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
init(context = {}) {
|
|
12
|
+
this.binding = 'splitview-master-listen'
|
|
13
|
+
return super.init(context)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
reflectedProperties () {
|
|
17
|
+
return ['masterEvent']
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @param {CustomEvent} event */
|
|
21
|
+
onMasterEvent (event) {
|
|
22
|
+
event.stopPropagation()
|
|
23
|
+
this.emit('master-change', event.detail)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
Component.define(tag, SplitViewMaster)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import './splitview.master.js'
|
|
2
|
+
|
|
3
|
+
describe('SplitViewMaster', () => {
|
|
4
|
+
let container = null
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
container = document.createElement('div')
|
|
7
|
+
document.body.appendChild(container)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
container.remove()
|
|
12
|
+
container = null
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('can be instantiated', () => {
|
|
16
|
+
container.innerHTML = /*html*/`
|
|
17
|
+
<ark-splitview-master>
|
|
18
|
+
</ark-splitview-master>
|
|
19
|
+
`
|
|
20
|
+
const master = container.querySelector('ark-splitview-master')
|
|
21
|
+
master.init()
|
|
22
|
+
master.connectedCallback()
|
|
23
|
+
|
|
24
|
+
expect(master).toBeTruthy()
|
|
25
|
+
expect(master).toBe(master.init())
|
|
26
|
+
expect(master.getAttribute('master-event')).toBeNull()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('can be instantiated with master-event attribute', () => {
|
|
30
|
+
container.innerHTML = `
|
|
31
|
+
<ark-splitview-master master-event="my-event">
|
|
32
|
+
</ark-splitview-master>
|
|
33
|
+
`
|
|
34
|
+
const master = container.querySelector('ark-splitview-master')
|
|
35
|
+
expect(master.getAttribute('master-event')).toEqual('my-event')
|
|
36
|
+
expect(master.masterEvent).toEqual('my-event')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('can throw a master-change event', () => {
|
|
40
|
+
container.innerHTML = `
|
|
41
|
+
<ark-splitview-master master-event="click">
|
|
42
|
+
<button>Button</button>
|
|
43
|
+
</ark-splitview-master>
|
|
44
|
+
`
|
|
45
|
+
const master = container.querySelector('ark-splitview-master')
|
|
46
|
+
const button = master.select('button')
|
|
47
|
+
|
|
48
|
+
let masterEvent = null
|
|
49
|
+
master.addEventListener('master-change', (event) => {masterEvent = event})
|
|
50
|
+
|
|
51
|
+
button.click()
|
|
52
|
+
|
|
53
|
+
expect(masterEvent).toBeTruthy()
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Component } from 'base/component'
|
|
2
|
+
import './splitview.js'
|
|
3
|
+
import './splitview.detail'
|
|
4
|
+
import './splitview.master.js'
|
|
5
|
+
|
|
6
|
+
class NestedMaster extends Component {
|
|
7
|
+
constructor() {
|
|
8
|
+
super()
|
|
9
|
+
this.addEventListener('click', (_) => {
|
|
10
|
+
this.emit('nested:master', {value: 'NESTED MASTER VALUE'})
|
|
11
|
+
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
Component.define('nested-master', NestedMaster)
|
|
16
|
+
|
|
17
|
+
class NestedDetail extends Component {
|
|
18
|
+
init(context) {
|
|
19
|
+
if(!context.value) return super.init()
|
|
20
|
+
|
|
21
|
+
this.value = context.value
|
|
22
|
+
return super.init()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render() {
|
|
26
|
+
this.content = this.value
|
|
27
|
+
return super.render()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
Component.define('nested-detail', NestedDetail)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
describe('SplitView', () => {
|
|
34
|
+
let container = null
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
container = document.createElement('div')
|
|
37
|
+
document.body.appendChild(container)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
container.remove()
|
|
42
|
+
container = null
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('can be instantiated', () => {
|
|
46
|
+
container.innerHTML = /* html */`
|
|
47
|
+
<ark-splitview></ark-splitview>
|
|
48
|
+
`
|
|
49
|
+
const splitview = container.querySelector('ark-splitview')
|
|
50
|
+
|
|
51
|
+
expect(splitview).toBeTruthy()
|
|
52
|
+
expect(splitview.init()).toBe(splitview)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('can coordinate the master and the detail components', () => {
|
|
56
|
+
container.innerHTML = /* html */`
|
|
57
|
+
<ark-splitview>
|
|
58
|
+
<ark-splitview-master master-event="nested:master">
|
|
59
|
+
<nested-master></nested-master>
|
|
60
|
+
</ark-splitview-master>
|
|
61
|
+
<ark-splitview-detail>
|
|
62
|
+
<nested-detail></nested-detail>
|
|
63
|
+
</ark-splitview-detail>
|
|
64
|
+
</ark-splitview>
|
|
65
|
+
`
|
|
66
|
+
const splitview = container.querySelector('ark-splitview')
|
|
67
|
+
|
|
68
|
+
const nestedMaster = splitview.select('nested-master')
|
|
69
|
+
|
|
70
|
+
nestedMaster.click()
|
|
71
|
+
|
|
72
|
+
const nestedDetail = splitview.select('nested-detail')
|
|
73
|
+
|
|
74
|
+
expect(nestedDetail.content).toEqual('NESTED MASTER VALUE')
|
|
75
|
+
})
|
|
76
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
TRANSLATE
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
The `ark-translate` component, provides an easy way to add translations in our app through a select input:
|
|
5
|
+
|
|
6
|
+
## INSTRUCTIONS
|
|
7
|
+
|
|
8
|
+
1. Create a folder in your app (named `/locale` by default) and add a folder for each language.
|
|
9
|
+
2. Add a `default.json` file, with the variables you are going to target, and the respective translations as its values.
|
|
10
|
+
|
|
11
|
+
**example:**
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"hello": "Hello",
|
|
16
|
+
"world": "World",
|
|
17
|
+
"magic": "Magic"
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
3. Instantiate the `ark-translate` component with `languages` attribute
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<ark-translate languages="en,es,fr"></ark-translate>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
4.Target the variables on any element you want to apply the translation, using the `data-i18n` attribute:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<span data-i18n="hello">Hello</span>
|
|
31
|
+
<span data-i18n="world">World</span>
|
|
32
|
+
<span>
|
|
33
|
+
<strong data-i18n="magic">Magic</strong>
|
|
34
|
+
</span>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Attributes
|
|
38
|
+
----------
|
|
39
|
+
|
|
40
|
+
| Name | Type | Options | Default | Description |
|
|
41
|
+
| :-------: | :---: | :-------------------------------------------------------: | :------------: | :--------------------------------------------------------------: |
|
|
42
|
+
| languages | text | en (English), es (Español), fr (Français), pt (Português) | 'es' (Español) | Specifies the available languages |
|
|
43
|
+
| endpoint | text | any | '/locales' | Specifies a folder in which the translation data will be stored. |
|
|
44
|
+
| namespace | text | any | default | The name of the json file with the translations |
|
|
45
|
+
| root | text | any HTML wrapper element | 'body' | The parent element that wraps the elements to be translated |
|
|
46
|
+
|
|
47
|
+
Properties
|
|
48
|
+
----------
|
|
49
|
+
|
|
50
|
+
| Name | Type | Options | Default | Description |
|
|
51
|
+
| :-------: | :---: | :-------------------------------------------------------: | :------------: | :--------------------------------------------------------------: |
|
|
52
|
+
| languages | text | en (English), es (Español), fr (Français), pt (Português) | 'es' (Español) | Specifies the available languages |
|
|
53
|
+
| endpoint | text | any | '/locales' | Specifies a folder in which the translation data will be stored. |
|
|
54
|
+
| namespace | text | any | 'default' | The name of the json file with the translations |
|
|
55
|
+
| root | text | any HTML wrapper element | 'body' | The parent element that wraps the elements to be translated |
|
|
56
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Component } from '../../../base/component/index.js'
|
|
2
|
+
|
|
3
|
+
const tag = 'ark-translate'
|
|
4
|
+
export class Translate extends Component {
|
|
5
|
+
init (context = {}) {
|
|
6
|
+
this.global = context.global || window
|
|
7
|
+
this.endpoint = context.endpoint || this.endpoint || '/locales'
|
|
8
|
+
this.namespace = context.namespace || this.namespace || 'default'
|
|
9
|
+
this.root = context.root || this.root || 'body'
|
|
10
|
+
this.dictionary = context.dictionary || {}
|
|
11
|
+
|
|
12
|
+
const dictionary = this.select('template')
|
|
13
|
+
if (dictionary) {
|
|
14
|
+
const content = dictionary.content['textContent']
|
|
15
|
+
this.dictionary = JSON.parse(content)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return super.init(context)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
reflectedProperties() {
|
|
22
|
+
return ['languages', 'endpoint', 'namespace', 'root']
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
render () {
|
|
26
|
+
const languages = this.languages.split(',').filter(
|
|
27
|
+
item => Boolean(item) && item.trim())
|
|
28
|
+
if (!languages.length) return super.render()
|
|
29
|
+
|
|
30
|
+
this.content = `
|
|
31
|
+
<select listen on-change="onLanguageChanged">
|
|
32
|
+
${languages.map(code => `
|
|
33
|
+
<option value="${code}">${LANGUAGE_LIST[code]['name']}</option>
|
|
34
|
+
`)}
|
|
35
|
+
</select>
|
|
36
|
+
`
|
|
37
|
+
return super.render()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async onLanguageChanged(event) {
|
|
41
|
+
event.stopPropagation()
|
|
42
|
+
const language = event.target.value
|
|
43
|
+
await this.transliterate({ language })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async transliterate(options = {}) {
|
|
47
|
+
const language = options.language || 'es'
|
|
48
|
+
const root = this.global.document.querySelector(
|
|
49
|
+
options.root || this.root)
|
|
50
|
+
|
|
51
|
+
for (const node of root.querySelectorAll('[data-i18n]')) {
|
|
52
|
+
const { key, namespace } = this.parseKey(node.dataset.i18n)
|
|
53
|
+
const dictionary = await this.resolveDictionary(language, namespace)
|
|
54
|
+
|
|
55
|
+
node.textContent = dictionary[key] || node.textContent
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
parseKey(value) {
|
|
60
|
+
let key = value
|
|
61
|
+
let namespace = this.namespace
|
|
62
|
+
|
|
63
|
+
const splitList = value.split(':')
|
|
64
|
+
if (splitList.length > 1) {
|
|
65
|
+
namespace = splitList[0]
|
|
66
|
+
key = splitList[1]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { key, namespace }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async resolveDictionary(language, namespace) {
|
|
73
|
+
let dictionary = ((this.dictionary[language]
|
|
74
|
+
|| {})[namespace] || null)
|
|
75
|
+
|
|
76
|
+
if (dictionary !== null) return dictionary
|
|
77
|
+
|
|
78
|
+
if (!this.global.fetch) return {}
|
|
79
|
+
|
|
80
|
+
const url = `${this.endpoint}/${language}/${namespace}.json`
|
|
81
|
+
const response = await this.global.fetch(url)
|
|
82
|
+
|
|
83
|
+
dictionary = await response.json()
|
|
84
|
+
|
|
85
|
+
this.dictionary[language] || (this.dictionary[language] = {})
|
|
86
|
+
this.dictionary[language][namespace] = dictionary
|
|
87
|
+
|
|
88
|
+
return dictionary
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
Component.define(tag, Translate)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
const LANGUAGE_LIST = {
|
|
96
|
+
es: {name: 'Español'},
|
|
97
|
+
en: {name: 'English'},
|
|
98
|
+
fr: {name: 'Français'},
|
|
99
|
+
pt: {name: 'Português'}
|
|
100
|
+
}
|