diff --git a/electron/src/tsconfig.json b/electron/src/tsconfig.json
index 92b896e6..ff03177a 100644
--- a/electron/src/tsconfig.json
+++ b/electron/src/tsconfig.json
@@ -17,6 +17,7 @@
"jquery",
"core-js",
"select2",
+ "file-saver",
"electron",
"usb"
]
diff --git a/electron/src/webpack.config.js b/electron/src/webpack.config.js
index aa1eecf1..cc4300ee 100644
--- a/electron/src/webpack.config.js
+++ b/electron/src/webpack.config.js
@@ -27,7 +27,8 @@ module.exports = {
modules: [path.join(rootDir, "node_modules")],
alias: {
jquery: 'jquery/dist/jquery.min.js',
- select2: 'select2/dist/js/select2.full.min.js'
+ select2: 'select2/dist/js/select2.full.min.js',
+ 'file-saver': 'filesaver.js/FileSaver.min.js'
}
},
module: {
diff --git a/package.json b/package.json
index 78257094..a6e78e5f 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"@ngrx/store-log-monitor": "3.0.2",
"@types/core-js": "0.9.35",
"@types/electron": "^1.4.32",
+ "@types/file-saver": "0.0.0",
"@types/jquery": "^2.0.40",
"@types/node": "^7.0.5",
"@types/usb": "^1.1.2",
@@ -47,8 +48,10 @@
"@ngrx/store": "2.2.1",
"bootstrap": "^3.3.7",
"browser-stdout": "^1.3.0",
+ "buffer": "^5.0.3",
"core-js": "2.4.1",
"dragula": "^3.7.2",
+ "filesaver.js": "^0.2.0",
"font-awesome": "^4.6.3",
"jquery": "3.1.1",
"json-loader": "^0.5.4",
diff --git a/shared/src/components/keymap/edit/keymap-edit.component.html b/shared/src/components/keymap/edit/keymap-edit.component.html
index 6d39d7b2..3f0dd2da 100644
--- a/shared/src/components/keymap/edit/keymap-edit.component.html
+++ b/shared/src/components/keymap/edit/keymap-edit.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/shared/src/components/keymap/edit/keymap-edit.component.ts b/shared/src/components/keymap/edit/keymap-edit.component.ts
index b9317969..2bf948bf 100644
--- a/shared/src/components/keymap/edit/keymap-edit.component.ts
+++ b/shared/src/components/keymap/edit/keymap-edit.component.ts
@@ -4,14 +4,18 @@ import { ActivatedRoute } from '@angular/router';
import '@ngrx/core/add/operator/select';
import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/first';
import 'rxjs/add/operator/let';
+import 'rxjs/add/operator/map';
import 'rxjs/add/operator/publishReplay';
import 'rxjs/add/operator/switchMap';
-import { Observable } from 'rxjs/Observable';
+
+import { saveAs } from 'file-saver';
import { Keymap } from '../../../config-serializer/config-items/Keymap';
import { AppState } from '../../../store';
-import { getKeymap, getKeymaps } from '../../../store/reducers/user-configuration';
+import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
@Component({
selector: 'keymap-edit',
@@ -41,4 +45,35 @@ export class KeymapEditComponent {
.map((keymaps: Keymap[]) => keymaps.length > 1);
}
+ downloadKeymap() {
+ const exportableJSON$: Observable = this.keymap$
+ .switchMap(keymap => this.toExportableJSON(keymap))
+ .map(exportableJSON => JSON.stringify(exportableJSON));
+
+ this.keymap$
+ .combineLatest(exportableJSON$)
+ .first()
+ .subscribe(latest => {
+ const keymap = latest[0];
+ const exportableJSON = latest[1];
+ const fileName = keymap.name + '_keymap.json';
+ saveAs(new Blob([exportableJSON], { type: 'application/json' }), fileName);
+ });
+ }
+
+ private toExportableJSON(keymap: Keymap): Observable {
+ return this.store
+ .let(getUserConfiguration())
+ .first()
+ .map(userConfiguration => {
+ return {
+ site: 'https://ultimatehackingkeyboard.com',
+ description: 'Ultimate Hacking Keyboard keymap',
+ keyboardModel: 'UHK60',
+ dataModelVersion: userConfiguration.dataModelVersion,
+ objectType: 'keymap',
+ objectValue: keymap.toJsonObject()
+ };
+ });
+ }
}
diff --git a/shared/src/components/keymap/header/keymap-header.component.html b/shared/src/components/keymap/header/keymap-header.component.html
index 572f4b2b..b1d7122e 100644
--- a/shared/src/components/keymap/header/keymap-header.component.html
+++ b/shared/src/components/keymap/header/keymap-header.component.html
@@ -34,5 +34,6 @@
data-original-title="Duplicate keymap"
(click)="duplicateKeymap()"
>
+
\ No newline at end of file
diff --git a/shared/src/components/keymap/header/keymap-header.component.scss b/shared/src/components/keymap/header/keymap-header.component.scss
index ce3eda58..e33b1461 100644
--- a/shared/src/components/keymap/header/keymap-header.component.scss
+++ b/shared/src/components/keymap/header/keymap-header.component.scss
@@ -43,6 +43,18 @@
}
}
+.layer__download {
+ top: 10px;
+ font-size: 0.8em;
+ position: relative;
+ margin-right: 10px;
+
+ &:hover {
+ cursor: pointer;
+ color: $icon-hover;
+ }
+}
+
.pane-title {
margin-bottom: 1em;
diff --git a/shared/src/components/keymap/header/keymap-header.component.ts b/shared/src/components/keymap/header/keymap-header.component.ts
index 7ed69ba1..fde6edcd 100644
--- a/shared/src/components/keymap/header/keymap-header.component.ts
+++ b/shared/src/components/keymap/header/keymap-header.component.ts
@@ -3,6 +3,8 @@ import {
Component,
ElementRef,
Input,
+ Output,
+ EventEmitter,
OnChanges,
Renderer,
SimpleChanges,
@@ -25,6 +27,7 @@ import { KeymapActions } from '../../../store/actions';
export class KeymapHeaderComponent implements OnChanges {
@Input() keymap: Keymap;
@Input() deletable: boolean;
+ @Output() downloadClick = new EventEmitter();
@ViewChild('name') keymapName: ElementRef;
@ViewChild('abbr') keymapAbbr: ElementRef;
@@ -87,4 +90,8 @@ export class KeymapHeaderComponent implements OnChanges {
setTrashTitle(): void {
this.trashTitle = this.deletable ? '' : 'The last keymap cannot be deleted.';
}
+
+ onDownloadIconClick(): void {
+ this.downloadClick.emit();
+ }
}
diff --git a/shared/src/config-serializer/config-items/Module.ts b/shared/src/config-serializer/config-items/Module.ts
index 39f194c5..22cff961 100644
--- a/shared/src/config-serializer/config-items/Module.ts
+++ b/shared/src/config-serializer/config-items/Module.ts
@@ -3,6 +3,7 @@ import { UhkBuffer } from '../UhkBuffer';
import { Helper as KeyActionHelper, KeyAction, NoneAction } from './key-action';
import { Keymap } from './Keymap';
import { Macro } from './Macro';
+import { PlayMacroAction, SwitchLayerAction } from './key-action';
enum PointerRole {
none,
@@ -54,7 +55,7 @@ export class Module {
id: this.id,
pointerRole: PointerRole[this.pointerRole],
keyActions: this.keyActions.map(keyAction => {
- if (keyAction) {
+ if (keyAction && (macros || !(keyAction instanceof PlayMacroAction || keyAction instanceof SwitchLayerAction))) {
return keyAction.toJsonObject(macros);
}
})
diff --git a/web/src/tsconfig.json b/web/src/tsconfig.json
index ce2ea70b..b4d65ff0 100644
--- a/web/src/tsconfig.json
+++ b/web/src/tsconfig.json
@@ -16,7 +16,8 @@
"node",
"jquery",
"core-js",
- "select2"
+ "select2",
+ "file-saver"
]
},
"exclude": [
diff --git a/web/src/vendor.ts b/web/src/vendor.ts
new file mode 100644
index 00000000..91896cec
--- /dev/null
+++ b/web/src/vendor.ts
@@ -0,0 +1,3 @@
+import './shared/vendor.ts';
+
+import 'buffer';
diff --git a/web/src/webpack.config.js b/web/src/webpack.config.js
index bc39e051..3086cea6 100644
--- a/web/src/webpack.config.js
+++ b/web/src/webpack.config.js
@@ -11,7 +11,7 @@ console.log(rootDir, __dirname);
module.exports = {
entry: {
polyfills: path.resolve(rootDir, 'src/shared/polyfills.ts'),
- vendor: path.resolve(rootDir, 'src/shared/vendor.ts'),
+ vendor: path.resolve(rootDir, 'src/vendor.ts'),
app: path.resolve(rootDir, 'src/main.ts')
},
output: {
@@ -24,7 +24,8 @@ module.exports = {
modules: [path.join(rootDir, "node_modules")],
alias: {
jquery: 'jquery/dist/jquery.min.js',
- select2: 'select2/dist/js/select2.full.min.js'
+ select2: 'select2/dist/js/select2.full.min.js',
+ 'file-saver': 'filesaver.js/FileSaver.min.js'
}
},
module: {