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.
966 lines
52 KiB
HTML
966 lines
52 KiB
HTML
<!--***********************************************
|
|
KEYBOARD LAYOUT EDITOR
|
|
Copyright (C) 2013-2015 Ian Prest
|
|
All rights reserved.
|
|
************************************************-->
|
|
<!DOCTYPE html>
|
|
<html ng-app="kbApp">
|
|
<head>
|
|
<title>Keyboard Layout Editor</title>
|
|
<meta charset="utf-8">
|
|
<link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css" media="screen">
|
|
<link rel="stylesheet" type="text/css" href="bower_components/fontawesome/css/font-awesome.min.css">
|
|
<link rel="stylesheet" type="text/css" href="bower_components/hint.css/hint.min.css">
|
|
<link rel="stylesheet" type="text/css" href="bower_components/angular-bootstrap-colorpicker/css/colorpicker.min.css">
|
|
<link rel="stylesheet" type="text/css" href="css/kb.css">
|
|
<script type="text/javascript" src="bower_components/jquery/jquery.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular/angular.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular-sanitize/angular-sanitize.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular-ui-utils/components/angular-ui-docs/build/ui-utils.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular-ui-bootstrap/dist/ui-bootstrap-tpls-0.12.0.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/crypto-js/crypto-js.js"></script>
|
|
<script type="text/javascript" src="bower_components/marked/marked.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/FileSaver/FileSaver.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/ng-file-upload/ng-file-upload.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular-native-dragdrop/draganddrop.js"></script>
|
|
<script type="text/javascript" src="bower_components/angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/doT/doT.min.js"></script>
|
|
<script type="text/javascript" src="bower_components/URLON/src/urlon.js"></script>
|
|
<script type="text/javascript" src="js/color.js"></script>
|
|
<script type="text/javascript" src="js/jsonl.min.js"></script>
|
|
<script type="text/javascript" src="extensions.js"></script>
|
|
<script type="text/javascript" src="render.js"></script>
|
|
<script type="text/javascript" src="serial.js"></script>
|
|
<script type="text/javascript" src="kb.js"></script>
|
|
</head>
|
|
<body ng-controller="kbCtrl"
|
|
ng-mouseup="selectRelease($event)"
|
|
ng-mousemove="selectMove($event)"
|
|
ui-keydown="{'shift-191' : 'showHelp($event)',
|
|
112 : 'showHelp($event)',
|
|
118 : 'showOptions($event)',
|
|
'ctrl-83' : 'save($event)' }">
|
|
<div id="wrap">
|
|
|
|
<!--***********************************************
|
|
Nav Bar / Header
|
|
************************************************-->
|
|
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
|
|
<div class="navbar-header">
|
|
<!-- Hamburger menu, when width is too small -->
|
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
|
|
<span class="sr-only">Toggle navigation</span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
</button>
|
|
|
|
<!-- Main branding icon/title -->
|
|
<a class="navbar-brand" href="#"><i class="fa fa-keyboard-o"></i> keyboard-layout-editor.com</a>
|
|
</div>
|
|
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
|
|
|
<!-- Left-aligned NavBar buttons -->
|
|
<ul class="nav navbar-nav">
|
|
<!-- Presets dropdown -->
|
|
<li class="dropdown" dropdown>
|
|
<a class="dropdown-toggle" dropdown-toggle><i class="fa fa-keyboard-o"></i> Preset <b class="caret"></b></a>
|
|
<ul class="dropdown-menu">
|
|
<li class="dropdown-header">Standard Layouts:</li>
|
|
<li ng-repeat="v in layouts"><a ng-click="loadPreset(v.data)" href="#">{{v.name}}</a></li>
|
|
<li class="divider"></li>
|
|
<li class="dropdown-header">Complex Samples:</li>
|
|
<li ng-repeat="(k,v) in samples"><a ng-click="loadSample(v)" href="#">{{k}}</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<!-- Color swatches dropdown -->
|
|
<li class="dropdown" dropdown>
|
|
<a class="dropdown-toggle" dropdown-toggle><i class="fa fa-th"></i> Color Swatches <b class="caret"></b></a>
|
|
<ul class="dropdown-menu">
|
|
<li ng-repeat="pal in palettes"><a ng-click="loadPalette(pal)" href="#">{{pal.name}}</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<!-- Right-aligned NavBar buttons -->
|
|
<ul class="nav navbar-nav navbar-right" style="">
|
|
<!-- Options button -->
|
|
<li><a href="#" ng-click="showOptions()"><i class="fa fa-cog"></i> Options</a></li>
|
|
<!-- Permalink button -->
|
|
<li><a ng-href="{{getPermalink()}}" target="_blank" ng-click="dirty = false"><i class="fa fa-link"></i> Permalink</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="body" ng-cloak>
|
|
|
|
<!--***********************************************
|
|
Main Toolbar
|
|
************************************************-->
|
|
<!-- Add Key button w/dropdown -->
|
|
<div class="btn-group" dropdown>
|
|
<button type="button" class="btn btn-primary" ng-click="addKey()"><i class="fa fa-plus-circle"></i> Add Key</button>
|
|
<button type="button" class="btn btn-primary dropdown-toggle" dropdown-toggle>
|
|
<span class="caret"></span>
|
|
</button>
|
|
<ul class="dropdown-menu" role="menu">
|
|
<li><a ng-click="addKeys(1)">Add 1 Key</a></li>
|
|
<li><a ng-click="addKeys(5)">Add 5 Keys</a></li>
|
|
<li><a ng-click="addKeys(10)">Add 10 Keys</a></li>
|
|
<li><a ng-click="addKeys(25)">Add 25 Keys</a></li>
|
|
<li class="divider" ng-class="{hidden: !specialKeys}"></li>
|
|
<li ng-repeat="(k,v) in specialKeys"><a ng-click="addKey(v)">Add '{{k}}' Key</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Delete Key button -->
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-danger" ng-class="{disabled:selectedKeys.length<1}" ng-click="deleteKeys()">
|
|
<i class="fa fa-minus-circle"></i> Delete Keys
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Undo/Redo button group -->
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canUndo()}" ng-click="undo()"><i class="fa fa-undo"></i> Undo</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canRedo()}" ng-click="redo()"><i class="fa fa-repeat"></i> Redo</button>
|
|
</div>
|
|
|
|
<!-- Clipboard button group -->
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canCopy()}" ng-click="cut()"><i class="fa fa-cut"></i> Cut</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canCopy()}" ng-click="copy()"><i class="fa fa-copy"></i> Copy</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canPaste()}" ng-click="paste()"><i class="fa fa-paste"></i> Paste</button>
|
|
</div>
|
|
<!-- Save button (right aligned) -->
|
|
<div class="btn-group pull-right">
|
|
<button type="button" class="btn btn-success" ng-class="{disabled:!canSave()}" ng-click="save()"><i class="fa fa-save"></i> Save</button>
|
|
</div>
|
|
<div class="btn-group pull-right" style="margin-right: 4px;">
|
|
<button type="button" class="btn btn-success" ng-click="downloadSvg()"><i class="fa fa-download"></i> Download SVG (experimental)</button>
|
|
</div>
|
|
|
|
|
|
<!--***********************************************
|
|
Main Keyboard Preview/Editor area
|
|
************************************************-->
|
|
<div id="keyboard" ng-cloak
|
|
tabindex="0"
|
|
ng-style="{height: kbHeight + 'px', 'background-color': keyboard.meta.backcolor}"
|
|
ui-keydown="{ left:'moveKeys(-moveStep,0,$event)',
|
|
right:'moveKeys(moveStep,0,$event)',
|
|
up:'moveKeys(0,-moveStep,$event)',
|
|
down:'moveKeys(0,moveStep,$event)',
|
|
'shift-left':'sizeKeys(-sizeStep,0,$event)',
|
|
'shift-right':'sizeKeys(sizeStep,0,$event)',
|
|
'shift-up':'sizeKeys(0,-sizeStep,$event)',
|
|
'shift-down':'sizeKeys(0,sizeStep,$event)',
|
|
'pageup':'rotateKeys(-rotateStep,$event)',
|
|
'pagedown':'rotateKeys(rotateStep,$event)',
|
|
'ctrl-left':'moveCenterKeys(-moveStep,0,$event)',
|
|
'ctrl-right':'moveCenterKeys(moveStep,0,$event)',
|
|
'ctrl-up':'moveCenterKeys(0,-moveStep,$event)',
|
|
'ctrl-down':'moveCenterKeys(0,moveStep,$event)',
|
|
delete:'deleteKeys()',
|
|
insert:'addKey()',
|
|
74: 'prevKey($event)',
|
|
75: 'nextKey($event)',
|
|
'shift-74': 'prevKey($event)',
|
|
'shift-75': 'nextKey($event)',
|
|
113: 'focusEditor()',
|
|
esc: 'unselectAll()',
|
|
'ctrl-65': 'selectAll($event)',
|
|
'ctrl-67 ctrl-45': 'copy($event)',
|
|
'ctrl-88 shift-46': 'cut($event)',
|
|
'ctrl-86 shift-45': 'paste($event)',
|
|
'ctrl-90' : 'undo()',
|
|
'ctrl-shift-90' : 'redo()',
|
|
'ctrl-89' : 'redo()' }"
|
|
ng-mousedown="selectClick($event)"
|
|
ngf-drop="true" ngf-change="uploadJson($files, $event)" ngf-drag-over-class="drag-over">
|
|
|
|
<div ng-repeat="key in keys()"
|
|
class="key {{key.profile}}"
|
|
ng-mouseover="hoveredKey=key"
|
|
ng-mouseleave="hoveredKey=null"
|
|
ng-class="{hover: hoveredKey==key, selected: selectedKeys.indexOf(key)>=0, HOMING:key.nub}"
|
|
ng-bind-html="key.html">
|
|
</div>
|
|
|
|
<div style="position:relative;line-height:1.2;" ng-style="{top:(kbHeight-26)+'px'}"
|
|
ng-hide="!keyboard.meta.name && !keyboard.meta.author">
|
|
<a href="#" ng-click="previewNotes()">{{keyboard.meta.name}}<br/><i>{{keyboard.meta.author}}</i></a>
|
|
</div>
|
|
<div style='clear:both'></div>
|
|
{{calcKbHeight()}}
|
|
</div>
|
|
<div id="selectionRectangle" ng-style="{display:selRect.display, left:selRect.l+'px', width:selRect.w+'px', top:selRect.t+'px', height:selRect.h+'px'}"></div>
|
|
<div id="rotationCrosshairs" ng-style="{display:multi.crosshairs, left:(keyboardLeft()+multi.crosshairs_x-1)+'px', top:(keyboardTop()+multi.crosshairs_y-3)+'px'}"><i class="fa fa-crosshairs"></i></div>
|
|
|
|
|
|
<!--***********************************************
|
|
Editor controls
|
|
************************************************-->
|
|
|
|
<!-- Tab strip -->
|
|
<ul class="nav nav-tabs" ng-cloak>
|
|
<li ng-class="{active:selTab==0}"><a ng-click="selTab=0" data-toggle="tab"><i class="fa fa-edit"></i> Properties</a></li>
|
|
<li ng-class="{active:selTab==1}"><a ng-click="selTab=1" data-toggle="tab"><i class="fa fa-keyboard-o"></i> Keyboard Properties</a></li>
|
|
<li ng-class="{active:selTab==2}"><a ng-click="selTab=2" data-toggle="tab"><i class="fa fa-code"></i> Raw data</a></li>
|
|
</ul>
|
|
<div id="tab-content" class='col-md-12 col-lg-12 row' ui-keydown="{esc:'focusKb()'}" ng-cloak>
|
|
|
|
<!-- PROPERTIES EDITOR -->
|
|
<div id="properties" ng-class="{hidden:selTab!=0}">
|
|
<form class="form-horizontal col-sm-8 col-md-5 col-lg-5">
|
|
|
|
<!-- Top Label -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="labeleditor0">Top Label:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-label-editor label-index="0" hint-text="Specify the primary text of the keycap; typically displayed top-left, unless the centering options are used."></kbd-label-editor>
|
|
<kbd-label-editor label-index="2" hint-text="Specify secondary text for the keycap; typically displayed top-right."></kbd-label-editor>
|
|
<kbd-multi-check field="centerx" hint-text="Center the keycap text horizontally; the labels that would normally be left-aligned will be centered instead.">Center X</kbd-multi-check>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Center Label -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="labeleditor6">Center Label:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-label-editor label-index="6" hint-text="Specify secondary text for the keycap; typically displayed center-left. You can specify a horizontal rule with <hr>."></kbd-label-editor>
|
|
<kbd-label-editor label-index="7" hint-text="Specify secondary text for the keycap; typically displayed center-right."></kbd-label-editor>
|
|
<kbd-multi-check field="centery" hint-text="Center the keycap text vertically; the labels that would normally be top-aligned will be centered instead.">Center Y</kbd-multi-check>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bottom Label -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="labeleditor1">Bottom Label:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-label-editor label-index="1" hint-text="Specify secondary text for the keycap; typically displayed bottom-left."></kbd-label-editor>
|
|
<kbd-label-editor label-index="3" hint-text="Specify secondary text for the keycap; typically displayed bottom-right."></kbd-label-editor>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Side-Print Label -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="labeleditor4">Side-Print Label:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-label-editor label-index="4" hint-text="Specify the primary side-printed text for the keycap."></kbd-label-editor>
|
|
<kbd-label-editor label-index="5" hint-text="Specify secondary side-printed text for the keycap."></kbd-label-editor>
|
|
<kbd-multi-check field="centerf" hint-text="Center the side-printed text.">Center</kbd-multi-check>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Legend Size -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="fontheight-editor">Legend Size:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the primary and secondary sizes for the keycap legends. The primary size affects only the primary text legend, while the secondary size is applied to all other legends.">
|
|
<kbd-multi-numbox field="fontheight" size="6" min="1" max="9"></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> / </div>
|
|
<kbd-multi-numbox field="fontheight2" size="6" min="1" max="9"></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Width -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="width-editor">Width:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the primary and secondary widths for the keycap. The secondary width is used to specify the size of non-rectangular or stepped keys.">
|
|
<kbd-multi-numbox field="width" size="6" min="0.5" max="12" step='{{sizeStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> / </div>
|
|
<kbd-multi-numbox field="width2" size="6" min="0.5" max="12" step='{{sizeStep}}'></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Height -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="height-editor">Height:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the primary and secondary heights for the keycap. The secondary height is used to specify the size of non-rectangular or stepped keys.">
|
|
<kbd-multi-numbox field="height" size="6" min="0.5" max="12" step='{{sizeStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> / </div>
|
|
<kbd-multi-numbox field="height2" size="6" min="0.5" max="12" step='{{sizeStep}}'></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- X -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="x-editor">X:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the X position of the keycap. An X-offset can also be specified to indicate how non-rectangular keys should be displayed.">
|
|
<kbd-multi-numbox field="x" size="6" min="0" max="36" step='{{moveStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> + </div>
|
|
<kbd-multi-numbox field="x2" size="6" min="-6" max="6" step='{{moveStep}}'></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Y -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="y-editor">Y:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the Y position of the keycap. A Y-offset can also be specified to indicate how non-rectangular keys should be displayed.">
|
|
<kbd-multi-numbox field="y" size="6" min="0" max="36" step='{{moveStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> + </div>
|
|
<kbd-multi-numbox field="y2" size="6" min="-6" max="6" step='{{moveStep}}'></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Profile / Row -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="profileeditor">Profile / Row:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the profile and (optionally) the row-number of the selected keys, e.g., 'DCS R1', 'DSA', 'DSA SPACE', etc.">
|
|
<div class="form-group form-group-sm">
|
|
<input id="profileeditor" class="form-control input-sm" size="24" type='text'
|
|
ng-model="multi.profile"
|
|
ng-change="updateMulti('profile')"
|
|
ng-blur="validateMulti('profile')"
|
|
ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Key Color -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="coloreditor">Key Color:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-color-picker picker-id="coloreditor" picker-position="top"
|
|
ng-model="multi.color"
|
|
ng-change="updateMulti('color')"
|
|
ng-blur="validateMulti('color')"
|
|
ng-disabled="selectedKeys.length<1"
|
|
hint-text="Specify the color to use for the background of the selected keycaps."
|
|
ui-on-Drop="dropSwatch($data,$event,false)" drop-channel="dragColor"></kbd-color-picker>
|
|
<div class="form-group form-group-sm color-name">{{colorName(multi.color)}}</div>
|
|
</div>
|
|
|
|
<!-- Swap Colors Button -->
|
|
<div>
|
|
<div id="swap-colors"
|
|
class="hint--top hint--rounded"
|
|
data-hint="Swap the text and keycap colors.">
|
|
<button class="btn btn-default"
|
|
ng-click="swapColors()"
|
|
ng-disabled="selectedKeys.length<1" >
|
|
<i class="fa fa-random"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Label Color -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="textcoloreditor">Label Color:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-color-picker picker-id="textcoloreditor" picker-position="top"
|
|
ng-model="multi.text[0]"
|
|
ng-change="updateMulti('text',-1)"
|
|
ng-blur="validateMulti('text')"
|
|
ng-disabled="selectedKeys.length<1"
|
|
hint-text="Specify the color to use for the legend text on the selected keycaps."
|
|
ui-on-Drop="dropSwatch($data,$event,true,-1)" drop-channel="dragColor"></kbd-color-picker>
|
|
<div class="form-group form-group-sm color-name">{{colorName(multi.text[0])}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rotation -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap" for="rotation_angle-editor">Rotation:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline hint--top hint--rounded"
|
|
data-hint="Specify the angle (in degrees) by which to rotate the keycaps, and the x & y coordinates of the center of rotation.">
|
|
<kbd-multi-numbox field="rotation_angle" size="3" min="-180" max="180" step='{{rotateStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> ° </div>
|
|
<kbd-multi-numbox field="rotation_x" size="6" min="0" max="36" step='{{moveStep}}'></kbd-multi-numbox>
|
|
<div class="form-group form-group-sm"> , </div>
|
|
<kbd-multi-numbox field="rotation_y" size="6" min="0" max="36" step='{{moveStep}}'></kbd-multi-numbox>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Misc -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-3 col-lg-3 text-nowrap">Misc:</label>
|
|
<div class="col-md-9 col-lg-9">
|
|
<div class="form-inline">
|
|
<kbd-multi-check field="ghost" hint-text="Specify whether the selected keys should be rendered slightly transparently; this is useful to draw attention to the other, non-ghosted keycaps.">Ghosted</kbd-multi-check>
|
|
<kbd-multi-check field="stepped" hint-text="Specify whether the selected keys are 'stepped', i.e., part of the key is at a lower height than the rest. The secondary 'width' indicates the width of the stepped part.">Stepped</kbd-multi-check>
|
|
<kbd-multi-check field="nub" hint-text="Specifies that the selected keys are 'homing' keys, which help the user find the home-row by touch alone.">Homing</kbd-multi-check>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
|
|
<div class="col-md-4 col-lg-4" ng-class="{hidden:!palette.name}">
|
|
{{palette.name}} <a ng-href='{{palette.href}}' data-hint="{{palette.description}}" class="hint--top hint--rounded" target="_blank">(more info)</a>
|
|
<ul id="swatches" ng-class="{disabled:selectedKeys.length<1}">
|
|
<li ng-repeat="color in palette.colors"
|
|
ng-style="{'background-color':color.css}"
|
|
ng-click="clickSwatch(color,$event)"
|
|
class="swatch hint--top"
|
|
ng-class="{'selected-bg': color.css === multi.color, 'selected-fg': color.css === multi.text[0]}"
|
|
data-hint="{{color.name}}"
|
|
ui-draggable="true" drag-channel="dragColor" drag="color">
|
|
<div class='highlight fg'></div>
|
|
<div class='highlight bg'></div>
|
|
</li>
|
|
</ul>
|
|
<alert type="warning" style="margin-top:10px;" ng-hide="paletteAlertHidden" close="paletteAlertHidden = true">
|
|
<i class="fa fa-info-circle"></i> Click on a swatch to set the color of the selected key(s), or Ctrl+Click to set the text color. You can also drag color swatches to individual labels to set different colors for each one.
|
|
</alert>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- KEYBOARD PROPERTIES EDITOR -->
|
|
<div id="kbdproperties" ng-class="{hidden:selTab!=1}">
|
|
<form class="form-horizontal col-sm-12 col-md-12 col-lg-12">
|
|
|
|
<!-- Keyboard Color -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-2 col-lg-1 text-nowrap" for="kbdcoloreditor">Keyboard Color:</label>
|
|
<div class="col-md-10 col-lg-11">
|
|
<div class="form-inline">
|
|
<kbd-color-picker picker-id="kbdcoloreditor"
|
|
ng-model="meta.backcolor"
|
|
ng-change="updateMeta('backcolor')"
|
|
ng-blur="validateMeta('backcolor')"
|
|
hint-text="Specify the background color for the keyboard."></kbd-color-picker>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Keyboard Name -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-2 col-lg-1 text-nowrap" for="kbdnameeditor">Keyboard Name:</label>
|
|
<div class="col-md-10 col-lg-11 form-outdent hint--top hint--rounded"
|
|
data-hint="Specify the name of this keyboard layout.">
|
|
<input id="kbdnameeditor" class="form-control input-sm" type='text'
|
|
ng-model="meta.name"
|
|
ng-change="updateMeta('name')"
|
|
ng-blur="validateMeta('name')">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Author -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-2 col-lg-1 text-nowrap" for="authoreditor">Author:</label>
|
|
<div class="col-md-10 col-lg-11 form-outdent hint--top hint--rounded"
|
|
data-hint="Specify the author of this keyboard layout.">
|
|
<input id="authoreditor" class="form-control input-sm" type='text'
|
|
ng-model="meta.author"
|
|
ng-change="updateMeta('author')"
|
|
ng-blur="validateMeta('author')">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="form-group form-group-sm">
|
|
<label class="control-label col-md-2 col-lg-1 text-nowrap" for="noteseditor">Notes:</label>
|
|
<div class="col-md-10 col-lg-11 form-outdent">
|
|
<div class="hint--top hint--rounded" style="width:100%"
|
|
data-hint="Specify any additional notes about this keyboard layout, e.g., links to manufacturers, colors used, additional credits, etc. GitHub-Flavored Markdown is supported for rich formatting.">
|
|
<textarea id="noteseditor" class="form-control" rows="15" spellcheck="true"
|
|
ng-model="meta.notes"
|
|
ng-change="updateMeta('notes')"
|
|
ng-blur="validateMeta('notes')"></textarea>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="btn-group btn-group-xs" role="group">
|
|
<button type="button" class="btn btn-success" ng-click="previewNotes()"><i class="fa fa-eye"></i> Preview</button>
|
|
</div>
|
|
<div class="btn-group btn-group-xs" role="group">
|
|
<a class="btn btn-primary" href="https://help.github.com/articles/markdown-basics/" target='_blank'><i class="fa fa-question-circle"></i> Markdown Syntax</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- RAW DATA EDITOR -->
|
|
<div id="tab-rawdata" ng-class="{hidden:selTab!=2}">
|
|
<div ngf-drop="true" ngf-change="uploadJson($files, $event)" ngf-drag-over-class="drag-over">
|
|
<textarea id="rawdata" spellcheck="false" ng-model="serialized" ng-change="updateFromSerialized()" ng-class="{error:deserializeException!==''}" rows="15"></textarea>
|
|
</div>
|
|
<div style='text-align:right;margin-top:4px;'>
|
|
<div class="btn-group btn-group-xs" role="group">
|
|
<button type="button" class="btn btn-success" ng-click="downloadJson()"><i class="fa fa-download"></i> Download JSON</button>
|
|
<button ngf-select="true" class="btn btn-success" ngf-change="uploadJson($files, $event)"><i class="fa fa-upload"></i> Upload JSON</button>
|
|
</div>
|
|
<div class="btn-group btn-group-xs" role="group">
|
|
<a class="btn btn-primary" href="https://github.com/ijprest/keyboard-layout-editor/wiki/Serialized-Data-Format" target='_blank'><i class="fa fa-question-circle"></i> Raw Data Syntax</a>
|
|
</div>
|
|
</div>
|
|
<div id="rawdata-error" class="alert alert-danger" style='margin-top:1em;margin-bottom:0px' ng-class="{hidden:!deserializeException}">{{deserializeException}}</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="col-md-12 col-lg-12 row" style="margin-top:1em;margin-left:0px;">
|
|
<alert type="success" ng-hide="!saved" close="saved=false" ng-cloak>
|
|
Saved! Your saved layout can be accessed via <a class="alert-link" ng-href="#/layouts/{{saved}}">this link</a>.
|
|
</alert>
|
|
<alert type="danger" ng-hide="!saveError" close="saveError=''" ng-cloak>
|
|
<P>There was an error saving your layout on the server: {{saveError}}</P>
|
|
<P>To ensure you don't lose any data, it is recommended that you <a class="alert-link" ng-click="downloadJson()">download your layout as JSON</a>.</P>
|
|
</alert>
|
|
<alert type="danger" ng-hide="!loadError" close="loadError=false" ng-cloak>
|
|
The requested layout does not exist.
|
|
</alert>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!--***********************************************
|
|
Footer
|
|
************************************************-->
|
|
<div id="footer" ng-cloak>
|
|
<div class="container">
|
|
<p class="text-muted credit" style="float:left">
|
|
Keyboard Layout Editor v{{version}} (<a href='#' ng-click="showMarkdown('CHANGELOG.md', $event)">changelog</a>)<br/>
|
|
Copyright © 2013-2015 — Ian Prest (<a href='#' ng-click="showMarkdown('CONTRIB.md', $event)">and contributors</a>)<br/>
|
|
All rights reserved. (<a href='#' ng-click="showMarkdown('LICENSE.md', $event)">LICENSE</a>)
|
|
</p>
|
|
<div style="float:right;">
|
|
<a href="#" ng-click="showHelp($event)"><i class="fa fa-question-circle"></i> Help & keyboard shortcuts</a><br/>
|
|
<a href="https://github.com/ijprest/keyboard-layout-editor/issues" target="_blank"><i class="fa fa-bug"></i> Found a bug?</a><br/>
|
|
<a href="https://github.com/ijprest/keyboard-layout-editor" target="_blank"><i class="fa fa-github"></i> Code hosted on GitHub</a><br/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!--***********************************************
|
|
Help Dialog
|
|
************************************************-->
|
|
<script type="text/ng-template" id="helpDialog.html">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" ng-click="cancel()">×</button>
|
|
<h4 class="modal-title">How to use keyboard-layout-editor.com</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<h5>Getting Started:</h5>
|
|
<ul>
|
|
<li>Try loading one of the preset layouts from the dropdown at the top of the page.</li>
|
|
<ul>
|
|
<li>The <em>standard layouts</em> are intended to be used as a starting point for customization.</li>
|
|
<li>The <em>complex samples</em> are intended to give you an idea of the editor's capabilities, and to show off some awesome user-creations!</li>
|
|
</ul>
|
|
<li>Select a key in the editor by clicking on it; then try changing the various properties in the property-editor form.</li>
|
|
<li>You can select multiple keys by holding down CTRL and clicking on them, or extend the current selection by SHIFT-clicking on an item. You can also drag a marquee rectangle around the keys you want to select.</li>
|
|
<li>Try the keyboard shortcuts (described below); they make editing various properties much quicker.</li>
|
|
<li>You can save your layout to the server by clicking the 'Save' button on the toolbar.</li>
|
|
<li>You can save your layout locally by bookmarking the 'Permalink' (at the top of the page) in your bookmarks list.</li>
|
|
</ul>
|
|
|
|
<h5>Global Keyboard Shortcuts:</h5>
|
|
<dl class='dl-horizontal'>
|
|
<dt><kbd>F1</kbd> / <kbd>?</kbd></dt><dd>Show this help dialog</dd>
|
|
<dt><kbd>F7</kbd></dt><dd>Show the Options dialog</dd>
|
|
<dt><kbd>Ctrl–S</kbd></dt><dd>Save your layout (on the server)</dd>
|
|
</dl>
|
|
|
|
<h5>Editor Keyboard Shortcuts (these require that the editor has input focus):</h5>
|
|
<dl class='dl-horizontal' style='float:left;width:50%;'>
|
|
<dt><kbd>↑↓←→</kbd></dt><dd>Move the selected keys</dd>
|
|
<dt><kbd>Shift–↑↓←→</kbd></dt><dd>Resize the selected keys</dd>
|
|
<dt><kbd>Ctrl–↑↓←→</kbd></dt><dd>Move the center of rotation for the selected keys</dd>
|
|
<dt><kbd>PgUp</kbd> / <kbd>PgDn</kbd></dt><dd>Change the angle of rotation for the selected keys</dd>
|
|
<dt><kbd>Ins</kbd></dt><dd>Add a new key</dd>
|
|
<dt><kbd>Del</kbd></dt><dd>Delete the selected keys</dd>
|
|
<dt><kbd>F2</kbd></dt><dd>Edit the text of the selected key</dd>
|
|
</dl>
|
|
<dl class='dl-horizontal' style='float:left;width:50%;'>
|
|
<dt><kbd>Ctrl–A</kbd> / <kbd>Esc</kbd></dt><dd>Select / deselect all keys</dd>
|
|
<dt><kbd>J</kbd> / <kbd>K</kbd></dt><dd>Select the previous / next key in the editor.</dd>
|
|
<dt><kbd>Ctrl–Z</kbd></dt><dd>Undo</dd>
|
|
<dt><kbd>Ctrl–Shift–Z</kbd> or <kbd>Ctrl–Y</kbd></dt><dd>Redo</dd>
|
|
<dt><kbd>Ctrl–X</kbd> or <kbd>Shift–Del</kbd></dt><dd>Cut the selected keys</dd>
|
|
<dt><kbd>Ctrl–C</kbd> or <kbd>Ctrl–Ins</kbd></dt><dd>Copy the selected keys</dd>
|
|
<dt><kbd>Ctrl–V</kbd> or <kbd>Shift–Ins</kbd></dt><dd>Paste keys from the clipboard</dd>
|
|
</dl>
|
|
<p> </p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" ng-click="ok()">OK</button>
|
|
</div>
|
|
</script>
|
|
|
|
<!--***********************************************
|
|
Markdown dialog for displaying README, etc.
|
|
************************************************-->
|
|
<script type="text/ng-template" id="markdownDialog.html">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" ng-click="cancel()">×</button>
|
|
<h4 class="modal-title">{{$parent.markdownTitle}}</h4>
|
|
</div>
|
|
<div class="modal-body" ng-bind-html="$parent.markdownContent"> </div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" ng-click="ok()">OK</button>
|
|
</div>
|
|
</script>
|
|
|
|
<!--***********************************************
|
|
Options Dialog
|
|
************************************************-->
|
|
<script type="text/ng-template" id="optionsDialog.html">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" ng-click="cancel()">×</button>
|
|
<h4 class="modal-title">Options</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<h5>Editor Step Sizes:</h5>
|
|
<div class="form-horizontal">
|
|
<div class="form-group form-group-sm">
|
|
<label for="moveStepEditor" class="col-sm-6 col-md-3 col-lg-2 control-label">Move Step:</label>
|
|
<div class="col-sm-6 col-md-9 col-lg-10">
|
|
<div class="form-inline">
|
|
<div class="form-group form-group-sm">
|
|
<div class="input-group input-group-sm hint--top hint--rounded"
|
|
data-hint="Controls the step size when moving keys around the keyboard layout.">
|
|
<input id="moveStepEditor" class="form-control" type="number" min="0.05" max="2.5" step="0.05" size="6" ng-model="params.moveStep">
|
|
<span class="input-group-addon">units</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<label for="sizeStepEditor" class="col-sm-6 col-md-3 col-lg-2 control-label">Size Step:</label>
|
|
<div class="col-sm-6 col-md-9 col-lg-10">
|
|
<div class="form-inline">
|
|
<div class="form-group form-group-sm">
|
|
<div class="input-group input-group-sm hint--top hint--rounded"
|
|
data-hint="Controls the step size when resizing keys in the keyboard layout.">
|
|
<input id="sizeStepEditor" class="form-control" type="number" min="0.05" max="2.5" step="0.05" size="6" ng-model="params.sizeStep">
|
|
<span class="input-group-addon">units</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<label for="rotateStepEditor" class="col-sm-6 col-md-3 col-lg-2 control-label">Rotate Step:</label>
|
|
<div class="col-sm-6 col-md-9 col-lg-10">
|
|
<div class="form-inline">
|
|
<div class="form-group form-group-sm">
|
|
<div class="input-group input-group-sm hint--top hint--rounded"
|
|
data-hint="Controls the step size when rotating keys in the keyboard layout.">
|
|
<input id="rotateStepEditor" class="form-control" type="number" min="1" max="90" step="1" size="6" ng-model="params.rotateStep">
|
|
<span class="input-group-addon">degrees</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-danger" ng-click="cancel()">Cancel</button>
|
|
<button type="button" class="btn btn-primary" ng-click="ok()">OK</button>
|
|
</div>
|
|
</script>
|
|
|
|
<!--***********************************************
|
|
Angular Templates
|
|
************************************************-->
|
|
|
|
<!-- Color Picker Template -->
|
|
<script type="text/ng-template" id="colorPicker.html">
|
|
<div class="form-group form-group-sm">
|
|
<div class="input-group input-group-sm hint--top hint--rounded" ng-attr-data-hint="{{hintText}}">
|
|
<input id="{{pickerId}}" class="form-control" size="8" type='text'
|
|
ng-model="color" ng-change="onChange()" ng-blur="onBlur()" ng-disabled="isDisabled && isDisabled()"
|
|
colorpicker="hex" colorpicker-close-on-select="true" colorpicker-position="{{pickerPosition || 'bottom'}}">
|
|
<span class="input-group-btn">
|
|
<button class="btn btn-default" ng-style="{'background-color':color}" ng-model="color" ng-change="onChange()" ng-disabled="isDisabled && isDisabled()"
|
|
colorpicker="hex" colorpicker-close-on-select="true" colorpicker-position="{{pickerPosition || 'bottom'}}"> </button>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<!-- Simple Editor Templates -->
|
|
<script type="text/ng-template" id="multiCheck.html">
|
|
<div class="form-group form-group-sm">
|
|
<div class="checkbox hint--top hint--rounded" ng-attr-data-hint="{{hintText}}">
|
|
<label>
|
|
<input id="{{field}}" type="checkbox"
|
|
ng-model="$parent.multi[field]"
|
|
ng-change="$parent.updateMulti(field)"
|
|
ng-blur="$parent.validateMulti(field)"
|
|
ng-disabled="$parent.selectedKeys.length<1">
|
|
<span ng-transclude></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<script type="text/ng-template" id="multiNumbox.html">
|
|
<div class="form-group form-group-sm">
|
|
<input id="{{field}}-editor" class="form-control input-sm" size="{{size}}" type='number' min="{{min}}" max="{{max}}" step="{{step || 1}}"
|
|
ng-model="$parent.multi[field]"
|
|
ng-change="$parent.updateMulti(field)"
|
|
ng-blur="$parent.validateMulti(field)"
|
|
ng-disabled="$parent.selectedKeys.length<1">
|
|
</div>
|
|
</script>
|
|
|
|
<!-- Label Editor Template -->
|
|
<script type="text/ng-template" id="labelEditor.html">
|
|
<div class="form-group form-group-sm">
|
|
<div class="input-group input-group-sm hint--top hint--rounded" ng-attr-data-hint="{{hintText}}"
|
|
ui-on-Drop="$parent.dropSwatch($data,$event,true,labelIndex)" drop-channel="dragColor">
|
|
<input id="labeleditor{{labelIndex}}" class="form-control" size="6" type='text'
|
|
ng-model="$parent.multi.labels[labelIndex]"
|
|
ng-change="$parent.updateMulti('labels',labelIndex)"
|
|
ng-blur="$parent.validateMulti('labels',labelIndex)"
|
|
ng-disabled="$parent.labelDisabled(labelIndex)">
|
|
<span class="input-group-btn">
|
|
<button class="btn btn-default"
|
|
ng-style="{'background-color':$parent.getTextColor($parent.multi.text,labelIndex)}"
|
|
ng-model="$parent.multi.text[labelIndex]"
|
|
ng-change="$parent.updateMulti('text',labelIndex)"
|
|
colorpicker="hex"
|
|
colorpicker-close-on-select="true"
|
|
colorpicker-with-input="true"
|
|
ng-disabled="$parent.labelDisabled(labelIndex)"> </button>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<!--***********************************************
|
|
DOT.js Templates
|
|
************************************************-->
|
|
|
|
<!-- Keycap Template -->
|
|
<script type="text/ng-template" id="keycap_html">
|
|
<div class='{{=key.ghost ? "ghosted keycap" : "keycap"}}'
|
|
{{? key.rotation_angle }}
|
|
style='transform:rotate({{=key.rotation_angle}}deg); transform-origin:{{=parms.origin_x}}px {{=parms.origin_y}}px;'
|
|
{{?}}>
|
|
|
|
<div style="left: {{=parms.capx}}px; top: {{=parms.capy}}px;
|
|
width: {{=parms.capwidth}}px; height: {{=parms.capheight}}px;
|
|
border: solid {{=sizes.strokeWidth}}px black; border-radius: {{=sizes.roundOuter}}px;
|
|
background-color: {{=parms.darkColor}};"
|
|
class="keyborder"></div>
|
|
{{? parms.jShaped }}
|
|
<div style="left: {{=parms.capx2}}px; top: {{=parms.capy2}}px;
|
|
width: {{=parms.capwidth2}}px; height: {{=parms.capheight2}}px;
|
|
border: solid {{=sizes.strokeWidth}}px black; border-radius: {{=sizes.roundOuter}}px;
|
|
background-color: {{=parms.darkColor}};"
|
|
class="keyborder"></div>
|
|
<div style="left: {{=parms.capx + sizes.strokeWidth}}px; top: {{=parms.capy + sizes.strokeWidth}}px;
|
|
width: {{=parms.capwidth - sizes.strokeWidth*2}}px;
|
|
height: {{=parms.capheight - sizes.strokeWidth*2}}px;
|
|
background-color: {{=parms.darkColor}};
|
|
border-radius: {{=sizes.roundOuter}}px;"></div>
|
|
{{?}}
|
|
|
|
{{? !key.ghost }}
|
|
<div style="left: {{=parms.innercapx}}px; top: {{=parms.innercapy}}px;
|
|
width: {{=parms.innercapwidth}}px; height: {{=parms.innercapheight}}px;
|
|
border: solid {{=sizes.strokeWidth}}px rgba(0,0,0,0.1);
|
|
background-color: {{=parms.lightColor}};
|
|
border-radius: {{=sizes.roundInner}}px;"
|
|
class="keytop"></div>
|
|
{{? parms.jShaped && !key.stepped }}
|
|
<div style="left: {{=parms.innercapx2}}px; top: {{=parms.innercapy2}}px;
|
|
width: {{=parms.innercapwidth2}}px; height: {{=parms.innercapheight2}}px;
|
|
border: solid {{=sizes.strokeWidth}}px rgba(0,0,0,0.1); border-radius: {{=sizes.roundInner}}px;
|
|
background-color: {{=parms.lightColor}};
|
|
background-position: {{=Math.min(parms.innercapx-parms.innercapx2,0)}}px {{=Math.min(parms.innercapy-parms.innercapy2,0)}}px;
|
|
background-size: {{=Math.max(parms.innercapwidth,parms.innercapwidth2)}}px {{=Math.max(parms.innercapheight,parms.innercapheight2)}}px;"
|
|
class="keytop"></div>
|
|
<div style="left: {{=parms.innercapx + sizes.strokeWidth}}px; top: {{=parms.innercapy + sizes.strokeWidth}}px;
|
|
width: {{=parms.innercapwidth - sizes.strokeWidth*2}}px; height: {{=parms.innercapheight - sizes.strokeWidth*2}}px;
|
|
border-radius: {{=sizes.roundInner}}px;
|
|
background-color: {{=parms.lightColor}};
|
|
background-position: {{=Math.min(parms.innercapx2-parms.innercapx,0)}}px {{=Math.min(parms.innercapy2-parms.innercapy,0)}}px;
|
|
background-size: {{=Math.max(parms.innercapwidth,parms.innercapwidth2)}}px {{=Math.max(parms.innercapheight,parms.innercapheight2)}}px;"
|
|
class="keytop"></div>
|
|
{{?}}
|
|
|
|
<div style='left: {{=parms.innercapx}}px; top: {{=parms.innercapy}}px; width: {{=parms.innercapwidth}}px; height: {{=parms.innercapheight}}px; padding: {{=sizes.padding}}px;' class='keylabels'>
|
|
{{~key.labels :label:i}}
|
|
{{? label && label != "" && !(key.align&$renderKey.noRenderText[i]) }}
|
|
{{ var sanitizedLabel = ""; try { sanitizedLabel = $sanitize(label.replace(/<([^a-zA-Z\/]|$)/,"<$1")); } catch(e) {console.log(e);} }}
|
|
{{? sanitizedLabel !== "" }}
|
|
{{ var textColor = i < key.text.length ? key.text[i] : key.text[0]; if(!textColor) textColor = key.text[0]; }}
|
|
{{ var textColorLight = lightenColor($color.hex(textColor), 1.2).hex(); }}
|
|
<div class='keylabel keylabel{{=i+1}} centerx-{{=key.centerx}} centery-{{=key.centery}} centerf-{{=key.centerf}} textsize{{= i>0 ? key.fontheight2 : key.fontheight}}' style='color:{{= i===4||i===5 ? textColor : textColorLight}}; width:{{=parms.textcapwidth}}px; height:{{=parms.textcapheight}}px;'>
|
|
<div style='width:{{=parms.textcapwidth}}px; max-width:{{=parms.textcapwidth}}px; height:{{=parms.textcapheight}}px;'>{{=sanitizedLabel}}</div>
|
|
</div>
|
|
{{??}}
|
|
<div class="hint--top hint--rounded" data-hint="Error: Invalid HTML in label field."><i class="fa fa-times-circle"></i></div>
|
|
{{?}}
|
|
{{?}}
|
|
{{~}}
|
|
</div>
|
|
{{?}} <!--!key.ghost-->
|
|
|
|
</div>
|
|
</script>
|
|
|
|
<!-- Keycap Template for SVG-->
|
|
<script type="text/ng-template" id="keycap_svg">
|
|
<g class='{{=key.ghost ? "ghosted keycap" : "keycap"}}'
|
|
{{? key.rotation_angle }}
|
|
transform="rotate({{=key.rotation_angle}} {{=parms.origin_x}} {{=parms.origin_y}})"
|
|
{{?}}>
|
|
|
|
<!-- Outer Border -->
|
|
<rect x="{{=parms.capx+sizes.strokeWidth}}" y="{{=parms.capy+sizes.strokeWidth}}"
|
|
width="{{=parms.capwidth-sizes.strokeWidth*2}}" height="{{=parms.capheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.darkColor}}" class="outer border"/>
|
|
{{? parms.jShaped }}
|
|
<rect x="{{=parms.capx2+sizes.strokeWidth}}" y="{{=parms.capy2+sizes.strokeWidth}}"
|
|
width="{{=parms.capwidth2-sizes.strokeWidth*2}}" height="{{=parms.capheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.darkColor}}" class="outer border"/>
|
|
{{?}}
|
|
<!-- Outer Fill -->
|
|
<rect x="{{=parms.capx+sizes.strokeWidth}}" y="{{=parms.capy+sizes.strokeWidth}}"
|
|
width="{{=parms.capwidth-sizes.strokeWidth*2}}" height="{{=parms.capheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.darkColor}}"/>
|
|
{{? parms.jShaped }}
|
|
<rect x="{{=parms.capx2+sizes.strokeWidth}}" y="{{=parms.capy2+sizes.strokeWidth}}"
|
|
width="{{=parms.capwidth2-sizes.strokeWidth*2}}" height="{{=parms.capheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.darkColor}}"/>
|
|
{{?}}
|
|
|
|
{{? !key.ghost }}
|
|
<!-- Inner Border -->
|
|
<rect x="{{=parms.innercapx+sizes.strokeWidth}}" y="{{=parms.innercapy+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth-sizes.strokeWidth*2}}" height="{{=parms.innercapheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}" class="inner border"/>
|
|
{{? parms.jShaped && !key.stepped }}
|
|
<rect x="{{=parms.innercapx2+sizes.strokeWidth}}" y="{{=parms.innercapy2+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth2-sizes.strokeWidth*2}}" height="{{=parms.innercapheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}" class="inner border"/>
|
|
{{?}}
|
|
<!-- Inner Fill -->
|
|
<rect x="{{=parms.innercapx+sizes.strokeWidth}}" y="{{=parms.innercapy+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth-sizes.strokeWidth*2}}" height="{{=parms.innercapheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}"/>
|
|
{{? parms.jShaped && !key.stepped }}
|
|
<rect x="{{=parms.innercapx2+sizes.strokeWidth}}" y="{{=parms.innercapy2+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth2-sizes.strokeWidth*2}}" height="{{=parms.innercapheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}"/>
|
|
{{?}}
|
|
{{? sizes.profile !== "" }}
|
|
{{var theProfile = sizes.profile; if(/\b(SPACE)\b/.exec(key.profile)) theProfile = "SPACE";}}
|
|
{{? parms.jShaped && !key.stepped }}
|
|
{{
|
|
/*much harder to do j-shaped keys in SVG*/
|
|
theProfile = '_fill'+parms.index;
|
|
var rect = {
|
|
left: Math.min(parms.innercapx, parms.innercapx2),
|
|
top: Math.min(parms.innercapy, parms.innercapy2),
|
|
right: Math.min(parms.innercapx+parms.innercapwidth, parms.innercapx2+parms.innercapwidth2),
|
|
bottom: Math.min(parms.innercapy+parms.innercapheight, parms.innercapy2+parms.innercapheight2)
|
|
};
|
|
}}
|
|
{{? sizes.profile==="SA" || sizes.profile==="DSA" }}
|
|
<radialGradient id="{{=theProfile}}" xlink:href="#{{=sizes.profile}}" gradientUnits="userSpaceOnUse"
|
|
cx="{{=(rect.left+rect.right)/2}}" cy="{{=(rect.top+rect.bottom)/2}}"
|
|
r="{{=Math.min(rect.right-rect.left, rect.bottom-rect.top)}}"/>
|
|
{{??}}
|
|
<linearGradient id="{{=theProfile}}" xlink:href="#{{=sizes.profile}}" gradientUnits="userSpaceOnUse"
|
|
x1="{{=rect.left}}" y1="{{=rect.top}}" x2="{{=rect.right}}" y2="{{=rect.top}}"/>
|
|
{{?}}
|
|
<rect x="{{=parms.innercapx2+sizes.strokeWidth}}" y="{{=parms.innercapy2+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth2-sizes.strokeWidth*2}}" height="{{=parms.innercapheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}"/>
|
|
<rect x="{{=parms.innercapx2+sizes.strokeWidth}}" y="{{=parms.innercapy2+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth2-sizes.strokeWidth*2}}" height="{{=parms.innercapheight2-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="url(#{{=theProfile}})"/>
|
|
<rect x="{{=parms.innercapx+sizes.strokeWidth}}" y="{{=parms.innercapy+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth-sizes.strokeWidth*2}}" height="{{=parms.innercapheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="{{=parms.lightColor}}"/>
|
|
{{?}}
|
|
<rect x="{{=parms.innercapx+sizes.strokeWidth}}" y="{{=parms.innercapy+sizes.strokeWidth}}"
|
|
width="{{=parms.innercapwidth-sizes.strokeWidth*2}}" height="{{=parms.innercapheight-sizes.strokeWidth*2}}"
|
|
rx="{{=sizes.roundOuter}}" fill="url(#{{=theProfile}})"/>
|
|
{{?}}
|
|
{{?}}
|
|
</g>
|
|
</script>
|
|
|
|
<script type="text/ng-template" id="keyboard_svg">
|
|
<svg width='{{=parms.width+parms.margin*2+parms.padding*2}}{{=parms.units}}'
|
|
height='{{=parms.height+parms.margin*2+parms.padding*2}}{{=parms.units}}'
|
|
viewBox='0 0 {{=parms.width+parms.margin*2+parms.padding*2}} {{=parms.height+parms.margin*2+parms.padding*2}}'
|
|
xmlns='http://www.w3.org/2000/svg'
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
|
|
<style type='text/css'>
|
|
.keycap .border { stroke: black; stroke-width: {{=parms.strokeWidth*2}}; }
|
|
.keycap .inner.border { stroke: rgba(0,0,0,.1); }
|
|
</style>
|
|
<defs>
|
|
<linearGradient id="DCS">
|
|
<stop offset="0%" stop-color="black" stop-opacity="0"/>
|
|
<stop offset="40%" stop-color="black" stop-opacity="0.1"/>
|
|
<stop offset="60%" stop-color="black" stop-opacity="0.1"/>
|
|
<stop offset="100%" stop-color="black" stop-opacity="0"/>
|
|
</linearGradient>
|
|
<linearGradient id="SPACE" x1="0%" x2="0%" y1="0%" y2="100%">
|
|
<stop offset="0%" stop-color="black" stop-opacity="0.1"/>
|
|
<stop offset="20%" stop-color="black" stop-opacity="0.0"/>
|
|
<stop offset="40%" stop-color="black" stop-opacity="0.0"/>
|
|
<stop offset="100%" stop-color="black" stop-opacity="0.1"/>
|
|
</linearGradient>
|
|
<radialGradient id="DSA">
|
|
<stop offset="0%" stop-color="black" stop-opacity="0.1"/>
|
|
<stop offset="10%" stop-color="black" stop-opacity="0.1"/>
|
|
<stop offset="100%" stop-color="black" stop-opacity="0"/>
|
|
</radialGradient>
|
|
<radialGradient id="SA" xlink:href="#DSA" />
|
|
</defs>
|
|
|
|
<g transform='translate({{=parms.margin}},{{=parms.margin}})'>
|
|
<rect width="{{=parms.width+parms.padding*2}}" height="{{=parms.height+parms.padding*2}}"
|
|
stroke="#ddd" stroke-width="1" fill="{{=parms.backcolor}}" rx="6"/>
|
|
<g transform='translate({{=parms.padding}},{{=parms.padding}})'>
|
|
{{=parms.keys}}
|
|
</g>
|
|
</g>
|
|
</svg>
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|