Major refactoring of the keycap rendering to HTML

-- Generating HTML with a doT.js template function; hopefully easier to
maintain.
-- More of the parameters refactored into the JS code, rather than
relying on being in the CSS; benefit => those parameters are available
when I do SVG rendering.
-- Also, now using Stylus to compile & minify CSS, and auto-inline small
images (Sublime project describes how to compile).
pull/92/head
Ian Prest 9 years ago
parent ec21e1df5c
commit 824707f776

1
.gitignore vendored

@ -5,4 +5,5 @@ fonts/EngraversGothic-Regular-webfont.*
fonts/kbd-custom.*
jsonl.min.js
jsonl.js
*.sublime-workspace
*~

@ -27,5 +27,6 @@ The following third-party software packages were used in the creation of keyboar
* [URLON](https://github.com/vjeux/URLON) (URL Object Notation)
* [Jison](http://zaach.github.io/jison/) (JavaScript parser generator)
* [Hint.css](http://kushagragour.in/lab/hint/) (CSS-only tooltips)
* [doT.js](http://olado.github.io/doT/) (fast micro-templating)
* [Font Awesome](http://fortawesome.github.io/Font-Awesome/)
* [C64 TrueType Font](http://style64.org/c64-truetype) font (by [Style64.org](https://www.style64.org))

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
{"version":3,"sources":["../kb.css"],"names":[],"mappings":"AAEE,WACE,YAAa,6BACb,IAAkC,kDAClC,IAAsE,uTAItE,YAAa,SACb,WAAY,SARd,WACE,YAAa,aACb,IAAkC,qCAClC,IAAsE,mPAItE,YAAa,SACb,WAAY,SARd,WACE,YAAa,SACb,IAAkC,gCAClC,IAAsE,2NAItE,YAAa,SACb,WAAY,SAShB,KAAM,KACJ,OAAQ,KACR,YAAuB,0CACvB,AACA,sBAAuB,KACvB,oBAAqB,KACrB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KACb,OAAQ,QAEV,MAAQ,OAAQ,KAChB,KAAM,YAAa,UAAW,eAAiB,OAAQ,QAGvD,MACE,WAAY,KACZ,OAAQ,gBACR,OAAQ,KACR,OAAQ,aAAc,AACtB,QAAS,SAAU,CAIrB,QACE,OAAQ,KACR,iBAAkB,QAIpB,UACE,QAAS,IACT,SAAU,SACV,OAAQ,eACR,cAAe,IACf,iBAAkB,KAClB,WAAY,KACZ,WAAY,YACZ,WAAY,KACZ,cAAe,KAEjB,cACE,SAAU,SACV,aAAc,KACd,WAAY,WACZ,gBAAiB,YAEnB,4BAA8B,aAAc,mBAAkB,aAAc,MAC5E,+BAAiC,aAAc,gBAAgB,aAAc,MAC7E,mBAAqB,QAAS,GAG9B,cAAgB,QAAS,WAAY,SAAU,kBAC/C,eAAgB,eAAgB,eAAgB,eAAiB,WAAY,MAC7E,eAAgB,eAAiB,eAAgB,OACjD,eAAgB,eAAiB,eAAgB,OACjD,WAAY,WAAa,IAAK,KAAM,WAAY,KAAM,UAAW,gBAAiB,YAAa,OAAQ,SAAU,OACjH,4BAA6B,4BAA6B,4BAA6B,4BAA8B,WAAY,OACjI,4BAA6B,4BAA8B,eAAgB,OAGzE,oBACE,UAAgB,IAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAFf,oBACE,UAAgB,KAChB,YAAa,IAGjB,WAAa,YAAwB,+BACrC,aAAe,QAAS,OACxB,oBACE,SAAU,SACV,QAAS,MACT,SAAU,OACV,YAAa,OACb,QAAS,mUAIX,eAAgB,gBACd,YAAa,6BAA8B,CAG7C,gBAAiB,gBAAiB,eAAgB,eAAiB,WAAY,KAAM,UAAW,eAChG,aAAc,aACZ,WAAgG,0GAChG,kBAAmB,UAErB,aAAc,YACZ,WAA0F,iGAC1F,kBAAmB,UAGrB,mBAAoB,mBAAoB,mBAAoB,kBAC1D,WAAiG,2GACjG,kBAAmB,UAErB,kBAAmB,oBAAqB,mBACtC,WAAgE,mEAChE,kBAAmB,UAErB,2BACE,iBAA+B,0IAC/B,kBAAmB,UACnB,oBAAqB,WAEvB,+BAAgC,8BAAgC,iBAAkB,KAElF,aACE,YAAa,aACb,UAAW,eACX,OAAQ,UACR,eAAgB,EAChB,QAAS,EACT,OAAQ,EAIV,UAAY,gBAAiB,KAC7B,QACE,QAAS,aACT,SAAU,SACV,MAAO,KACP,OAAQ,KACR,OAAQ,eACR,aAAc,KACd,cAAe,KACf,QAAS,EAEX,2BAA6B,iBAAiC,mBAC9D,4BAA8B,YAAa,OAE3C,mBAAqB,QAAS,KAC9B,kCAAoC,QAAS,MAAO,QAAS,IAAK,MAAO,IAAK,OAAQ,IAAK,OAAQ,eAAiB,WAAY,KAAO,QAAS,IAAM,SAAU,SAAU,KAAM,IAAK,IAAK,KAC1L,kCAAoC,QAAS,MAAO,QAAS,IAAK,MAAO,IAAK,OAAQ,IAAK,OAAQ,eAAiB,WAAY,KAAO,QAAS,IAAM,SAAU,SAAU,KAAM,IAAK,IAAK,KAG1L,QAAU,QAAS,KACnB,OAAS,OAAQ,kBACjB,oBAAsB,SAAU,SAAU,OAAQ,gBAClD,oBACE,QAAS,KACT,SAAU,SACV,OAAQ,EACR,QAAS,EACT,UAAW,KACX,YAAa,KACb,MAAO,KACP,OAAQ,KACR,MAAO,KACP,YAAyB,8CAG3B,SAAU,eAAgB,aAAe,YAAuB,6CAChE,SAAW,MAAO,KAClB,eAAiB,YAAa,IAE9B,aACI,YAAa,eACb,aAAc,eACd,cAAe,eACf,YAAa,KACb,eAAgB,KAChB,YAAa,EAEjB,gBAAkB,aAAc,KAGhC,qBAAuB,MAAO,MAC9B,YAAa,kBAAoB,YAAa,SAC9C,aAAc,YAAa,mBAAoB,kBAAoB,mBAAoB,SAAW,gBAAiB,SAAW,WAAY,SAG1I,wBAA0B,MAAO,KACjC,yBAA2B,MAAO,KAGlC,8BAAgC,OAAQ,QACxC,8BAAgC,OAAQ,KACxC,8BAAgC,OAAQ,KAAM,WAAY,EAC1D,4BACE,eAAgB,KAChB,OAA0B,+BAC1B,WAAY,gBAGd,WAAa,OAAQ,2BAA2B,WAAY,WAGhD,aACV,KAAM,KAAO,SAAU,OAAQ,OAAQ,KAAM,OAAQ,aAAc,QAAS,aAC5E,gBAAiB,2BAA4B,cAAe,cAAe,QAAS,YAAa,gBAAkB,QAAS,KAAM,OAAQ,aAAc,QAAS,aACjK,SAAW,OAAQ,aAAc,QAAS,aAC1C,EAAI,MAAO,KAAO,gBAAiB,KACnC,UACE,OAAQ,KACR,iBAAkB,mBAClB,UAA0B,eAC1B,SAAU,oBACV,KAAM,EACN,IAAK,EACL,aAAc,EAAK,YAAa,GAKpC,cAAgB,aAAc,EAG9B,8BAA+B,6DAA+D,YAAa,MAC3G,0CAA4C,YAAa,EAAG,aAAc,EAC1E,YAAc,cAAe,IAC7B,uBAAwB,gCAAkC,OAAQ,KAAM,QAAS,IACjF,0CAA4C,OAAQ,KAAM,QAAS,IAAK,UAAW,KACnF,qCAAuC,OAAQ,KAAM,QAAS,IAAK,UAAW,KAC9E,0CAA4C,YAAa,IAAK,WAAY,KAE1E,aAAe,SAAU,SAAU,IAAK,KAAM,KAAM,MAAO,QAAS,EACpE,YAAc,QAAS,aAAc,UAAW,IAAK,UAAW,KAAM,YAAa","file":"kb.css"}

8
js/doT.min.js vendored

@ -0,0 +1,8 @@
/* Laura Doktorova https://github.com/olado/doT */
(function(){function p(b,a,d){return("string"===typeof a?a:a.toString()).replace(b.define||h,function(a,c,e,g){0===c.indexOf("def.")&&(c=c.substring(4));c in d||(":"===e?(b.defineParams&&g.replace(b.defineParams,function(a,b,l){d[c]={arg:b,text:l}}),c in d||(d[c]=g)):(new Function("def","def['"+c+"']="+g))(d));return""}).replace(b.use||h,function(a,c){b.useParams&&(c=c.replace(b.useParams,function(a,b,c,l){if(d[c]&&d[c].arg&&l)return a=(c+":"+l).replace(/'|\\/g,"_"),d.__exp=d.__exp||{},d.__exp[a]=
d[c].text.replace(new RegExp("(^|[^\\w$])"+d[c].arg+"([^\\w$])","g"),"$1"+l+"$2"),b+"def.__exp['"+a+"']"}));var e=(new Function("def","return "+c))(d);return e?p(b,e,d):e})}function k(b){return b.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var f={version:"1.0.3",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0},m;f.encodeHTMLSource=function(b){var a={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"},d=b?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(b){return b?
b.toString().replace(d,function(b){return a[b]||b}):""}};m=function(){return this||(0,eval)("this")}();"undefined"!==typeof module&&module.exports?module.exports=f:"function"===typeof define&&define.amd?define(function(){return f}):m.doT=f;var r={start:"'+(",end:")+'",startencode:"'+encodeHTML("},s={start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("},h=/$^/;f.template=function(b,a,d){a=a||f.templateSettings;var n=a.append?r:s,c,e=0,g;b=a.use||a.define?p(a,b,d||{}):b;b=("var out='"+(a.strip?
b.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):b).replace(/'|\\/g,"\\$&").replace(a.interpolate||h,function(b,a){return n.start+k(a)+n.end}).replace(a.encode||h,function(b,a){c=!0;return n.startencode+k(a)+n.end}).replace(a.conditional||h,function(b,a,c){return a?c?"';}else if("+k(c)+"){out+='":"';}else{out+='":c?"';if("+k(c)+"){out+='":"';}out+='"}).replace(a.iterate||h,function(b,a,c,d){if(!a)return"';} } out+='";e+=1;g=d||"i"+e;a=k(a);return"';var arr"+
e+"="+a+";if(arr"+e+"){var "+c+","+g+"=-1,l"+e+"=arr"+e+".length-1;while("+g+"<l"+e+"){"+c+"=arr"+e+"["+g+"+=1];out+='"}).replace(a.evaluate||h,function(a,b){return"';"+k(b)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|\}|^|\{)out\+='';/g,"$1").replace(/\+''/g,"");c&&(a.selfcontained||!m||m._encodeHTML||(m._encodeHTML=f.encodeHTMLSource(a.doNotSkipEncoded)),b="var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("+f.encodeHTMLSource.toString()+
"("+(a.doNotSkipEncoded||"")+"));"+b);try{return new Function(a.varname,b)}catch(q){throw"undefined"!==typeof console&&console.log("Could not create a template function: "+b),q;}};f.compile=function(b,a){return f.template(b,null,a)}})();

357
kb.css

@ -1,44 +1,34 @@
@font-face {
font-family: 'engravers_gothic_fsregular';
src: url('fonts/EngraversGothic-Regular-webfont.eot');
src: url('fonts/EngraversGothic-Regular-webfont.eot?#iefix') format('embedded-opentype'),
url('fonts/EngraversGothic-Regular-webfont.woff') format('woff'),
url('fonts/EngraversGothic-Regular-webfont.ttf') format('truetype'),
url('fonts/EngraversGothic-Regular-webfont.svg#engravers_gothic_fsregular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "C64 Pro Mono";
src: url('fonts/C64_Pro_Mono-STYLE.eot');
src: url('fonts/C64_Pro_Mono-STYLE.eot?#iefix') format('embedded-opentype'),
url('fonts/C64_Pro_Mono-STYLE.woff') format('woff'),
url('fonts/C64_Pro_Mono-STYLE.ttf') format('truetype'),
url('fonts/C64_Pro_Mono-STYLE.svg#C64ProMono') format('svg');
}
@font-face {
font-family: "C64 Pro";
src: url('fonts/C64_Pro-STYLE.eot');
src: url('fonts/C64_Pro-STYLE.eot?#iefix') format('embedded-opentype'),
url('fonts/C64_Pro-STYLE.woff') format('woff'),
url('fonts/C64_Pro-STYLE.ttf') format('truetype'),
url('fonts/C64_Pro-STYLE.svg#C64Pro') format('svg');
/* Helper function to set up our fonts */
webfont(family, file, weight = 'normal', style='normal') {
@font-face {
font-family: family;
src: url('/fonts/' + file + ".eot");
src: url('/fonts/' + file + ".eot?#iefix") format('embedded-opentype'),
url('/fonts/' + file + ".woff") format('woff'),
url('/fonts/' + file + ".ttf") format('truetype'),
url('/fonts/' + file + ".svg#" + family) format('svg');
font-weight: weight;
font-style: style;
}
}
/* Set up all the web-fonts we host */
webfont('engravers_gothic_fsregular', 'EngraversGothic-Regular-webfont');
webfont('C64ProMono', 'C64_Pro_Mono-STYLE');
webfont('C64Pro', 'C64_Pro-STYLE');
/* Basic style */
html, body {
height: 100%;
font-family: "Segoe UI", "Arial", "Helvetica", sans-serif;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.body {
margin: 10px;
}
height: 100%;
font-family: "Segoe UI", "Arial", "Helvetica", sans-serif;
/* Prevent highlighting/selecting text */
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.body { margin: 10px; }
.nav, .pagination, .carousel, .panel-title a { cursor: pointer; }
/* Wrapper for page content to push down footer */
@ -46,10 +36,8 @@ html, body {
min-height: 100%;
height: auto !important;
height: 100%;
/* Negative indent footer by its height */
margin: 0 auto -70px;
/* Pad bottom by footer height */
padding: 0 0 60px;
margin: 0 auto -70px; /* Negative indent footer by its height */
padding: 0 0 60px; /* Pad bottom by footer height */
}
/* Set the fixed height of the footer here */
@ -59,189 +47,125 @@ html, body {
}
/* The keyboard background */
#keyboard {
padding: 5px;
position:relative;
border: solid 1px #ddd;
border-radius: 6px;
background-color: #eee;
min-height: 64px;
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
margin-top: 10px;
margin-bottom: 10px;
}
#keyboard {
padding: 9px;
position: relative;
border: solid 1px #ddd;
border-radius: 6px;
background-color: #eee;
min-height: 56px;
box-sizing: content-box;
margin-top: 10px;
margin-bottom: 10px;
}
#keyboard div {
position: absolute;
border-color: black;
box-sizing: border-box;
background-clip: padding-box;
}
#keyboard .hover .keyborder { border-color: green !important; border-style: solid; }
#keyboard .selected .keyborder { border-color: red !important; border-style: solid; }
#keyboard .ghosted { opacity: 0.5; }
.key {
position: relative;
display:table;
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
}
/* Key labels */
.keylabel>div { display: table-cell; position: static !important; }
.keylabel3>div, .keylabel4>div, .keylabel6>div, .keylabel8>div { text-align: right; }
.keylabel7>div, .keylabel8>div { vertical-align: middle; }
.keylabel2>div, .keylabel4>div { vertical-align: bottom; }
.keylabel5, .keylabel6 { top: 100%; margin-top: -1px; font-size: 10px !important; white-space: nowrap; overflow: hidden;}
.keylabel1.centerx-true>div, .keylabel2.centerx-true>div, .keylabel5.centerf-true>div, .keylabel7.centerx-true>div { text-align: center; }
.keylabel1.centery-true>div, .keylabel3.centery-true>div { vertical-align: middle; }
/* The external border of the keycap */
.keyborder {
position: absolute;
border-radius: 5px;
border: solid 1px black;
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
for i in (1..9) {
.keylabel.textsize{i} {
font-size: (6+2*i)px;
line-height: 1em;
}
}
.keyborder.inner { opacity: 0.1; border-radius: 4px; }
.hover .keyborder { border-color: green; }
.selected .keyborder { border-color: red; }
.ghosted { opacity: 0.4; }
/* The sides of the cap (darker) */
.keybg {
position: absolute;
border-radius: 5px;
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
.keylabels { font-family: "Helvetica", "Arial", sans-serif; }
.keylabel hr { display: inline; }
.keylabel hr:before {
position: relative;
display: block;
overflow: hidden;
white-space: nowrap;
content: "\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500";
}
/* The face of the cap */
.keyfg {
font-family: "Helvetica", "Arial", sans-serif;
position: absolute;
border-radius: 3px;
display:table-cell;
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
/* Keycap-Profile Modifications */
.SA .keylabels, .DSA .keylabels {
font-family: 'engravers_gothic_fsregular'; /* substitute for Gorton Modified */
}
.keyfg .keylabel.textsize1 { font-size: 8px; line-height: 1em; }
.keyfg .keylabel.textsize2 { font-size: 10px; line-height: 1em; }
.keyfg .keylabel.textsize3 { font-size: 12px; line-height: 1em; }
.keyfg .keylabel.textsize4 { font-size: 14px; line-height: 1em; }
.keyfg .keylabel.textsize5 { font-size: 16px; line-height: 1em; }
.keyfg .keylabel.textsize6 { font-size: 18px; line-height: 1em; }
.keyfg .keylabel.textsize7 { font-size: 20px; line-height: 1em; }
.keyfg .keylabel.textsize8 { font-size: 22px; line-height: 1em; }
.keyfg .keylabel.textsize9 { font-size: 24px; line-height: 1em; }
.keyfg .keylabel hr { display: inline; }
.keyfg .keylabel hr:before {
position: relative;
display: block;
overflow: hidden;
white-space: nowrap;
content: "\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500\2500";
}
.DCS .keyfg, .OEM .keyfg {
background: -moz-linear-gradient(left, rgba(0,0,0,0) 0%, rgba(0,0,0,0.1) 40%, rgba(0,0,0,0.1) 60%, rgba(0,0,0,0) 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0)), color-stop(40%,rgba(0,0,0,0.1)), color-stop(60%,rgba(0,0,0,0.1)), color-stop(100%,rgba(0,0,0,0)));
background: -webkit-linear-gradient(left, rgba(0,0,0,0) 0%,rgba(0,0,0,0.1) 40%,rgba(0,0,0,0.1) 60%,rgba(0,0,0,0) 100%);
background: -o-linear-gradient(left, rgba(0,0,0,0) 0%,rgba(0,0,0,0.1) 40%,rgba(0,0,0,0.1) 60%,rgba(0,0,0,0) 100%);
background: -ms-linear-gradient(left, rgba(0,0,0,0) 0%,rgba(0,0,0,0.1) 40%,rgba(0,0,0,0.1) 60%,rgba(0,0,0,0) 100%);
background: linear-gradient(to right, rgba(0,0,0,0) 0%,rgba(0,0,0,0.1) 40%,rgba(0,0,0,0.1) 60%,rgba(0,0,0,0) 100%);
background-repeat: no-repeat;
.DSA .keylabel5, .DSA .keylabel6, .SA .keylabel5, .SA .keylabel6 { margin-top: -1px; font-size: 9px !important; }
.DCS .keytop, .OEM .keytop {
background: linear-gradient(to right, #00000000 0%, #0000001A 40%, #0000001A 60%, #00000000 100%);
background-repeat: no-repeat;
}
.DSA .keyborder.inner, .DSA .keyfg { margin-top: 3px; border-radius: 8px; }
.SA .keyborder.inner, .SA .keyfg { margin-top: 1px; border-radius: 5px; }
.DSA .keyfg, .SA .keyfg {
font-family: 'engravers_gothic_fsregular'; /* substitute for Gorton Modified */
background: -moz-radial-gradient(center, ellipse cover, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.1) 10%, rgba(0,0,0,0) 100%);
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(0,0,0,0.1)), color-stop(10%,rgba(0,0,0,0.1)), color-stop(100%,rgba(0,0,0,0)));
background: -webkit-radial-gradient(center, ellipse cover, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.1) 10%,rgba(0,0,0,0) 100%);
background: -o-radial-gradient(center, ellipse cover, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.1) 10%,rgba(0,0,0,0) 100%);
background: -ms-radial-gradient(center, ellipse cover, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.1) 10%,rgba(0,0,0,0) 100%);
background: radial-gradient(ellipse at center, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0.1) 10%,rgba(0,0,0,0) 100%);
background-repeat: no-repeat;
.DSA .keytop, .SA .keytop {
background: radial-gradient(ellipse at center, #0000001A 0%, #0000001A 10%, #00000000 100%);
background-repeat: no-repeat;
}
.DCS.SPACE .keyfg, .OEM.SPACE .keyfg, .DSA.SPACE .keyfg, .SA.SPACE .keyfg {
background: -moz-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0) 40%, rgba(0,0,0,0.1) 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0,0,0,0.1)), color-stop(20%, rgba(0,0,0,0)), color-stop(40%, rgba(0,0,0,0)), color-stop(100%, rgba(0,0,0,0.1)));
background: -webkit-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0) 40%, rgba(0,0,0,0.1) 100%);
background: -o-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0) 40%, rgba(0,0,0,0.1) 100%);
background: -ms-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0) 40%, rgba(0,0,0,0.1) 100%);
background: linear-gradient(to bottom, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0) 40%, rgba(0,0,0,0.1) 100%);
background-repeat: no-repeat;
.DCS.SPACE .keytop, .OEM.SPACE .keytop, .DSA.SPACE .keytop, .SA.SPACE .keytop {
background: linear-gradient(to bottom, #0000001A 0%, #00000000 20%, #00000000 40%, #0000001A 100%);
background-repeat: no-repeat;
}
.DSA.DISH .keyfg, .DSA.HOMING .keyfg, .SA.HOMING .keyfg {
background: -moz-radial-gradient(circle, rgba(0,0,0,0.11) 50%, rgba(0,0,0,0.04) 60%);
background: -webkit-gradient(radial, center center, 50%, center center, 60%, from(rgba(0,0,0,0.12)), to(rgba(0,0,0,0.04)));
background: -webkit-radial-gradient(circle, rgba(0,0,0,0.11) 50%, rgba(0,0,0,0.04) 60%);
background: -o-radial-gradient(circle, rgba(0,0,0,0.11) 50%, rgba(0,0,0,0.04) 60%);
background: -ms-radial-gradient(circle, rgba(0,0,0,0.11) 50%, rgba(0,0,0,0.04) 60%);
background: radial-gradient(circle, rgba(0,0,0,0.11) 50%, rgba(0,0,0,0.04) 60%);
background-repeat: no-repeat;
.DSA.DISH .keytop, .DSA.HOMING .keytop, .SA.HOMING .keytop {
background: radial-gradient(circle, #0000001C 50%, #0000000A 60%);
background-repeat: no-repeat;
}
.HOMING .keyfg .keylabels {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAACCAYAAABhYU3QAAAAGElEQVQI12P4//+/ODGYAUwwMAThwyA1ACUKJ4H2Fi17AAAAAElFTkSuQmCC);
.HOMING .keytop .keylabels {
background-image: url("nub.png");
background-repeat: no-repeat;
background-position: center 90%;
}
.DSA.HOMING .keyfg .keylabels, .SA.HOMING .keyfg .keylabels { background-image: none; }
.DSA.HOMING .keytop .keylabels, .SA.HOMING .keytop .keylabels { background-image: none; }
span.PETSCII {
font-family: "C64 Pro Mono";
font-size: 6px !important;
border: solid 1px;
letter-spacing: 0px;
padding: 0;
margin: 0;
font-family: "C64ProMono";
font-size: 6px !important;
border: solid 1px;
letter-spacing: 0px;
padding: 0;
margin: 0;
}
/* Key labels */
.keylabels { display: table; }
.keylabel { display: table-row; position: absolute; left:2px; top:2px; right:2px; bottom:2px; }
.keylabel > div { display: table-cell; }
.keylabel3>div, .keylabel4>div, .keylabel6>div, .keylabel8>div { text-align: right; }
.keylabel7>div, .keylabel8>div { vertical-align: middle; }
.keylabel2>div, .keylabel4>div { vertical-align: bottom; }
.keylabel5, .keylabel6 { top:100%; margin-top:0px; font-size: 10px !important; white-space:nowrap; overflow: hidden;}
.DSA .keylabel5, .DSA .keylabel6, .SA .keylabel5, .SA .keylabel6 { margin-top:-1px; font-size: 9px !important; }
.keylabel1.centerx-true>div, .keylabel2.centerx-true>div, .keylabel5.centerf-true>div, .keylabel7.centerx-true>div { text-align: center; }
.keylabel1.centery-true>div, .keylabel3.centery-true>div { vertical-align: middle; }
/* color swatches */
#swatches {
list-style-type: none;
-webkit-margin-before: 0em;
-webkit-margin-after: 0em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
-webkit-padding-start: 0px;
}
#swatches { list-style-type: none; }
.swatch {
display: inline-block;
position:relative;
width: 16px;
height: 32px;
border:solid 1px #888;
margin-right:-1px;
margin-bottom:-6px;
padding:0px;
display: inline-block;
position: relative;
width: 16px;
height: 32px;
border: solid 1px #888;
margin-right: -1px;
margin-bottom: -6px;
padding: 0px;
}
#swatches.disabled .swatch { background-color: rgb(235,235,228) !important; }
#swatches [data-hint]:after { white-space: nowrap; }
.swatch .highlight { display:none; }
.swatch.selected-bg .highlight.bg { display:block; z-index:100; width: 6px; height: 6px; border: solid 1px black; background: white; opacity; 0.75; position:absolute; left:7px; top:23px; }
.swatch.selected-fg .highlight.fg { display:block; z-index:100; width: 6px; height: 6px; border: solid 1px white; background: black; opacity; 0.75; position:absolute; left:1px; top:23px; }
.swatch .highlight { display: none; }
.swatch.selected-bg .highlight.bg { display: block; z-index: 100; width: 6px; height: 6px; border: solid 1px black; background: white; opacity: 0.75; position: absolute; left: 7px; top: 23px; }
.swatch.selected-fg .highlight.fg { display: block; z-index: 100; width: 6px; height: 6px; border: solid 1px white; background: black; opacity: 0.75; position: absolute; left: 1px; top: 23px; }
/* general styles */
.hidden { display: none; }
.error { border: solid 2px rgb(217,83,79); }
#selectionRectangle { position: absolute; border: dashed 2px red; }
#rotationCrosshairs {
display: none;
position: absolute;
margin: 0px;
padding: 0px;
font-size: 25px;
line-height: 23px;
width: 25px;
height: 25px;
color: black;
text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
#rotationCrosshairs {
display: none;
position: absolute;
margin: 0px;
padding: 0px;
font-size: 25px;
line-height: 23px;
width: 25px;
height: 25px;
color: black;
text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
}
#rawdata, #rawdata-error, #noteseditor { font-family: "Consolas", "Courier New", "Courier", monospace; }
@ -256,49 +180,43 @@ span.PETSCII {
padding-bottom: 15px;
margin-left: 0px;
}
#properties.row { padding-left:30px; }
/*Help Dialog*/
.modal-xl .modal-dialog { width:80vw; }
.modal-xxl .modal-dialog { width:90vw; }
#properties.row { padding-left: 30px; }
/* Tooltip modifications */
.hint--rounded:after { width: 300px; }
.hint:after, [data-hint]:after { white-space: pre-line; }
.hint:before, .hint:after, [data-hint]:before, [data-hint]:after { -webkit-transition: 0.1s ease; -moz-transition: 0.1s ease; transition: 0.1s ease; }
#swap-colors { position: absolute; top: 11px; left: 200px; z-index: 1; }
.color-name { display: inline-block; min-width: 3em; font-size: 10px; white-space: nowrap; }
/* Help Dialog */
.modal-xl .modal-dialog { width: 80vw; }
.modal-xxl .modal-dialog { width: 90vw; }
/* Our "README" dialog; we want the body of the dialog itself to be scrollable */
.markdownDialog .modal-dialog { margin: 30 auto; } /*60px*/
.markdownDialog .modal-header { height: 55px; }
.markdownDialog .modal-footer { height: 74px; margin-top: 0px; }
.markdownDialog .modal-body {
padding-bottom: 15px;
height: calc(100vh - 205px) !important;
overflow-y: auto !important;
padding-bottom: 15px;
height: calc(100vh - 205px) !important;
overflow-y: auto !important;
}
.drag-over { border: dotted 3px red !important; box-sizing: border-box; }
/* Only show the keyboard layout itself when printing */
@media print {
html, body { overflow:hidden; height:100%; margin: 0 !important; padding: 0 !important; }
html, body { overflow: hidden; height: 100%; margin: 0 !important; padding: 0 !important; }
#wrap > .navbar, #wrap > .body > .btn-group, #keyboard ~ *, #keyboard + *, #footer, #helpDialog, #markdownDialog { display: none; margin: 0 !important; padding: 0 !important; }
div.body { margin: 0 !important; padding: 0 !important; }
a { color: black; text-decoration: none; }
#keyboard {
border: none;
background-color: inherit !important;
transform:scale(0.75,0.75);
-moz-transform:scale(0,75,0.75);
-ms-transform:scale(0,75,0.75);
-webkit-transform:scale(0.75,0.75);
position: absolute !important;
left: 0px;
top: 0px;
padding-left: 0px; padding-top: 0px;
border: none;
background-color: inherit !important;
transform: scale(0.75,0.75);
position: absolute !important;
left: 0px;
top: 0px;
padding-left: 0px; padding-top: 0px;
}
}
@ -312,4 +230,7 @@ span.PETSCII {
.form-control.input-sm, .input-group-sm > .form-control { height: 26px; padding: 2px; }
.input-group-sm > .input-group-btn > .btn { height: 26px; padding: 2px; min-width: 16px; }
.input-group-sm > .input-group-addon { height: 26px; padding: 2px; min-width: 16px; }
.form-horizontal .form-group-sm .checkbox { padding-top: 3px; min-height:26px; }
.form-horizontal .form-group-sm .checkbox { padding-top: 3px; min-height: 26px; }
#swap-colors { position: absolute; top: 11px; left: 200px; z-index: 1; }
.color-name { display: inline-block; min-width: 3em; font-size: 10px; white-space: nowrap; }

@ -12,7 +12,7 @@ All rights reserved.
<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="css/colorpicker.min.css">
<link rel="stylesheet" type="text/css" href="kb.css">
<link rel="stylesheet" type="text/css" href="css/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>
@ -27,6 +27,7 @@ All rights reserved.
<script type="text/javascript" src="js/ng-file-upload.min.js"></script>
<script type="text/javascript" src="js/draganddrop.min.js"></script>
<script type="text/javascript" src="js/bootstrap-colorpicker-module.min.js"></script>
<script type="text/javascript" src="js/doT.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>
@ -552,7 +553,7 @@ Footer
Copyright &copy; 2013-2015 &mdash; 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; text-alignment:right;">
<div style="float:right;">
<a href="#" ng-click="showHelp($event)"><i class="fa fa-question-circle"></i> Help &amp; 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/>
@ -693,6 +694,10 @@ Options Dialog
</div>
</script>
<!--***********************************************
Angular Templates
************************************************-->
<!-- Color Picker Template -->
<script type="text/ng-template" id="colorPicker.html">
<div class="form-group form-group-sm">
@ -758,5 +763,79 @@ Options Dialog
</div>
</script>
<!--***********************************************
DOT.js Templates
************************************************-->
<!-- Keycap Template -->
<script type="text/ng-template" id="keycap_t">
<div class='{{=key.ghost ? "ghosted" : "keycap"}}'
{{? key.rotation_angle }}
style='transform:rotate({{=key.rotation_angle}}deg); transform-origin:{{=key.parms.origin_x}}px {{=key.parms.origin_y}}px;'
{{?}}>
<div style="left: {{=key.parms.capx}}px; top: {{=key.parms.capy}}px;
width: {{=key.parms.capwidth}}px; height: {{=key.parms.capheight}}px;
border: solid {{=key.sizes.strokeWidth}}px black; border-radius: {{=key.sizes.roundOuter}}px;
background-color: {{=key.parms.darkColor}};"
class="keyborder"></div>
{{? key.parms.jShaped }}
<div style="left: {{=key.parms.capx2}}px; top: {{=key.parms.capy2}}px;
width: {{=key.parms.capwidth2}}px; height: {{=key.parms.capheight2}}px;
border: solid {{=key.sizes.strokeWidth}}px black; border-radius: {{=key.sizes.roundOuter}}px;
background-color: {{=key.parms.darkColor}};"
class="keyborder"></div>
<div style="left: {{=key.parms.capx + key.sizes.strokeWidth}}px; top: {{=key.parms.capy + key.sizes.strokeWidth}}px;
width: {{=key.parms.capwidth - key.sizes.strokeWidth*2}}px;
height: {{=key.parms.capheight - key.sizes.strokeWidth*2}}px;
background-color: {{=key.parms.darkColor}};
border-radius: {{=key.sizes.roundOuter}}px;"></div>
{{?}}
{{? !key.ghost }}
<div style="left: {{=key.parms.innercapx}}px; top: {{=key.parms.innercapy}}px;
width: {{=key.parms.innercapwidth}}px; height: {{=key.parms.innercapheight}}px;
border: solid {{=key.sizes.strokeWidth}}px rgba(0,0,0,0.1);
background-color: {{=key.parms.lightColor}};
border-radius: {{=key.sizes.roundInner}}px;"
class="keytop"></div>
{{? key.parms.jShaped && !key.stepped }}
<div style="left: {{=key.parms.innercapx2}}px; top: {{=key.parms.innercapy2}}px;
width: {{=key.parms.innercapwidth2}}px; height: {{=key.parms.innercapheight2}}px;
border: solid {{=key.sizes.strokeWidth}}px rgba(0,0,0,0.1); border-radius: {{=key.sizes.roundInner}}px;
background-color: {{=key.parms.lightColor}};
background-position: {{=Math.min(key.parms.innercapx-key.parms.innercapx2,0)}}px {{=Math.min(key.parms.innercapy-key.parms.innercapy2,0)}}px;
background-size: {{=Math.max(key.parms.innercapwidth,key.parms.innercapwidth2)}}px {{=Math.max(key.parms.innercapheight,key.parms.innercapheight2)}}px;"
class="keytop"></div>
<div style="left: {{=key.parms.innercapx + key.sizes.strokeWidth}}px; top: {{=key.parms.innercapy + key.sizes.strokeWidth}}px;
width: {{=key.parms.innercapwidth - key.sizes.strokeWidth*2}}px; height: {{=key.parms.innercapheight - key.sizes.strokeWidth*2}}px;
border-radius: {{=key.sizes.roundInner}}px;
background-color: {{=key.parms.lightColor}};
background-position: {{=Math.min(key.parms.innercapx2-key.parms.innercapx,0)}}px {{=Math.min(key.parms.innercapy2-key.parms.innercapy,0)}}px;
background-size: {{=Math.max(key.parms.innercapwidth,key.parms.innercapwidth2)}}px {{=Math.max(key.parms.innercapheight,key.parms.innercapheight2)}}px;"
class="keytop"></div>
{{?}}
<div style='left: {{=key.parms.innercapx}}px; top: {{=key.parms.innercapy}}px; width: {{=key.parms.innercapwidth}}px; height: {{=key.parms.innercapheight}}px; padding: {{=key.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\/]|$)/,"&lt;$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:{{=key.parms.textcapwidth}}px; height:{{=key.parms.textcapheight}}px;'>
<div style='width:{{=key.parms.textcapwidth}}px; max-width:{{=key.parms.textcapwidth}}px; height:{{=key.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>
</body>
</html>

@ -203,7 +203,7 @@
});
if($scope.keyboard.meta.name || $scope.keyboard.meta.author)
bottom += 32;
$scope.kbHeight = bottom + 8;
$scope.kbHeight = bottom;
};
// Given a key, generate the HTML needed to render it

