mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-16 12:47:41 +00:00
Merge pull request #6917 from keymanapp/feat/developer/touch-layout-schema-high-quality
feat(developer): cleanup touch layout files on load and save 🙊
This commit is contained in:
commit
ca47fce5b2
5 changed files with 114 additions and 33 deletions
|
|
@ -42,7 +42,8 @@ The general structure of a .keyman-touch-layout file is:
|
|||
## `root` object
|
||||
|
||||
The `root` object may contain up to three properties, each being a [`platform`
|
||||
object](#platform-object), named `"phone"`, `"tablet"` or `"desktop"`.
|
||||
object](#platform-object), named `"phone"`, `"tablet"` or `"desktop"`. There
|
||||
must be at least one property.
|
||||
|
||||
## `platform` object
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ optionally contain three additional properties: `font`, `fontsize`, and
|
|||
`displayUnderlying`.
|
||||
|
||||
* `layer`
|
||||
: An array of [`layer` objects](#layer-object). Required.
|
||||
: A non-empty array of [`layer` objects](#layer-object). Required.
|
||||
|
||||
* `font`
|
||||
: An optional CSS-style font-family specification, being the name of the font to
|
||||
|
|
@ -140,7 +141,7 @@ affect the modifiers in any key events generated by keys on the layer.
|
|||
|
||||
* `row`
|
||||
|
||||
: An array of [`row` objects](#row-object). Required.
|
||||
: A non-empty array of [`row` objects](#row-object). Required.
|
||||
|
||||
## `row` object
|
||||
|
||||
|
|
@ -150,19 +151,19 @@ properties: `id` and `key`.
|
|||
* `id`
|
||||
|
||||
: An non-negative integer denoting where the row appears, with `0` being the top
|
||||
row.
|
||||
row. Required.
|
||||
|
||||
Legacy: this value was sometimes an integer in a string. This string format is
|
||||
deprecated and will not be supported in future versions of Keyman Developer.
|
||||
|
||||
* `key`
|
||||
|
||||
: An array of [`key` objects](#key-object).
|
||||
: A non-empty array of [`key` objects](#key-object). Required.
|
||||
|
||||
## `key` object
|
||||
|
||||
Describes a single key on a touch layout row. See also [`sk`
|
||||
object](#sk-object). A `key` object has no required properties.
|
||||
object](#sk-object). A `key` object must include either an `id` or `sp` property.
|
||||
|
||||
* `id`
|
||||
|
||||
|
|
@ -314,7 +315,9 @@ properties are not fully supported as of Keyman 15: `font`, `fontsize`, `pad`,
|
|||
and `width`.
|
||||
|
||||
* `id`
|
||||
: A string identifier for the longpress key. See `key` object for details.
|
||||
|
||||
: String. Required. An identifier for the longpress key. See `key` object for
|
||||
details.
|
||||
|
||||
* `text`
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
"tablet": { "$ref": "#/definitions/platform" },
|
||||
"phone": { "$ref": "#/definitions/platform" },
|
||||
"desktop": { "$ref": "#/definitions/platform" }
|
||||
}
|
||||
},
|
||||
"minProperties": 1,
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"platform": {
|
||||
|
|
@ -28,7 +30,8 @@
|
|||
|
||||
"layers": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/layer" }
|
||||
"items": { "$ref": "#/definitions/layer" },
|
||||
"minItems": 1
|
||||
},
|
||||
|
||||
"layer": {
|
||||
|
|
@ -48,7 +51,8 @@
|
|||
|
||||
"rows": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/row" }
|
||||
"items": { "$ref": "#/definitions/row" },
|
||||
"minItems": 1
|
||||
},
|
||||
|
||||
"row": {
|
||||
|
|
@ -69,7 +73,8 @@
|
|||
|
||||
"keys": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/key" }
|
||||
"items": { "$ref": "#/definitions/key" },
|
||||
"minItems": 1
|
||||
},
|
||||
|
||||
"key": {
|
||||
|
|
@ -88,6 +93,13 @@
|
|||
"flick": { "$ref": "#/definitions/flick" },
|
||||
"multitap": { "$ref": "#/definitions/subkeys" }
|
||||
},
|
||||
"anyOf": [
|
||||
{"required": ["id"]},
|
||||
{"required": ["sp"]},
|
||||
{"required": ["sk"]},
|
||||
{"required": ["flick"]},
|
||||
{"required": ["multitap"]}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
|
|
@ -98,24 +110,25 @@
|
|||
|
||||
"key-sp": {
|
||||
"type": "integer",
|
||||
"enum": [0, 1, 2, 8, 9, 10],
|
||||
"enum": [0, 1, 2, 8, 9, 10]
|
||||
},
|
||||
|
||||
"key-pad": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 10000
|
||||
"maximum": 100000
|
||||
},
|
||||
|
||||
"key-width": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1000
|
||||
"maximum": 100000
|
||||
},
|
||||
|
||||
"subkeys": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/subkey" }
|
||||
"items": { "$ref": "#/definitions/subkey" },
|
||||
"minItems": 1
|
||||
},
|
||||
|
||||
"subkey": {
|
||||
|
|
@ -140,6 +153,7 @@
|
|||
"patternProperties": {
|
||||
"^(n|s|e|w|ne|nw|se|sw)$": { "$ref": "#/definitions/subkey" }
|
||||
},
|
||||
"minProperties": 1,
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -813,7 +813,7 @@ $(function() {
|
|||
};
|
||||
|
||||
this.saveJSON = function(force) {
|
||||
builder.removeEmptyRows();
|
||||
builder.cleanupKVKL();
|
||||
var newJson = JSON.stringify(KVKL, null, ' ');
|
||||
if(force || newJson != json) {
|
||||
// When adding or deleting layers and platforms, we need to force because
|
||||
|
|
@ -978,23 +978,6 @@ $(function() {
|
|||
);
|
||||
};
|
||||
|
||||
builder.removeEmptyRows = function() {
|
||||
var json = JSON.stringify(KVKL, null, ' ');
|
||||
for (var platform in KVKL) {
|
||||
for (let layer of KVKL[platform].layer) {
|
||||
let newRow = [], n = 1;
|
||||
for(let row of layer.row) {
|
||||
if(row.key.length > 0) {
|
||||
row.id = n;
|
||||
n++;
|
||||
newRow.push(row);
|
||||
}
|
||||
}
|
||||
layer.row = newRow;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
builder.textControlsInToolbar = function() {
|
||||
return $('body').hasClass('text-controls-in-toolbar');
|
||||
}
|
||||
|
|
@ -1004,6 +987,7 @@ $(function() {
|
|||
|
||||
function initBuilder() {
|
||||
$(function() {
|
||||
builder.cleanupKVKL();
|
||||
builder.prepareKeyCapTypes();
|
||||
builder.preparePlatforms();
|
||||
builder.enableUndoControls();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
<script><xsl:attribute name="src"><xsl:value-of select="/TouchLayoutBuilder/LibPath"/>layer-controls.js</xsl:attribute></script>
|
||||
<script><xsl:attribute name="src"><xsl:value-of select="/TouchLayoutBuilder/LibPath"/>builder-charmap.js</xsl:attribute></script>
|
||||
<script><xsl:attribute name="src"><xsl:value-of select="/TouchLayoutBuilder/LibPath"/>drag-drop.js</xsl:attribute></script>
|
||||
<script><xsl:attribute name="src"><xsl:value-of select="/TouchLayoutBuilder/LibPath"/>cleanup.js</xsl:attribute></script>
|
||||
<script>initBuilder();</script>
|
||||
</head>
|
||||
<body class='text-controls-in-toolbar'>
|
||||
|
|
|
|||
79
developer/src/tike/xml/layoutbuilder/cleanup.js
Normal file
79
developer/src/tike/xml/layoutbuilder/cleanup.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
$(function() {
|
||||
|
||||
builder.cleanupKVKL = function() {
|
||||
let cleanupEmptyArrays = function() {
|
||||
for (let platform in KVKL) {
|
||||
for (let layer of KVKL[platform].layer) {
|
||||
let newRow = [], n = 1;
|
||||
for(let row of layer.row) {
|
||||
if(row.key && Array.isArray(row.key)) {
|
||||
for(let key of row.key) {
|
||||
if(key.sk && (!Array.isArray(key.sk) || key.sk.length == 0)) {
|
||||
delete key.sk;
|
||||
}
|
||||
}
|
||||
if(row.key.length > 0) {
|
||||
row.id = n;
|
||||
n++;
|
||||
newRow.push(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
layer.row = newRow;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
let cleanupNumericField = function(obj, prop) {
|
||||
if(typeof obj[prop] == 'number') {
|
||||
return true;
|
||||
}
|
||||
if(typeof obj[prop] == 'string') {
|
||||
let v = obj[prop].trim();
|
||||
if(v != '') {
|
||||
v = parseInt(v, 10);
|
||||
if(isFinite(v)) {
|
||||
obj[prop] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete obj[prop];
|
||||
return true;
|
||||
}
|
||||
|
||||
let cleanupKeyTypes = function(key) {
|
||||
// Delete empty strings for id
|
||||
if(typeof key.id != 'undefined') {
|
||||
if(typeof key.id != 'string') delete key.id;
|
||||
else if(key.id.trim() == '') delete key.id;
|
||||
}
|
||||
// Enforce numeric types for sp, pad, width
|
||||
return cleanupNumericField(key, 'sp') &&
|
||||
cleanupNumericField(key, 'pad') &&
|
||||
cleanupNumericField(key, 'width');
|
||||
}
|
||||
|
||||
let cleanupTypes = function() {
|
||||
for(let platform in KVKL) {
|
||||
for(let layer of KVKL[platform].layer) {
|
||||
for(let row of layer.row) {
|
||||
for(let key of row.key) {
|
||||
cleanupKeyTypes(key);
|
||||
if(key.sk) {
|
||||
for(let sk of key.sk) {
|
||||
cleanupKeyTypes(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return cleanupEmptyArrays() && cleanupTypes();
|
||||
};
|
||||
|
||||
}.bind(builder));
|
||||
Loading…
Add table
Reference in a new issue