Improved controls
This commit is contained in:
parent
5096391429
commit
c7164613a2
47
README.txt
47
README.txt
@ -23,8 +23,15 @@ File Open ^O
|
|||||||
File Save ^S
|
File Save ^S
|
||||||
File Export Vector ^E
|
File Export Vector ^E
|
||||||
File Export Image ^Shift+E
|
File Export Image ^Shift+E
|
||||||
History Undo ^Z
|
Edit Undo ^Z
|
||||||
History Redo ^Shift+Z
|
Edit Redo ^Shift+Z
|
||||||
|
View Color Picker G
|
||||||
|
View Toggle Grid H
|
||||||
|
View Toggle Tools ^H
|
||||||
|
Layers Foreground ^1
|
||||||
|
Layers Middleground ^2
|
||||||
|
Layers Background ^3
|
||||||
|
Layers Merge Layers ^M
|
||||||
Stroke Line A
|
Stroke Line A
|
||||||
Stroke Arc S
|
Stroke Arc S
|
||||||
Stroke Arc Rev D
|
Stroke Arc Rev D
|
||||||
@ -33,27 +40,21 @@ Stroke Close Z
|
|||||||
Stroke Arc(full) T
|
Stroke Arc(full) T
|
||||||
Stroke Arc Rev(full) Y
|
Stroke Arc Rev(full) Y
|
||||||
Stroke Clear Selection Escape
|
Stroke Clear Selection Escape
|
||||||
Effect Linecap Q
|
Stroke Erase Segment Backspace
|
||||||
Effect Linejoin W
|
Control Add Point Enter
|
||||||
Effect Mirror E
|
Control Move Up Up
|
||||||
Effect Fill R
|
Control Move Right Right
|
||||||
Effect Thicker }
|
Control Move Down Down
|
||||||
Effect Thinner {
|
Control Move Left Left
|
||||||
Effect Thicker +5 ]
|
Control Remove Point X
|
||||||
Effect Thinner -5 [
|
Style Linecap Q
|
||||||
Manual Add Point Enter
|
Style Linejoin W
|
||||||
Manual Move Up Up
|
Style Mirror E
|
||||||
Manual Move Right Right
|
Style Fill R
|
||||||
Manual Move Down Down
|
Style Thicker }
|
||||||
Manual Move Left Left
|
Style Thinner {
|
||||||
Manual Remove Point Shift+Backspace
|
Style Thicker +5 ]
|
||||||
Manual Remove Segment Backspace
|
Style Thinner -5 [
|
||||||
Layers Foreground ^1
|
|
||||||
Layers Middleground ^2
|
|
||||||
Layers Background ^3
|
|
||||||
Layers Merge Layers ^M
|
|
||||||
View Color Picker G
|
|
||||||
View Toggle Grid H
|
|
||||||
|
|
||||||
Extras
|
Extras
|
||||||
|
|
||||||
|
56
index.html
56
index.html
@ -59,7 +59,7 @@ function Acels (client) {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
this.convert = (event) => {
|
this.convert = (event) => {
|
||||||
const accelerator = event.key === ' ' ? 'Space' : event.key.substr(0, 1).toUpperCase() + event.key.substr(1)
|
const accelerator = event.key === ' ' ? 'Space' : capitalize(event.key.replace('Arrow', ''))
|
||||||
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
||||||
return `CmdOrCtrl+Shift+${accelerator}`
|
return `CmdOrCtrl+Shift+${accelerator}`
|
||||||
}
|
}
|
||||||
@ -113,6 +113,7 @@ function Acels (client) {
|
|||||||
this.toggle = () => {
|
this.toggle = () => {
|
||||||
this.el.className = this.el.className === 'hidden' ? '' : 'hidden'
|
this.el.className = this.el.className === 'hidden' ? '' : 'hidden'
|
||||||
}
|
}
|
||||||
|
function capitalize (s) { return s.substr(0, 1).toUpperCase() + s.substr(1) }
|
||||||
}
|
}
|
||||||
'use strict'
|
'use strict'
|
||||||
function History () {
|
function History () {
|
||||||
@ -408,8 +409,15 @@ function Client () {
|
|||||||
this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.write('dotgrid', 'grid', this.tool.export(), 'text/plain') })
|
this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.write('dotgrid', 'grid', this.tool.export(), 'text/plain') })
|
||||||
this.acels.set('File', 'Export Vector', 'CmdOrCtrl+E', () => { this.source.write('dotgrid', 'svg', this.manager.toString(), 'image/svg+xml') })
|
this.acels.set('File', 'Export Vector', 'CmdOrCtrl+E', () => { this.source.write('dotgrid', 'svg', this.manager.toString(), 'image/svg+xml') })
|
||||||
this.acels.set('File', 'Export Image', 'CmdOrCtrl+Shift+E', () => { this.manager.toPNG(this.tool.settings.size, (dataUrl) => { this.source.write('dotgrid', 'png', dataUrl, 'image/png') }) })
|
this.acels.set('File', 'Export Image', 'CmdOrCtrl+Shift+E', () => { this.manager.toPNG(this.tool.settings.size, (dataUrl) => { this.source.write('dotgrid', 'png', dataUrl, 'image/png') }) })
|
||||||
this.acels.set('History', 'Undo', 'CmdOrCtrl+Z', () => { this.tool.undo() })
|
this.acels.set('Edit', 'Undo', 'CmdOrCtrl+Z', () => { this.tool.undo() })
|
||||||
this.acels.set('History', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.tool.redo() })
|
this.acels.set('Edit', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.tool.redo() })
|
||||||
|
this.acels.set('View', 'Color Picker', 'G', () => { this.picker.start() })
|
||||||
|
this.acels.set('View', 'Toggle Grid', 'H', () => { this.renderer.toggle() })
|
||||||
|
this.acels.set('View', 'Toggle Tools', 'CmdOrCtrl+H', () => { this.interface.toggle() })
|
||||||
|
this.acels.set('Layers', 'Foreground', 'CmdOrCtrl+1', () => { this.tool.selectLayer(0) })
|
||||||
|
this.acels.set('Layers', 'Middleground', 'CmdOrCtrl+2', () => { this.tool.selectLayer(1) })
|
||||||
|
this.acels.set('Layers', 'Background', 'CmdOrCtrl+3', () => { this.tool.selectLayer(2) })
|
||||||
|
this.acels.set('Layers', 'Merge Layers', 'CmdOrCtrl+M', () => { this.tool.merge() })
|
||||||
this.acels.set('Stroke', 'Line', 'A', () => { this.tool.cast('line') })
|
this.acels.set('Stroke', 'Line', 'A', () => { this.tool.cast('line') })
|
||||||
this.acels.set('Stroke', 'Arc', 'S', () => { this.tool.cast('arc_c') })
|
this.acels.set('Stroke', 'Arc', 'S', () => { this.tool.cast('arc_c') })
|
||||||
this.acels.set('Stroke', 'Arc Rev', 'D', () => { this.tool.cast('arc_r') })
|
this.acels.set('Stroke', 'Arc Rev', 'D', () => { this.tool.cast('arc_r') })
|
||||||
@ -418,27 +426,21 @@ function Client () {
|
|||||||
this.acels.set('Stroke', 'Arc(full)', 'T', () => { this.tool.cast('arc_c_full') })
|
this.acels.set('Stroke', 'Arc(full)', 'T', () => { this.tool.cast('arc_c_full') })
|
||||||
this.acels.set('Stroke', 'Arc Rev(full)', 'Y', () => { this.tool.cast('arc_r_full') })
|
this.acels.set('Stroke', 'Arc Rev(full)', 'Y', () => { this.tool.cast('arc_r_full') })
|
||||||
this.acels.set('Stroke', 'Clear Selection', 'Escape', () => { this.tool.clear() })
|
this.acels.set('Stroke', 'Clear Selection', 'Escape', () => { this.tool.clear() })
|
||||||
this.acels.set('Effect', 'Linecap', 'Q', () => { this.tool.toggle('linecap') })
|
this.acels.set('Stroke', 'Erase Segment', 'Backspace', () => { this.tool.removeSegment() })
|
||||||
this.acels.set('Effect', 'Linejoin', 'W', () => { this.tool.toggle('linejoin') })
|
this.acels.set('Control', 'Add Point', 'Enter', () => { this.tool.addVertex(this.cursor.pos); this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Mirror', 'E', () => { this.tool.toggle('mirror') })
|
this.acels.set('Control', 'Move Up', 'Up', () => { this.cursor.pos.y -= 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Fill', 'R', () => { this.tool.toggle('fill') })
|
this.acels.set('Control', 'Move Right', 'Right', () => { this.cursor.pos.x += 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thicker', '}', () => { this.tool.toggle('thickness', 1) })
|
this.acels.set('Control', 'Move Down', 'Down', () => { this.cursor.pos.y += 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thinner', '{', () => { this.tool.toggle('thickness', -1) })
|
this.acels.set('Control', 'Move Left', 'Left', () => { this.cursor.pos.x -= 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thicker +5', ']', () => { this.tool.toggle('thickness', 5) })
|
this.acels.set('Control', 'Remove Point', 'X', () => { this.tool.removeSegmentsAt(this.cursor.pos) })
|
||||||
this.acels.set('Effect', 'Thinner -5', '[', () => { this.tool.toggle('thickness', -5) })
|
this.acels.set('Style', 'Linecap', 'Q', () => { this.tool.toggle('linecap') })
|
||||||
this.acels.set('Manual', 'Add Point', 'Enter', () => { this.tool.addVertex(this.cursor.pos); this.renderer.update() })
|
this.acels.set('Style', 'Linejoin', 'W', () => { this.tool.toggle('linejoin') })
|
||||||
this.acels.set('Manual', 'Move Up', 'Up', () => { this.cursor.pos.y -= 15; this.renderer.update() })
|
this.acels.set('Style', 'Mirror', 'E', () => { this.tool.toggle('mirror') })
|
||||||
this.acels.set('Manual', 'Move Right', 'Right', () => { this.cursor.pos.x += 15; this.renderer.update() })
|
this.acels.set('Style', 'Fill', 'R', () => { this.tool.toggle('fill') })
|
||||||
this.acels.set('Manual', 'Move Down', 'Down', () => { this.cursor.pos.y += 15; this.renderer.update() })
|
this.acels.set('Style', 'Thicker', '}', () => { this.tool.toggle('thickness', 1) })
|
||||||
this.acels.set('Manual', 'Move Left', 'Left', () => { this.cursor.pos.x -= 15; this.renderer.update() })
|
this.acels.set('Style', 'Thinner', '{', () => { this.tool.toggle('thickness', -1) })
|
||||||
this.acels.set('Manual', 'Remove Point', 'Shift+Backspace', () => { this.tool.removeSegmentsAt(this.cursor.pos) })
|
this.acels.set('Style', 'Thicker +5', ']', () => { this.tool.toggle('thickness', 5) })
|
||||||
this.acels.set('Manual', 'Remove Segment', 'Backspace', () => { this.tool.removeSegment() })
|
this.acels.set('Style', 'Thinner -5', '[', () => { this.tool.toggle('thickness', -5) })
|
||||||
this.acels.set('Layers', 'Foreground', 'CmdOrCtrl+1', () => { this.tool.selectLayer(0) })
|
|
||||||
this.acels.set('Layers', 'Middleground', 'CmdOrCtrl+2', () => { this.tool.selectLayer(1) })
|
|
||||||
this.acels.set('Layers', 'Background', 'CmdOrCtrl+3', () => { this.tool.selectLayer(2) })
|
|
||||||
this.acels.set('Layers', 'Merge Layers', 'CmdOrCtrl+M', () => { this.tool.merge() })
|
|
||||||
this.acels.set('View', 'Color Picker', 'G', () => { this.picker.start() })
|
|
||||||
this.acels.set('View', 'Toggle Grid', 'H', () => { this.renderer.toggle() })
|
|
||||||
this.acels.route(this)
|
this.acels.route(this)
|
||||||
this.manager.install()
|
this.manager.install()
|
||||||
this.interface.install(host)
|
this.interface.install(host)
|
||||||
@ -888,12 +890,6 @@ function Interface (client) {
|
|||||||
this.isVisible = !this.isVisible
|
this.isVisible = !this.isVisible
|
||||||
this.el.className = this.isVisible ? 'visible' : 'hidden'
|
this.el.className = this.isVisible ? 'visible' : 'hidden'
|
||||||
}
|
}
|
||||||
document.onkeydown = function (e) {
|
|
||||||
if (e.key === 'Tab') {
|
|
||||||
client.interface.toggle()
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function capitalize (str) {
|
function capitalize (str) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,15 @@ function Client () {
|
|||||||
this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.write('dotgrid', 'grid', this.tool.export(), 'text/plain') })
|
this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.write('dotgrid', 'grid', this.tool.export(), 'text/plain') })
|
||||||
this.acels.set('File', 'Export Vector', 'CmdOrCtrl+E', () => { this.source.write('dotgrid', 'svg', this.manager.toString(), 'image/svg+xml') })
|
this.acels.set('File', 'Export Vector', 'CmdOrCtrl+E', () => { this.source.write('dotgrid', 'svg', this.manager.toString(), 'image/svg+xml') })
|
||||||
this.acels.set('File', 'Export Image', 'CmdOrCtrl+Shift+E', () => { this.manager.toPNG(this.tool.settings.size, (dataUrl) => { this.source.write('dotgrid', 'png', dataUrl, 'image/png') }) })
|
this.acels.set('File', 'Export Image', 'CmdOrCtrl+Shift+E', () => { this.manager.toPNG(this.tool.settings.size, (dataUrl) => { this.source.write('dotgrid', 'png', dataUrl, 'image/png') }) })
|
||||||
this.acels.set('History', 'Undo', 'CmdOrCtrl+Z', () => { this.tool.undo() })
|
this.acels.set('Edit', 'Undo', 'CmdOrCtrl+Z', () => { this.tool.undo() })
|
||||||
this.acels.set('History', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.tool.redo() })
|
this.acels.set('Edit', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.tool.redo() })
|
||||||
|
this.acels.set('View', 'Color Picker', 'G', () => { this.picker.start() })
|
||||||
|
this.acels.set('View', 'Toggle Grid', 'H', () => { this.renderer.toggle() })
|
||||||
|
this.acels.set('View', 'Toggle Tools', 'CmdOrCtrl+H', () => { this.interface.toggle() })
|
||||||
|
this.acels.set('Layers', 'Foreground', 'CmdOrCtrl+1', () => { this.tool.selectLayer(0) })
|
||||||
|
this.acels.set('Layers', 'Middleground', 'CmdOrCtrl+2', () => { this.tool.selectLayer(1) })
|
||||||
|
this.acels.set('Layers', 'Background', 'CmdOrCtrl+3', () => { this.tool.selectLayer(2) })
|
||||||
|
this.acels.set('Layers', 'Merge Layers', 'CmdOrCtrl+M', () => { this.tool.merge() })
|
||||||
this.acels.set('Stroke', 'Line', 'A', () => { this.tool.cast('line') })
|
this.acels.set('Stroke', 'Line', 'A', () => { this.tool.cast('line') })
|
||||||
this.acels.set('Stroke', 'Arc', 'S', () => { this.tool.cast('arc_c') })
|
this.acels.set('Stroke', 'Arc', 'S', () => { this.tool.cast('arc_c') })
|
||||||
this.acels.set('Stroke', 'Arc Rev', 'D', () => { this.tool.cast('arc_r') })
|
this.acels.set('Stroke', 'Arc Rev', 'D', () => { this.tool.cast('arc_r') })
|
||||||
@ -61,27 +68,21 @@ function Client () {
|
|||||||
this.acels.set('Stroke', 'Arc(full)', 'T', () => { this.tool.cast('arc_c_full') })
|
this.acels.set('Stroke', 'Arc(full)', 'T', () => { this.tool.cast('arc_c_full') })
|
||||||
this.acels.set('Stroke', 'Arc Rev(full)', 'Y', () => { this.tool.cast('arc_r_full') })
|
this.acels.set('Stroke', 'Arc Rev(full)', 'Y', () => { this.tool.cast('arc_r_full') })
|
||||||
this.acels.set('Stroke', 'Clear Selection', 'Escape', () => { this.tool.clear() })
|
this.acels.set('Stroke', 'Clear Selection', 'Escape', () => { this.tool.clear() })
|
||||||
this.acels.set('Effect', 'Linecap', 'Q', () => { this.tool.toggle('linecap') })
|
this.acels.set('Stroke', 'Erase Segment', 'Backspace', () => { this.tool.removeSegment() })
|
||||||
this.acels.set('Effect', 'Linejoin', 'W', () => { this.tool.toggle('linejoin') })
|
this.acels.set('Control', 'Add Point', 'Enter', () => { this.tool.addVertex(this.cursor.pos); this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Mirror', 'E', () => { this.tool.toggle('mirror') })
|
this.acels.set('Control', 'Move Up', 'Up', () => { this.cursor.pos.y -= 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Fill', 'R', () => { this.tool.toggle('fill') })
|
this.acels.set('Control', 'Move Right', 'Right', () => { this.cursor.pos.x += 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thicker', '}', () => { this.tool.toggle('thickness', 1) })
|
this.acels.set('Control', 'Move Down', 'Down', () => { this.cursor.pos.y += 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thinner', '{', () => { this.tool.toggle('thickness', -1) })
|
this.acels.set('Control', 'Move Left', 'Left', () => { this.cursor.pos.x -= 15; this.renderer.update() })
|
||||||
this.acels.set('Effect', 'Thicker +5', ']', () => { this.tool.toggle('thickness', 5) })
|
this.acels.set('Control', 'Remove Point', 'X', () => { this.tool.removeSegmentsAt(this.cursor.pos) })
|
||||||
this.acels.set('Effect', 'Thinner -5', '[', () => { this.tool.toggle('thickness', -5) })
|
this.acels.set('Style', 'Linecap', 'Q', () => { this.tool.toggle('linecap') })
|
||||||
this.acels.set('Manual', 'Add Point', 'Enter', () => { this.tool.addVertex(this.cursor.pos); this.renderer.update() })
|
this.acels.set('Style', 'Linejoin', 'W', () => { this.tool.toggle('linejoin') })
|
||||||
this.acels.set('Manual', 'Move Up', 'Up', () => { this.cursor.pos.y -= 15; this.renderer.update() })
|
this.acels.set('Style', 'Mirror', 'E', () => { this.tool.toggle('mirror') })
|
||||||
this.acels.set('Manual', 'Move Right', 'Right', () => { this.cursor.pos.x += 15; this.renderer.update() })
|
this.acels.set('Style', 'Fill', 'R', () => { this.tool.toggle('fill') })
|
||||||
this.acels.set('Manual', 'Move Down', 'Down', () => { this.cursor.pos.y += 15; this.renderer.update() })
|
this.acels.set('Style', 'Thicker', '}', () => { this.tool.toggle('thickness', 1) })
|
||||||
this.acels.set('Manual', 'Move Left', 'Left', () => { this.cursor.pos.x -= 15; this.renderer.update() })
|
this.acels.set('Style', 'Thinner', '{', () => { this.tool.toggle('thickness', -1) })
|
||||||
this.acels.set('Manual', 'Remove Point', 'Shift+Backspace', () => { this.tool.removeSegmentsAt(this.cursor.pos) })
|
this.acels.set('Style', 'Thicker +5', ']', () => { this.tool.toggle('thickness', 5) })
|
||||||
this.acels.set('Manual', 'Remove Segment', 'Backspace', () => { this.tool.removeSegment() })
|
this.acels.set('Style', 'Thinner -5', '[', () => { this.tool.toggle('thickness', -5) })
|
||||||
this.acels.set('Layers', 'Foreground', 'CmdOrCtrl+1', () => { this.tool.selectLayer(0) })
|
|
||||||
this.acels.set('Layers', 'Middleground', 'CmdOrCtrl+2', () => { this.tool.selectLayer(1) })
|
|
||||||
this.acels.set('Layers', 'Background', 'CmdOrCtrl+3', () => { this.tool.selectLayer(2) })
|
|
||||||
this.acels.set('Layers', 'Merge Layers', 'CmdOrCtrl+M', () => { this.tool.merge() })
|
|
||||||
this.acels.set('View', 'Color Picker', 'G', () => { this.picker.start() })
|
|
||||||
this.acels.set('View', 'Toggle Grid', 'H', () => { this.renderer.toggle() })
|
|
||||||
this.acels.route(this)
|
this.acels.route(this)
|
||||||
|
|
||||||
this.manager.install()
|
this.manager.install()
|
||||||
|
@ -159,13 +159,6 @@ function Interface (client) {
|
|||||||
this.el.className = this.isVisible ? 'visible' : 'hidden'
|
this.el.className = this.isVisible ? 'visible' : 'hidden'
|
||||||
}
|
}
|
||||||
|
|
||||||
document.onkeydown = function (e) {
|
|
||||||
if (e.key === 'Tab') {
|
|
||||||
client.interface.toggle()
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function capitalize (str) {
|
function capitalize (str) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ function Acels (client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.convert = (event) => {
|
this.convert = (event) => {
|
||||||
const accelerator = event.key === ' ' ? 'Space' : event.key.substr(0, 1).toUpperCase() + event.key.substr(1)
|
const accelerator = event.key === ' ' ? 'Space' : capitalize(event.key.replace('Arrow', ''))
|
||||||
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
||||||
return `CmdOrCtrl+Shift+${accelerator}`
|
return `CmdOrCtrl+Shift+${accelerator}`
|
||||||
}
|
}
|
||||||
@ -81,6 +81,7 @@ function Acels (client) {
|
|||||||
this.onKeyDown = (e) => {
|
this.onKeyDown = (e) => {
|
||||||
const target = this.get(this.convert(e))
|
const target = this.get(this.convert(e))
|
||||||
if (!target || !target.downfn) { return this.pipe ? this.pipe.onKeyDown(e) : null }
|
if (!target || !target.downfn) { return this.pipe ? this.pipe.onKeyDown(e) : null }
|
||||||
|
|
||||||
target.downfn()
|
target.downfn()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
@ -118,4 +119,6 @@ function Acels (client) {
|
|||||||
this.toggle = () => {
|
this.toggle = () => {
|
||||||
this.el.className = this.el.className === 'hidden' ? '' : 'hidden'
|
this.el.className = this.el.className === 'hidden' ? '' : 'hidden'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function capitalize (s) { return s.substr(0, 1).toUpperCase() + s.substr(1) }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user