diff --git a/shared/src/components/keymap/header/keymap-header.component.html b/shared/src/components/keymap/header/keymap-header.component.html index e5c712f6..e6d684c0 100644 --- a/shared/src/components/keymap/header/keymap-header.component.html +++ b/shared/src/components/keymap/header/keymap-header.component.html @@ -5,14 +5,12 @@ keymap (, private renderer: Renderer) { } + constructor(private store: Store, private renderer: Renderer2) { } ngOnChanges(changes: SimpleChanges) { if (changes['keymap']) { this.setKeymapTitle(); + this.setName(); + this.setAbbreviation(); } if (changes['deletable']) { this.setTrashTitle(); @@ -64,7 +66,7 @@ export class KeymapHeaderComponent implements OnChanges { editKeymapName(name: string) { if (name.length === 0) { - this.renderer.setElementProperty(this.keymapName.nativeElement, 'value', this.keymap.name); + this.setName(); return; } @@ -75,12 +77,12 @@ export class KeymapHeaderComponent implements OnChanges { const regexp = new RegExp(/^[a-zA-Z\d]+$/g); if (newAbbr.length < 1 || newAbbr.length > 3 || !regexp.test(newAbbr)) { - this.renderer.setElementProperty(this.keymapAbbr.nativeElement, 'value', this.keymap.abbreviation); + this.setAbbreviation(); return; } newAbbr = newAbbr.toUpperCase(); - this.store.dispatch(KeymapActions.editKeymapAbbr(this.keymap.abbreviation, newAbbr)); + this.store.dispatch(KeymapActions.editKeymapAbbr(this.keymap.name, this.keymap.abbreviation, newAbbr)); } setKeymapTitle(): void { @@ -96,4 +98,12 @@ export class KeymapHeaderComponent implements OnChanges { onDownloadIconClick(): void { this.downloadClick.emit(); } + + private setName(): void { + this.renderer.setProperty(this.keymapName.nativeElement, 'value', this.keymap.name); + } + + private setAbbreviation() { + this.renderer.setProperty(this.keymapAbbr.nativeElement, 'value', this.keymap.abbreviation); + } } diff --git a/shared/src/components/macro/header/macro-header.component.html b/shared/src/components/macro/header/macro-header.component.html index 916d26ee..2f89df39 100644 --- a/shared/src/components/macro/header/macro-header.component.html +++ b/shared/src/components/macro/header/macro-header.component.html @@ -5,7 +5,6 @@ diff --git a/shared/src/components/macro/header/macro-header.component.ts b/shared/src/components/macro/header/macro-header.component.ts index 3e038d99..c60f737a 100644 --- a/shared/src/components/macro/header/macro-header.component.ts +++ b/shared/src/components/macro/header/macro-header.component.ts @@ -1,5 +1,12 @@ import { - AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, Renderer, + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnChanges, + Renderer2, + SimpleChanges, ViewChild } from '@angular/core'; @@ -21,17 +28,20 @@ export class MacroHeaderComponent implements AfterViewInit, OnChanges { @Input() isNew: boolean; @ViewChild('macroName') macroName: ElementRef; - constructor(private store: Store, private renderer: Renderer) { } + constructor(private store: Store, private renderer: Renderer2) { } - ngOnChanges() { + ngOnChanges(changes: SimpleChanges) { if (this.isNew) { - this.renderer.invokeElementMethod(this.macroName.nativeElement, 'select', []); + this.setFocusOnName(); + } + if (changes['macro']) { + this.setName(); } } ngAfterViewInit() { if (this.isNew) { - this.renderer.invokeElementMethod(this.macroName.nativeElement, 'select', []); + this.setFocusOnName(); } } @@ -45,11 +55,19 @@ export class MacroHeaderComponent implements AfterViewInit, OnChanges { editMacroName(name: string) { if (name.length === 0) { - this.renderer.setElementProperty(this.macroName.nativeElement, 'value', this.macro.name); + this.setName(); return; } this.store.dispatch(MacroActions.editMacroName(this.macro.id, name)); } + private setFocusOnName() { + this.macroName.nativeElement.select(); + } + + private setName(): void { + this.renderer.setProperty(this.macroName.nativeElement, 'value', this.macro.name); + } + } diff --git a/shared/src/store/actions/keymap.ts b/shared/src/store/actions/keymap.ts index d1460174..91944a0d 100644 --- a/shared/src/store/actions/keymap.ts +++ b/shared/src/store/actions/keymap.ts @@ -69,12 +69,13 @@ export namespace KeymapActions { }; } - export function editKeymapAbbr(abbr: string, newAbbr: string): Action { + export function editKeymapAbbr(name: string, abbr: string, newAbbr: string): Action { return { type: KeymapActions.EDIT_ABBR, payload: { - abbr: abbr, - newAbbr: newAbbr + name, + abbr, + newAbbr } }; } diff --git a/shared/src/store/effects/keymap.ts b/shared/src/store/effects/keymap.ts index 0c91e38e..03df04ff 100644 --- a/shared/src/store/effects/keymap.ts +++ b/shared/src/store/effects/keymap.ts @@ -54,9 +54,14 @@ export class KeymapEffects { @Effect({ dispatch: false }) editAbbr$: any = this.actions$ .ofType(KeymapActions.EDIT_ABBR) - .map(action => action.payload.newAbbr) - .do(newAbbr => { - this.router.navigate(['/keymap', newAbbr]); + .withLatestFrom(this.store) + .do(([action, store]) => { + for (const keymap of store.userConfiguration.keymaps) { + if (keymap.name === action.payload.name && keymap.abbreviation === action.payload.newAbbr) { + this.router.navigate(['/keymap', action.payload.newAbbr]); + return; + } + } }); constructor(private actions$: Actions, private router: Router, private store: Store) { } diff --git a/shared/src/store/effects/macro.ts b/shared/src/store/effects/macro.ts index 2a3448fe..5365c416 100644 --- a/shared/src/store/effects/macro.ts +++ b/shared/src/store/effects/macro.ts @@ -14,11 +14,11 @@ import { AppState } from '../index'; @Injectable() export class MacroEffects { - @Effect({dispatch: false}) remove$: any = this.actions$ + @Effect({ dispatch: false }) remove$: any = this.actions$ .ofType(MacroActions.REMOVE) .map(action => this.store.dispatch(KeymapActions.checkMacro(action.payload))) .withLatestFrom(this.store) - .map(latest => latest[1].userConfiguration.macros) + .map(([action, state]) => state.userConfiguration.macros) .do(macros => { if (macros.length === 0) { this.router.navigate(['/macro']); @@ -27,14 +27,23 @@ export class MacroEffects { } }); - @Effect({dispatch: false}) add$: any = this.actions$ + @Effect({ dispatch: false }) add$: any = this.actions$ .ofType(MacroActions.ADD) .withLatestFrom(this.store) - .map(latest => latest[1].userConfiguration.macros) + .map(([action, state]) => state.userConfiguration.macros) .map(macros => macros[macros.length - 1]) .do(lastMacro => { this.router.navigate(['/macro', lastMacro.id, 'new']); }); + @Effect({ dispatch: false }) duplicate: any = this.actions$ + .ofType(MacroActions.DUPLICATE) + .withLatestFrom(this.store) + .map(([action, state]) => state.userConfiguration.macros) + .map(macros => macros[macros.length - 1]) + .do(lastMacro => { + this.router.navigate(['/macro', lastMacro.id]); + }); + constructor(private actions$: Actions, private router: Router, private store: Store) {} } diff --git a/shared/src/store/reducers/user-configuration.ts b/shared/src/store/reducers/user-configuration.ts index 4f1c27d2..6a4806ad 100644 --- a/shared/src/store/reducers/user-configuration.ts +++ b/shared/src/store/reducers/user-configuration.ts @@ -5,7 +5,7 @@ import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/map'; -import { Helper as KeyActionHelper, KeyAction } from '../../config-serializer/config-items/key-action'; +import { Helper as KeyActionHelper } from '../../config-serializer/config-items/key-action'; import { Keymap } from '../../config-serializer/config-items/keymap'; import { Macro } from '../../config-serializer/config-items/macro'; import { UserConfiguration } from '../../config-serializer/config-items/user-configuration'; @@ -26,43 +26,51 @@ export default function (state = initialState, action: Action): UserConfiguratio } case KeymapActions.ADD: - case KeymapActions.DUPLICATE: - { - const newKeymap: Keymap = new Keymap(action.payload); - newKeymap.abbreviation = generateAbbr(state.keymaps, newKeymap.abbreviation); - newKeymap.name = generateName(state.keymaps, newKeymap.name); - newKeymap.isDefault = (state.keymaps.length === 0); + case KeymapActions.DUPLICATE: { + const newKeymap: Keymap = new Keymap(action.payload); + newKeymap.abbreviation = generateAbbr(state.keymaps, newKeymap.abbreviation); + newKeymap.name = generateName(state.keymaps, newKeymap.name); + newKeymap.isDefault = (state.keymaps.length === 0); - changedUserConfiguration.keymaps = state.keymaps.concat(newKeymap); - break; - } - case KeymapActions.EDIT_NAME: - { - const name: string = generateName(state.keymaps, action.payload.name); + changedUserConfiguration.keymaps = state.keymaps.concat(newKeymap); + break; + } + case KeymapActions.EDIT_NAME: { + const name: string = action.payload.name.toUpperCase(); - changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => { - if (keymap.abbreviation === action.payload.abbr) { - keymap = Object.assign(new Keymap(), keymap); - keymap.name = name; - } - return keymap; - }); - break; - } - case KeymapActions.EDIT_ABBR: - const abbr: string = generateAbbr(state.keymaps, action.payload.newAbbr); + const duplicate = state.keymaps.some((keymap: Keymap) => { + return keymap.name === name && keymap.abbreviation !== action.payload.abbr; + }); changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => { - if (keymap.abbreviation === action.payload.abbr) { - keymap = Object.assign(new Keymap(), keymap); + keymap = Object.assign(new Keymap(), keymap); + + if (!duplicate && keymap.abbreviation === action.payload.abbr) { + keymap.name = name; + } + return keymap; + }); + + break; + } + case KeymapActions.EDIT_ABBR: { + const abbr: string = action.payload.newAbbr.toUpperCase(); + + const duplicate = state.keymaps.some((keymap: Keymap) => { + return keymap.name !== action.payload.name && keymap.abbreviation === abbr; + }); + + changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => { + keymap = Object.assign(new Keymap(), keymap); + if (!duplicate && keymap.abbreviation === action.payload.abbr) { keymap.abbreviation = abbr; - } else { - keymap = keymap.renameKeymap(action.payload.abbr, action.payload.newAbbr); } return keymap; }); break; + } + case KeymapActions.SET_DEFAULT: changedUserConfiguration.keymaps = state.keymaps.map((keymap: Keymap) => { if (keymap.abbreviation === action.payload || keymap.isDefault) { @@ -101,33 +109,32 @@ export default function (state = initialState, action: Action): UserConfiguratio }); break; - case KeymapActions.SAVE_KEY: - { - const newKeymap: Keymap = Object.assign(new Keymap(), action.payload.keymap); - newKeymap.layers = newKeymap.layers.slice(); + case KeymapActions.SAVE_KEY: { + const newKeymap: Keymap = Object.assign(new Keymap(), action.payload.keymap); + newKeymap.layers = newKeymap.layers.slice(); - const layerIndex: number = action.payload.layer; - const newLayer: Layer = Object.assign(new Layer(), newKeymap.layers[layerIndex]); - newKeymap.layers[layerIndex] = newLayer; + const layerIndex: number = action.payload.layer; + const newLayer: Layer = Object.assign(new Layer(), newKeymap.layers[layerIndex]); + newKeymap.layers[layerIndex] = newLayer; - const moduleIndex: number = action.payload.module; - const newModule: Module = Object.assign(new Module(), newLayer.modules[moduleIndex]); - newLayer.modules = newLayer.modules.slice(); - newLayer.modules[moduleIndex] = newModule; + const moduleIndex: number = action.payload.module; + const newModule: Module = Object.assign(new Module(), newLayer.modules[moduleIndex]); + newLayer.modules = newLayer.modules.slice(); + newLayer.modules[moduleIndex] = newModule; - const keyIndex: number = action.payload.key; - newModule.keyActions = newModule.keyActions.slice(); - newModule.keyActions[keyIndex] = KeyActionHelper.createKeyAction(action.payload.keyAction); + const keyIndex: number = action.payload.key; + newModule.keyActions = newModule.keyActions.slice(); + newModule.keyActions[keyIndex] = KeyActionHelper.createKeyAction(action.payload.keyAction); - changedUserConfiguration.keymaps = state.keymaps.map(keymap => { - if (keymap.abbreviation === newKeymap.abbreviation) { - keymap = newKeymap; - } + changedUserConfiguration.keymaps = state.keymaps.map(keymap => { + if (keymap.abbreviation === newKeymap.abbreviation) { + keymap = newKeymap; + } - return keymap; - }); - break; - } + return keymap; + }); + break; + } case KeymapActions.CHECK_MACRO: changedUserConfiguration.keymaps = state.keymaps.map(keymap => { keymap = Object.assign(new Keymap(), keymap); @@ -135,41 +142,43 @@ export default function (state = initialState, action: Action): UserConfiguratio return keymap; }); break; - case MacroActions.ADD: - { - const newMacro = new Macro(); - newMacro.id = generateMacroId(state.macros); - newMacro.name = generateName(state.macros, 'New macro'); - newMacro.isLooped = false; - newMacro.isPrivate = true; - newMacro.macroActions = []; + case MacroActions.ADD: { + const newMacro = new Macro(); + newMacro.id = generateMacroId(state.macros); + newMacro.name = generateName(state.macros, 'New macro'); + newMacro.isLooped = false; + newMacro.isPrivate = true; + newMacro.macroActions = []; - changedUserConfiguration.macros = state.macros.concat(newMacro); - break; - } - case MacroActions.DUPLICATE: - { - const newMacro = new Macro(action.payload); - newMacro.name = generateName(state.macros, newMacro.name); - newMacro.id = generateMacroId(state.macros); + changedUserConfiguration.macros = state.macros.concat(newMacro); + break; + } + case MacroActions.DUPLICATE: { + const newMacro = new Macro(action.payload); + newMacro.name = generateName(state.macros, newMacro.name); + newMacro.id = generateMacroId(state.macros); - changedUserConfiguration.macros = state.macros.concat(newMacro); - break; - } - case MacroActions.EDIT_NAME: - { - const name: string = generateName(state.macros, action.payload.name); + changedUserConfiguration.macros = state.macros.concat(newMacro); + break; + } + case MacroActions.EDIT_NAME: { + const name: string = action.payload.name; - changedUserConfiguration.macros = state.macros.map((macro: Macro) => { - if (macro.id === action.payload.id) { - macro.name = name; - } + const duplicate = state.macros.some((macro: Macro) => { + return macro.id !== action.payload.id && macro.name === name; + }); - return macro; - }); + changedUserConfiguration.macros = state.macros.map((macro: Macro) => { + macro = Object.assign(new Macro(), macro); + if (!duplicate && macro.id === action.payload.id) { + macro.name = name; + } - break; - } + return macro; + }); + + break; + } case MacroActions.REMOVE: changedUserConfiguration.macros = state.macros.filter((macro: Macro) => macro.id !== action.payload); break; @@ -274,7 +283,7 @@ export function getMacro(id: number) { } function generateAbbr(keymaps: Keymap[], abbr: string): string { - const chars: string[] = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); + const chars: string[] = '23456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); let position = 0; while (keymaps.some((keymap: Keymap) => keymap.abbreviation === abbr)) { @@ -286,15 +295,15 @@ function generateAbbr(keymaps: Keymap[], abbr: string): string { } function generateName(items: { name: string }[], name: string) { - let suffix = 2; - const oldName: string = name; - - while (items.some(item => item.name === name)) { - name = oldName + ` (${suffix})`; - ++suffix; - } - - return name; + let suffix = 1; + const regexp = / \(\d+\)$/g; + const matchName = name.replace(regexp, ''); + items.forEach(item => { + if (item.name.replace(regexp, '') === matchName) { + suffix++; + } + }); + return `${matchName} (${suffix})`; } function generateMacroId(macros: Macro[]) {