@ -0,0 +1,35 @@
{
"folders":
[
{
"name": "Root",
"path": "."
}
],
"settings":
{
"tab_size": 2,
"translate_tabs_to_spaces": true,
"build_system": "Automatic",
//SublimeOnSaveBuild package (optional)
"filename_filter": "\\.(css|js|sass|less|scss)$",
"build_on_save": 1
},
"build_systems":
[
{
"name": "Stylus.KB",
"cmd": ["stylus", "--out", "css", "-c", "-m", "--inline", "--with", "{limit:1024}", "$file" ],
"windows": { "cmd": ["stylus.cmd", "--out", "css", "-c", "-m", "--inline", "--with", "{limit:1024}", "$file" ] },
"selector": "source.css, source.stylus",
"working_dir" : "$project_path"
},
{
"name": "Make.KB",
"cmd": ["cmd", "/c", "dir"],
"selector": "source.js, text.html",
"working_dir" : "$project_path"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

@ -3,17 +3,37 @@ var $renderKey = {};
"use strict";
// Some predefined sizes for our caps:
// - cap == size of 1 unit, e.g., 0.75", or 19.05mm is standard
// - spacing == distance from edge of unit to cap, e.g., (0.75" - 0.715")/2 (for DCS)
// - margin == distance from edge of cap (at bottom) to edge of cap (at top), e.g., (0.715" - 0.470")/2 (for DCS)
// - padding == distance between text & edge of cap; should match CSS
// - strokeWidth == thickness of the outline strokes; should match CSS
// - roundInner/roundOuter == corner roundness for inner/outer borders; should match CSS
// - scaleFactor == scale between unit type and actual numbers used
// - unit == size of 1 unit, e.g., 0.75", or 19.05mm is standard
// - keySpacing == distance from edge of unit-square to keycap, e.g., (0.75" - 0.715")/2 (for DCS)
// - bevelMargin == distance from edge of keycap (at bottom) to edge of keycap (at top), e.g., (0.715" - 0.470")/2 (for DCS)
// - padding == distance between text & edge of keycap
// - strokeWidth == thickness of the outline strokes
// - roundInner/roundOuter == corner roundness for inner/outer borders
var unitSizes = {
px : { cap: 54, padding: 2, margin: 6, spacing: 1, strokeWidth: 1, roundOuter: 5, roundInner: 3, scaleFactor: 1 }, // pixels
mm : { cap: 1905, padding: 0, margin: 311.15, spacing: 44.45, strokeWidth: 20, roundOuter: 100, roundInner: 200, scaleFactor: 100 } // 1/100 mm
px : {
unit : 54,
strokeWidth: 1,
"" : { keySpacing: 0, bevelMargin: 6, bevelOffsetY: 3, padding: 3, roundOuter: 5, roundInner: 3 },
"DCS" : { keySpacing: 0, bevelMargin: 6, bevelOffsetY: 3, padding: 3, roundOuter: 5, roundInner: 3 },
"DSA" : { keySpacing: 0, bevelMargin: 6, bevelOffsetY: 0, padding: 3, roundOuter: 5, roundInner: 8 },
"SA" : { keySpacing: 0, bevelMargin: 6, bevelOffsetY: 2, padding: 3, roundOuter: 5, roundInner: 5 }
},
mm : {
unit: 19.05,
strokeWidth: 0.20,
"" : { keySpacing: 0.4445, bevelMargin: 3.1115, padding: 0, roundOuter: 1.0, roundInner: 2.0 },
"DCS" : { keySpacing: 0.4445, bevelMargin: 3.1115, padding: 0, roundOuter: 1.0, roundInner: 2.0 },
"DSA" : { keySpacing: 0.4445, bevelMargin: 3.1115, padding: 0, roundOuter: 1.0, roundInner: 2.0 },
"SA" : { keySpacing: 0.4445, bevelMargin: 3.1115, padding: 0, roundOuter: 1.0, roundInner: 2.0 }
}
};
["px","mm"].forEach(function(unit) {
["","DCS","DSA", "SA"].forEach(function(profile) {
unitSizes[unit][profile].unit = unitSizes[unit].unit;
unitSizes[unit][profile].strokeWidth = unitSizes[unit].strokeWidth;
});
unitSizes[unit].OEM = unitSizes[unit].DCS; // same, for now
});
// Lighten a color by the specified amount
function lightenColor(color,mod) {
@ -22,146 +42,152 @@ var $renderKey = {};
return c.sRGB8();
}
function capsize(sizes,size) { return (size*sizes.cap) - (2*sizes.spacing); };
function getProfile(key) {
return (/\b(SA|DSA|DCS|OEM)\b/.exec(key.profile) || [""])[0];
}
function getRenderParms(key, sizes) {
var parms = {};
parms.capwidth = capsize(sizes,key.width);
parms.capwidth2 = capsize(sizes,key.width2);
parms.capheight = capsize(sizes,key.height);
parms.capheight2 = capsize(sizes,key.height2);
parms.capx = capsize(sizes,key.x) + sizes.margin;
parms.capx2 = capsize(sizes,key.x+key.x2)+sizes.margin;
parms.capy = capsize(sizes,key.y) + sizes.margin;
parms.capy2 = capsize(sizes,key.y+key.y2)+sizes.margin;
parms.jShaped = (parms.capwidth2 !== parms.capwidth) || (parms.capheight2 !== parms.capheight) || (parms.capx2 !== parms.capx) || (parms.capy2 !== parms.capy);
parms.innerPadding = (2*sizes.margin) + (2*sizes.padding);
parms.borderStyle = key.ghost ? "keyborder ghosted" : "keyborder";
parms.bgStyle = key.ghost ? "keybg ghosted" : "keybg";
parms.jShaped = (key.width !== key.width2) || (key.height !== key.height2) || key.x2 || key.y2;
// Overall dimensions of the unit square(s) that the cap occupies
parms.capwidth = sizes.unit * key.width;
parms.capheight = sizes.unit * key.height;
parms.capx = sizes.unit * key.x;
parms.capy = sizes.unit * key.y;
if(parms.jShaped) {
parms.capwidth2 = sizes.unit * key.width2;
parms.capheight2 = sizes.unit * key.height2;
parms.capx2 = sizes.unit * (key.x + key.x2);
parms.capy2 = sizes.unit * (key.y + key.y2);
}
// Dimensions of the outer part of the cap
parms.outercapwidth = parms.capwidth - sizes.keySpacing*2;
parms.outercapheight = parms.capheight - sizes.keySpacing*2;
parms.outercapx = parms.capx + sizes.keySpacing;
parms.outercapy = parms.capy + sizes.keySpacing;
if(parms.jShaped) {
parms.outercapy2 = parms.capy2 + sizes.keySpacing;
parms.outercapx2 = parms.capx2 + sizes.keySpacing;
parms.outercapwidth2 = parms.capwidth2 - sizes.keySpacing*2;
parms.outercapheight2 = parms.capheight2 - sizes.keySpacing*2;
}
// Dimensions of the top of the cap
parms.innercapwidth = parms.outercapwidth - sizes.bevelMargin*2;
parms.innercapheight = parms.outercapheight - sizes.bevelMargin*2;
parms.innercapx = parms.outercapx + sizes.bevelMargin;
parms.innercapy = parms.outercapy + sizes.bevelMargin - sizes.bevelOffsetY;
if(parms.jShaped) {
parms.innercapwidth2 = parms.outercapwidth2 - sizes.bevelMargin*2;
parms.innercapheight2 = parms.outercapheight2 - sizes.bevelMargin*2;
parms.innercapx2 = parms.outercapx2 + sizes.bevelMargin;
parms.innercapy2 = parms.outercapy2 + sizes.bevelMargin - sizes.bevelOffsetY;
}
// Dimensions of the text part of the cap
parms.textcapwidth = parms.innercapwidth - sizes.padding*2;
parms.textcapheight = parms.innercapheight - sizes.padding*2;
parms.textcapx = parms.innercapx + sizes.padding;
parms.textcapy = parms.innercapy + sizes.padding;
parms.darkColor = key.color;
parms.lightColor = lightenColor($color.hex(key.color), 1.2).hex();
key.centerx = key.align&1 ? true : false;
key.centery = key.align&2 ? true : false;
key.centerf = key.align&4 ? true : false;
return parms;
}
function getKeyBounds(key, sizes, parms) {
var bounds = {};
// Rotation matrix about the origin
bounds.origin_x = capsize(sizes,key.rotation_x)+sizes.margin;
bounds.origin_y = capsize(sizes,key.rotation_y)+sizes.margin;
var mat = Math.transMatrix(bounds.origin_x, bounds.origin_y).mult(Math.rotMatrix(key.rotation_angle)).mult(Math.transMatrix(-bounds.origin_x, -bounds.origin_y));
parms.origin_x = sizes.unit * key.rotation_x;
parms.origin_y = sizes.unit * key.rotation_y;
var mat = Math.transMatrix(parms.origin_x, parms.origin_y).mult(Math.rotMatrix(key.rotation_angle)).mult(Math.transMatrix(-parms.origin_x, -parms.origin_y));
// Construct the *eight* corner points, transform them, and determine the transformed bbox.
bounds.rect = { x:parms.capx, y:parms.capy, w:parms.capwidth, h:parms.capheight, x2:parms.capx+parms.capwidth, y2:parms.capy+parms.capheight };
bounds.rect2 = { x:parms.capx2, y:parms.capy2, w:parms.capwidth2, h:parms.capheight2, x2:parms.capx2+parms.capwidth2, y2:parms.capy2+parms.capheight2 };
bounds.bbox = { x:9999999, y:9999999, x2:-9999999, y2:-9999999 };
parms.rect = { x:parms.capx, y:parms.capy, w:parms.capwidth, h:parms.capheight, x2:parms.capx+parms.capwidth, y2:parms.capy+parms.capheight };
parms.rect2 = parms.jShaped ? { x:parms.capx2, y:parms.capy2, w:parms.capwidth2, h:parms.capheight2, x2:parms.capx2+parms.capwidth2, y2:parms.capy2+parms.capheight2 } : parms.rect;
parms.bbox = { x:9999999, y:9999999, x2:-9999999, y2:-9999999 };
var corners = [
{x:bounds.rect.x, y:bounds.rect.y},
{x:bounds.rect.x, y:bounds.rect.y2},
{x:bounds.rect.x2, y:bounds.rect.y},
{x:bounds.rect.x2, y:bounds.rect.y2},
{x:bounds.rect2.x, y:bounds.rect2.y},
{x:bounds.rect2.x, y:bounds.rect2.y2},
{x:bounds.rect2.x2, y:bounds.rect2.y},
{x:bounds.rect2.x2, y:bounds.rect2.y2},
{x:parms.rect.x, y:parms.rect.y},
{x:parms.rect.x, y:parms.rect.y2},
{x:parms.rect.x2, y:parms.rect.y},
{x:parms.rect.x2, y:parms.rect.y2}
];
if(parms.jShaped) corners.push(
{x:parms.rect2.x, y:parms.rect2.y},
{x:parms.rect2.x, y:parms.rect2.y2},
{x:parms.rect2.x2, y:parms.rect2.y},
{x:parms.rect2.x2, y:parms.rect2.y2}
);
for(var i = 0; i < corners.length; ++i) {
corners[i] = mat.transformPt(corners[i]);
bounds.bbox.x = Math.min(bounds.bbox.x, corners[i].x);
bounds.bbox.y = Math.min(bounds.bbox.y, corners[i].y);
bounds.bbox.x2 = Math.max(bounds.bbox.x2, corners[i].x);
bounds.bbox.y2 = Math.max(bounds.bbox.y2, corners[i].y);
parms.bbox.x = Math.min(parms.bbox.x, corners[i].x);
parms.bbox.y = Math.min(parms.bbox.y, corners[i].y);
parms.bbox.x2 = Math.max(parms.bbox.x2, corners[i].x);
parms.bbox.y2 = Math.max(parms.bbox.y2, corners[i].y);
}
bounds.bbox.w = bounds.bbox.x2 - bounds.bbox.x;
bounds.bbox.h = bounds.bbox.y2 - bounds.bbox.y;
parms.bbox.w = parms.bbox.x2 - parms.bbox.x;
parms.bbox.h = parms.bbox.y2 - parms.bbox.y;
return bounds;
return parms;
}
function STYLE(style) {
var html = "";
for(var key in style) {
if(style.hasOwnProperty(key)) {
html += key + ":" + style[key].toString();
if(typeof style[key] === 'number') html += "px";
html += ';';
}
}
return html;
}
function DIV(style, className, content) {
var html = "<div style='" + STYLE(style) + "'";
if(className) html += " class='"+className+"'";
html += ">";
if(content) html += (typeof content === 'function' ? content() : content.toString());
html += "</div>";
return html;
}
var html_t;
$(document).ready(function() {
html_t = doT.template($('#keycap_t').html(), {__proto__: doT.templateSettings, varname:"key, $sanitize, lightenColor"});
});
// Given a key, generate the HTML needed to render it
$renderKey.noRenderText = [0,2,1,3,0,4,2,3];
$renderKey.html = function(key, $sanitize) {
var sizes = unitSizes.px;
var sizes = unitSizes.px[getProfile(key)]; // always in pixels
var parms = getRenderParms(key, sizes);
// Get the rects & bounding-box of the key (for click-selection purposes)
var bounds = getKeyBounds(key, sizes, parms);
key.rect = bounds.rect;
key.rect2 = bounds.rect2;
key.bbox = bounds.bbox;
key.sizes = sizes;
key.parms = parms;
// Update the key alignment flags (UI depends on these being up-to-date)
key.centerx = key.align&1 ? true : false;
key.centery = key.align&2 ? true : false;
key.centerf = key.align&4 ? true : false;
// Update the rects & bounding-box of the key (for click-selection purposes)
key.rect = parms.rect;
key.rect2 = parms.rect2;
key.bbox = parms.bbox;
// Keep an inverse transformation matrix so that we can transform mouse
// coordinates into key-space.
key.mat = Math.transMatrix(bounds.origin_x, bounds.origin_y).mult(Math.rotMatrix(-key.rotation_angle)).mult(Math.transMatrix(-bounds.origin_x, -bounds.origin_y));
// Keep an inverse transformation matrix so that we can transform mouse coordinates into key-space.
key.mat = Math.transMatrix(parms.origin_x, parms.origin_y).mult(Math.rotMatrix(-key.rotation_angle)).mult(Math.transMatrix(-parms.origin_x, -parms.origin_y));
// Determine the location of the rotation crosshairs for the key
key.crosshairs = "none";
if(key.rotation_x || key.rotation_y || key.rotation_angle) {
key.crosshairs_x = bounds.origin_x;
key.crosshairs_y = bounds.origin_y;
key.crosshairs_x = parms.origin_x;
key.crosshairs_y = parms.origin_y;
key.crosshairs = "block";
}
// Generate the HTML
var html = "<div>";
if(key.rotation_angle) {
html = ("<div style='transform:rotate({0}deg); -ms-transform:rotate({0}deg); -webkit-transform:rotate({0}deg); " +
"transform-origin:{1}px {2}px; -ms-transform-origin:{1}px{2}px; -webkit-transform-origin:{1}px {2}px;'>")
.format(key.rotation_angle, bounds.origin_x, bounds.origin_y);
}
var div = "<div style='width:{0}px; height:{1}px; left:{2}px; top:{3}px; background-color:{4};' class='{5}'></div>\n";
// The border
html += div.format(parms.capwidth, parms.capheight, parms.capx, parms.capy, parms.darkColor, parms.borderStyle);
if(parms.jShaped) {
html += div.format(parms.capwidth2, parms.capheight2, parms.capx2, parms.capy2, parms.darkColor, parms.borderStyle);
}
// The key edges
html += div.format(parms.capwidth, parms.capheight, parms.capx+1, parms.capy+1, parms.darkColor, parms.bgStyle);
if(parms.jShaped) {
html += div.format(parms.capwidth2, parms.capheight2, parms.capx2+1, parms.capy2+1, parms.darkColor, parms.bgStyle);
}
if(!key.ghost) {
// The top of the cap
var divInner = "<div class='keyborder inner' style='width:{0}px; height:{1}px; left:{2}px; top:{3}px; background-color:{4}; padding:{5}px;'></div>\n";
html += divInner.format( parms.capwidth-parms.innerPadding, parms.capheight-parms.innerPadding, parms.capx+sizes.margin, parms.capy+(sizes.margin/2), parms.lightColor, sizes.padding );
if(parms.jShaped && !key.stepped) {
html += divInner.format( parms.capwidth2-parms.innerPadding, parms.capheight2-parms.innerPadding, parms.capx2+sizes.margin, parms.capy2+(sizes.margin/2), parms.lightColor, sizes.padding );
}
var maxWidth = parms.capwidth-(2*sizes.margin);
var maxHeight = parms.capheight-(2*sizes.margin);
var divFg = "<div class='keyfg' style='width:{0}px; height:{1}px; left:{2}px; top:{3}px; background-color:{4}; padding:{5}px; background-size:{6}px {7}px; background-position:{8}px {9}px;'>\n"
if(parms.jShaped && !key.stepped) {
maxWidth = Math.max(parms.capwidth,parms.capwidth2)-(2*sizes.margin);
maxHeight = Math.max(parms.capheight,parms.capheight2)-(2*sizes.margin);
html += divFg.format( parms.capwidth2-parms.innerPadding, parms.capheight2-parms.innerPadding, parms.capx2+sizes.margin+1, parms.capy2+(sizes.margin/2)+1, parms.lightColor, sizes.padding, maxWidth, maxHeight, Math.min(parms.capx,parms.capx2)-parms.capx2, Math.min(parms.capy,parms.capy2)-parms.capy2 );
html += "</div>";
}
html += divFg.format( parms.capwidth-parms.innerPadding, parms.capheight-parms.innerPadding, parms.capx+sizes.margin+1, parms.capy+(sizes.margin/2)+1, parms.lightColor, sizes.padding, maxWidth, maxHeight, Math.min(parms.capx,parms.capx2)-parms.capx, Math.min(parms.capy,parms.capy2)-parms.capy );
// The key labels
html += "<div class='keylabels' style='width:{0}px; height:{1}px;'>" /*left:{2}px; top:{3}px*/
.format(parms.capwidth-parms.innerPadding, parms.capheight-parms.innerPadding, parms.capx+sizes.margin+1, parms.capy+(sizes.margin/2)+1);
key.labels.forEach(function(label,i) {
if(label && label !== "" && !(key.align&$renderKey.noRenderText[i])) {
var sanitizedLabel = '<div class="hint--top hint--rounded" data-hint="Error: Invalid HTML in label field."><i class="fa fa-times-circle"></div></i>';
try { sanitizedLabel = $sanitize(label.replace(/<([^a-zA-Z\/]|$)/,"&lt;$1")); } catch(e) {}
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();
html += "<div class='keylabel keylabel{2} centerx-{5} centery-{6} centerf-{7} textsize{8}' style='color:{1};width:{3}px;height:{4}px;'><div style='width:{3}px;max-width:{3}px;height:{4}px;'>{0}</div></div>\n"
.format(sanitizedLabel, i===4||i===5 ? textColor : textColorLight, i+1, parms.capwidth-parms.innerPadding, parms.capheight-parms.innerPadding,
key.centerx, key.centery, key.centerf, i>0 ? key.fontheight2 : key.fontheight);
}
});
html += "</div></div></div>";
}
return html;
return html_t(key, $sanitize, lightenColor);
};
// Given a key, generate the SVG needed to render it
@ -169,16 +195,15 @@ var $renderKey = {};
// Update bbox
var parms = getRenderParms(key, sizes);
var bounds = getKeyBounds(key, sizes, parms);
bbox.x = Math.min(bbox.x, bounds.bbox.x);
bbox.y = Math.min(bbox.y, bounds.bbox.y);
bbox.x2 = Math.max(bbox.x2, bounds.bbox.x2);
bbox.y2 = Math.max(bbox.y2, bounds.bbox.y2);
bbox.x = Math.min(bbox.x, parms.bbox.x);
bbox.y = Math.min(bbox.y, parms.bbox.y);
bbox.x2 = Math.max(bbox.x2, parms.bbox.x2);
bbox.y2 = Math.max(bbox.y2, parms.bbox.y2);
// Generate the SVG
var svg = "<g class='key'>\n";
if(key.rotation_angle) {
svg = "<g class='key' transform='rotate({0} {1} {2})'>\n".format(key.rotation_angle, bounds.origin_x, bounds.origin_y);
svg = "<g class='key' transform='rotate({0} {1} {2})'>\n".format(key.rotation_angle, parms.origin_x, parms.origin_y);
}
var rectStrokeAndFill = ("<rect width='{0}' height='{1}' x='{2}' y='{3}' stroke='black' class='{5}' {6}/>\n" +
@ -199,20 +224,20 @@ var $renderKey = {};
}
if(!key.ghost) {
// The top of the cap
svg += rectStrokeAndFill.format( parms.capwidth-(2*sizes.margin), parms.capheight-(2*sizes.margin), parms.capx+sizes.margin+1, parms.capy+(sizes.margin/2)+1, parms.lightColor, "keyborder inner", roundInner );
// The top of the keycap
svg += rectStrokeAndFill.format( parms.capwidth-(2*sizes.bevelMargin), parms.capheight-(2*sizes.bevelMargin), parms.capx+sizes.bevelMargin+1, parms.capy+(sizes.bevelMargin/2)+1, parms.lightColor, "keyborder inner", roundInner );
if(parms.jShaped && !key.stepped) {
svg += rectStrokeAndFill.format( parms.capwidth2-(2*sizes.margin), parms.capheight2-(2*sizes.margin), parms.capx2+sizes.margin+1, parms.capy2+(sizes.margin/2)+1, parms.lightColor, "keyborder inner", roundInner );
svg += rectStrokeAndFill.format( parms.capwidth2-(2*sizes.bevelMargin), parms.capheight2-(2*sizes.bevelMargin), parms.capx2+sizes.bevelMargin+1, parms.capy2+(sizes.bevelMargin/2)+1, parms.lightColor, "keyborder inner", roundInner );
}
var maxWidth = parms.capwidth-(2*sizes.margin);
var maxHeight = parms.capheight-(2*sizes.margin);
var maxWidth = parms.capwidth-(2*sizes.bevelMargin);
var maxHeight = parms.capheight-(2*sizes.bevelMargin);
if(parms.jShaped && !key.stepped) {
maxWidth = Math.max(parms.capwidth,parms.capwidth2)-(2*sizes.margin);
maxHeight = Math.max(parms.capheight,parms.capheight2)-(2*sizes.margin);
svg += rectFill.format( parms.capwidth2-(2*sizes.margin), parms.capheight2-(2*sizes.margin), parms.capx2+sizes.margin+1, parms.capy2+(sizes.margin/2)+1, parms.lightColor, "keyfg", roundInner );
maxWidth = Math.max(parms.capwidth,parms.capwidth2)-(2*sizes.bevelMargin);
maxHeight = Math.max(parms.capheight,parms.capheight2)-(2*sizes.bevelMargin);
svg += rectFill.format( parms.capwidth2-(2*sizes.bevelMargin), parms.capheight2-(2*sizes.bevelMargin), parms.capx2+sizes.bevelMargin+1, parms.capy2+(sizes.bevelMargin/2)+1, parms.lightColor, "keyfg", roundInner );
}
svg += rectFill.format( parms.capwidth-(2*sizes.margin), parms.capheight-(2*sizes.margin), parms.capx+sizes.margin+1, parms.capy+(sizes.margin/2)+1, parms.lightColor, "keyfg", roundInner );
svg += rectFill.format( parms.capwidth-(2*sizes.bevelMargin), parms.capheight-(2*sizes.bevelMargin), parms.capx+sizes.bevelMargin+1, parms.capy+(sizes.bevelMargin/2)+1, parms.lightColor, "keyfg", roundInner );
//TODO//key labels
}
@ -223,19 +248,18 @@ var $renderKey = {};
$renderKey.fullSVG = function(keys, metadata) {
// Render all the keys
var units = "px";
var sizes = unitSizes[units];
var bbox = { x: 99999999, y:99999999, x2:-99999999, y2:-99999999 };
var keysSVG = "";
keys.forEach(function(key) {
keysSVG += $renderKey.svg(key, bbox, sizes);
keysSVG += $renderKey.svg(key, bbox, unitSizes[units][getProfile(key)]);
});
// Wrap with SVG boilerplate
var kbdMargin = 10, kbdPadding = 5;
var width = bbox.x2 + sizes.margin*2 + kbdMargin*2 + kbdPadding*2;
var height = bbox.y2 + sizes.margin*2 + kbdMargin*2 + kbdPadding*2;
var width = bbox.x2 + kbdMargin*2 + kbdPadding*2;
var height = bbox.y2 + kbdMargin*2 + kbdPadding*2;
var svg = "<svg width='{0}{4}' height='{1}{4}' viewBox='0 0 {2} {3}' xmlns='http://www.w3.org/2000/svg'>\n"
.format( width/sizes.scaleFactor, height/sizes.scaleFactor, width, height, units);
.format( width, height, width, height, units);
// styles
svg += "<style type='text/css'>\n";
@ -246,7 +270,7 @@ var $renderKey = {};
svg += "<g transform='translate({0},{0})'>\n".format(kbdMargin);
svg += "<rect width='{0}' height='{1}' stroke='#ddd' stroke-width='1' fill='{2}' rx='6' />\n"
.format( bbox.x2 + sizes.margin + kbdPadding*2, bbox.y2 + sizes.margin + kbdPadding*2, metadata.backcolor);
.format( bbox.x2 + kbdPadding*2, bbox.y2 + kbdPadding*2, metadata.backcolor);
svg += "<g transform='translate({0},{0})'>\n".format(kbdPadding);
svg += keysSVG;

Loading…
Cancel
Save