mirror of
https://github.com/ijprest/keyboard-layout-editor.git
synced 2026-04-10 02:00:46 -07:00
Implemented as a POST upload to AWS/S3. -- Each layout is a separate file; identified by its MD5 hash -- No real security to protect against malicious users "erasing" layouts, but S3 offers versioning. Also: -- Added save button on the toolbar. -- Added load/save alert boxes. -- Added Ctrl+S hotkey to save.
305 lines
No EOL
16 KiB
HTML
305 lines
No EOL
16 KiB
HTML
<!--
|
|
KEYBOARD LAYOUT EDITOR
|
|
Copyright (C) 2013 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="css/bootstrap.min.css" media="screen">
|
|
<link rel="stylesheet" type="text/css" href="css/font-awesome.min.css">
|
|
<link rel="stylesheet" type="text/css" href="css/hint.min.css">
|
|
<link rel="stylesheet" type="text/css" href="kb.css">
|
|
<script type="text/javascript" src="js/angular.min.js"></script>
|
|
<script type="text/javascript" src="js/angular-sanitize.min.js"></script>
|
|
<script type="text/javascript" src="js/ui-utils.min.js"></script>
|
|
<script type="text/javascript" src="js/jquery-2.0.2.min.js"></script>
|
|
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
|
<script type="text/javascript" src="js/urlon.js"></script>
|
|
<script type="text/javascript" src="js/md5.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()',
|
|
'ctrl-90' : 'undo()',
|
|
'ctrl-shift-90' : 'redo()',
|
|
'ctrl-89' : 'redo()',
|
|
'ctrl-83' : 'save($event)' }">
|
|
<div id="wrap">
|
|
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
|
|
<div class="navbar-header">
|
|
<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>
|
|
<a class="navbar-brand" href="#"><i class="icon-keyboard"></i> keyboard-layout-editor.com</a>
|
|
</div>
|
|
|
|
<ul class="nav navbar-nav">
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="icon-keyboard"></i> Preset <b class="caret"></b></a>
|
|
<ul class="dropdown-menu">
|
|
<li ng-repeat="(k,v) in layouts"><a ng-click="loadPreset(v)" href="#">{{k}}</a></li>
|
|
</ul>
|
|
</li>
|
|
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="icon-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>
|
|
|
|
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
|
<ul class="nav navbar-nav navbar-right">
|
|
<li><a ng-href="{{getPermalink()}}" target="_blank" ng-click="dirty = false"><i class="icon-link"></i> Permalink</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="body">
|
|
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-primary" ng-click="addKey()"><i class="glyphicon glyphicon-plus-sign"></i> Add Key</button>
|
|
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
|
|
<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>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-danger" ng-class="{disabled:selectedKeys.length<1}" ng-click="deleteKeys()"><i class="glyphicon glyphicon-remove-sign"></i> Delete Keys</button>
|
|
</div>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canUndo()}" ng-click="undo()"><i class="icon-undo"></i> Undo</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canRedo()}" ng-click="redo()"><i class="icon-repeat"></i> Redo</button>
|
|
</div>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canCopy()}" ng-click="cut()"><i class="icon-cut"></i> Cut</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canCopy()}" ng-click="copy()"><i class="icon-copy"></i> Copy</button>
|
|
<button type="button" class="btn btn-default" ng-class="{disabled:!canPaste()}" ng-click="paste()"><i class="icon-paste"></i> Paste</button>
|
|
</div>
|
|
<div class="btn-group pull-right">
|
|
<button type="button" class="btn btn-success" ng-class="{disabled:!canSave()}" ng-click="save()"><i class="icon-save"></i> Save</button>
|
|
</div>
|
|
<div id="keyboard"
|
|
tabindex="0"
|
|
ng-style="{height: kbHeight + 'px'}"
|
|
ui-keydown="{ left:'moveKeys(-.25,0,$event)',
|
|
right:'moveKeys(.25,0,$event)',
|
|
up:'moveKeys(0,-.25,$event)',
|
|
down:'moveKeys(0,.25,$event)',
|
|
'shift-left':'sizeKeys(-.25,0,$event)',
|
|
'shift-right':'sizeKeys(.25,0,$event)',
|
|
'shift-up':'sizeKeys(0,-.25,$event)',
|
|
'shift-down':'sizeKeys(0,.25,$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()',
|
|
'ctrl-67 ctrl-45': 'copy($event)',
|
|
'ctrl-88 shift-46': 'cut($event)',
|
|
'ctrl-86 shift-45': 'paste($event)' }"
|
|
ng-mousedown="selectClick($event)">
|
|
|
|
<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}"
|
|
ng-bind-html="key.html">
|
|
</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 style='clear:both'></div>
|
|
{{calcKbHeight()}}
|
|
</div>
|
|
|
|
<ul class="nav nav-tabs">
|
|
<li ng-class="{active:selTab==0}"><a ng-click="selTab=0" data-toggle="tab"><i class="icon-edit"></i> Properties</a></li>
|
|
<li ng-class="{active:selTab==1}"><a ng-click="selTab=1" data-toggle="tab"><i class="icon-code"></i> Raw data</a></li>
|
|
</ul>
|
|
<div class='tab-content' ui-keydown="{esc:'focusKb()'}">
|
|
<div id="properties" ng-class="{hidden:selTab!=0}" class="col-md-12 row">
|
|
|
|
<form class="form-horizontal col-md-4 col-lg-4">
|
|
<div class="control-group">
|
|
<label class="control-label" for="labeleditor">Top Label:</label>
|
|
<div class="controls">
|
|
<input id="labeleditor" size="8" type='text' ng-model="multi.label" ng-change="updateMulti('label')" ng-blur="validateMulti('label')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="labeleditor2">Bottom Label:</label>
|
|
<div class="controls">
|
|
<input id="labeleditor2" size="8" type='text' ng-model="multi.label2" ng-change="updateMulti('label2')" ng-blur="validateMulti('label2')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="widtheditor">Width:</label>
|
|
<div class="controls">
|
|
<input id="widtheditor" size="6" type='number' min='0.5' max='12' step='.25' ng-model="multi.width" ng-change="updateMulti('width')" ng-blur="validateMulti('width')" ng-disabled="selectedKeys.length<1">
|
|
/
|
|
<input size="6" type='number' min='0.5' max='12' step='.25' ng-model="multi.width2" ng-change="updateMulti('width2')" ng-blur="validateMulti('width2')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="heighteditor">Height:</label>
|
|
<div class="controls">
|
|
<input id="heighteditor" size="6" type='number' min='0.5' max='12' step='.25' ng-model="multi.height" ng-change="updateMulti('height')" ng-blur="validateMulti('height')" ng-disabled="selectedKeys.length<1">
|
|
/
|
|
<input size="6" type='number' min='0.5' max='12' step='.25' ng-model="multi.height2" ng-change="updateMulti('height2')" ng-blur="validateMulti('height2')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="xeditor">X:</label>
|
|
<div class="controls">
|
|
<input id="xeditor" size="6" type='number' min='0' max='36' step='.25' ng-model="multi.x" ng-change="updateMulti('x')" ng-blur="validateMulti('x')" ng-disabled="selectedKeys.length<1">
|
|
+
|
|
<input size="6" type='number' min='-6' max='6' step='.25' ng-model="multi.x2" ng-change="updateMulti('x2')" ng-blur="validateMulti('x2')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="yeditor">Y:</label>
|
|
<div class="controls">
|
|
<input id="yeditor" size="6" type='number' min='0' max='36' step='.25' ng-model="multi.y" ng-change="updateMulti('y')" ng-blur="validateMulti('y')" ng-disabled="selectedKeys.length<1">
|
|
+
|
|
<input size="6" type='number' min='-6' max='6' step='.25' ng-model="multi.y2" ng-change="updateMulti('y2')" ng-blur="validateMulti('y2')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="coloreditor">Key Color:</label>
|
|
<div class="controls">
|
|
<input id="coloreditor" size="8" type='text' ng-model="multi.color" ng-change="updateMulti('color')" ng-blur="validateMulti('color')" ng-disabled="selectedKeys.length<1">
|
|
<input type='color' class="colorpicker" ng-model="multi.color" ng-change="updateMulti('color')" ng-blur="validateMulti('color')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="textcoloreditor">Label Color:</label>
|
|
<div class="controls">
|
|
<input id="textcoloreditor" size="8" type='text' ng-model="multi.text" ng-change="updateMulti('text')" ng-blur="validateMulti('text')" ng-disabled="selectedKeys.length<1">
|
|
<input type='color' class="colorpicker" ng-model="multi.text" ng-change="updateMulti('text')" ng-blur="validateMulti('text')" ng-disabled="selectedKeys.length<1">
|
|
</div>
|
|
</div>
|
|
<div class="control-group">
|
|
<label class="control-label" for="ghosteditor">Ghosted:</label>
|
|
<div class="controls">
|
|
<input id="ghosteditor" type="checkbox" ng-model="multi.ghost" ng-change="updateMulti('ghost')" ng-blur="validateMulti('ghost')" ng-disabled="selectedKeys.length<1">
|
|
</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"
|
|
data-hint="{{color.name}}"></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div ng-class="{hidden:selTab!=1}" class="col-md-12">
|
|
<textarea id="rawdata" spellcheck="false" ng-model="serialized" ng-change="updateFromSerialized()" ng-class="{error:deserializeException!==''}"></textarea>
|
|
<div class="alert alert-danger" style='margin-top:1em;margin-bottom:0px' ng-class="{hidden:!deserializeException}">{{deserializeException}}</div>
|
|
</div>
|
|
</div>
|
|
<P></P>
|
|
<div ng-class="{hidden:!saved}" class="alert alert-success">
|
|
<a class="close" href="#" aria-hidden="true" ng-click="saved=false">×</a>
|
|
Saved! Your saved layout can be accessed via <a class="alert-link" ng-href="#/layouts/{{saved}}">this link</a>.
|
|
</div>
|
|
<div ng-class="{hidden:!saveError}" class="alert alert-danger">
|
|
<a class="close" href="#" aria-hidden="true" ng-click="saveError=''">×</a>
|
|
<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-href="{{getPermalink()}}" target="_blank" ng-click="dirty = false">bookmark this permalink</a>.</P>
|
|
</div>
|
|
<div ng-class="{hidden:!loadError}" class="alert alert-danger">
|
|
<a class="close" href="#" aria-hidden="true" ng-click="loadError=false">×</a>
|
|
The requested layout does not exist.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="footer">
|
|
<div class="container">
|
|
<p class="text-muted credit" style="float:left">
|
|
Keyboard Layout Editor v{{version}}<br/>
|
|
Copyright © 2013 — Ian Prest<br/>
|
|
All rights reserved.
|
|
</p>
|
|
<div style="float:right; text-alignment:right;">
|
|
<a href="#" ng-click="showHelp()"><i class="icon-keyboard"></i> Keyboard shortcuts available</a><br/>
|
|
<br/>
|
|
<a href="https://github.com/ijprest/keyboard-layout-editor" target="_blank"><i class="icon-github"></i> Code hosted on GitHub</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal -->
|
|
<div class="modal fade" id="helpDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog" style='width:70%;left:15%;'>
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</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; it will give you a good idea of the editor's capabilities.</li>
|
|
<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>Keyboard Shortcuts</h5>
|
|
<table class='shortcuts col-md-6' style='margin-bottom:5px;'>
|
|
<tr><td><span class='shortcut'>?</span></td><td>Show this help dialog</td></tr>
|
|
<tr><td><span class='shortcut'>↑↓←→</span></td><td>Move the selected keys</td></tr>
|
|
<tr><td><span class='shortcut'>Shift–↑↓←→</span></td><td>Resize the selected keys</td></tr>
|
|
<tr><td><span class='shortcut'>Ins</span></td><td>Add a new key</td></tr>
|
|
<tr><td><span class='shortcut'>Del</span></td><td>Delete the selected keys</td></tr>
|
|
<tr><td><span class='shortcut'>F2</span></td><td>Edit the text of the selected key</td></tr>
|
|
<tr><td><span class='shortcut'>J</span> / <span class='shortcut'>K</span></td><td>Select the previous / next key in the editor.</td></tr>
|
|
</table>
|
|
<table class='shortcuts col-md-6' style='margin-bottom:5px;'>
|
|
<tr><td><span class='shortcut'>Ctrl–S</span></td><td>Save your layout (on the server)</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–A</span> / <span class='shortcut'>Esc</span></td><td>Select / deselect all keys</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–Z</span></td><td>Undo</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–Shift–Z</span> or <span class='shortcut'>Ctrl–Y</span></td><td>Redo</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–X</span> or <span class='shortcut'>Shift–Del</span></td><td>Cut the selected keys</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–C</span> or <span class='shortcut'>Ctrl–Ins</span></td><td>Copy the selected keys</td></tr>
|
|
<tr><td><span class='shortcut'>Ctrl–V</span> or <span class='shortcut'>Shift–Ins</span></td><td>Paste keys from the clipboard</td></tr>
|
|
</table>
|
|
<P style='clear:both'>Note that most of these keys require that the keyboard editor has input focus.</P>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |