-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Implement storage selector
- Loading branch information
Showing
22 changed files
with
17,948 additions
and
7,022 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import {VNode} from 'vue'; | ||
import {Component, Prop, Vue} from 'vue-property-decorator'; | ||
import Icons from 'TYPO3/CMS/Backend/Icons'; | ||
|
||
@Component | ||
export default class Icon extends Vue { | ||
@Prop() | ||
identifier!: string; | ||
|
||
private icon: VNode | null = null; | ||
|
||
constructor(props: any) { | ||
super(props); | ||
} | ||
|
||
async mounted(): Promise<any> { | ||
const iconRaw = await Icons.getIcon(this.$props.identifier, Icons.sizes.small, null, null, 'inline'); | ||
this.icon = <span domPropsInnerHTML={iconRaw}></span>; | ||
} | ||
|
||
private render(): VNode | null { | ||
return this.icon; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,114 @@ | ||
import Icon from '@/components/Icon'; | ||
import {Mutations} from '@/enums/Mutations'; | ||
import {StorageInterface} from '@/interfaces/StorageInterface'; | ||
import {Component, Vue} from 'vue-property-decorator'; | ||
import {VNode} from 'vue'; | ||
import {Action} from 'vuex-class'; | ||
import {Action, State} from 'vuex-class'; | ||
|
||
@Component | ||
export default class StorageSelector extends Vue { | ||
@Action(Mutations.SET_STORAGE) | ||
setStorage!: Function; | ||
|
||
@State | ||
storages!: Array<StorageInterface>; | ||
|
||
@State | ||
activeStorage!: StorageInterface; | ||
|
||
constructor(props: any) { | ||
super(props); | ||
} | ||
|
||
private render(): VNode { | ||
private static toggleDropdown(e: Event): void { | ||
const me = (e.target as HTMLElement); | ||
const dropdown = me.closest('.component-dropdown'); | ||
if (dropdown === null) { | ||
return; | ||
} | ||
|
||
let isActive = dropdown.classList.contains('component-dropdown-active'); | ||
dropdown.classList.toggle('component-dropdown-active', !isActive); | ||
dropdown.classList.toggle('component-dropdown-inactive', isActive); | ||
|
||
const dropdownToggle = dropdown.querySelector('.component-dropdown-toggle'); | ||
if (dropdownToggle !== null) { | ||
dropdownToggle.setAttribute('aria-expanded', (!isActive).toString()); | ||
} | ||
} | ||
|
||
private static getBrowsableIdentifier(identifier: number): string { | ||
return identifier + ':/'; | ||
} | ||
|
||
private render(): VNode | null { | ||
if (!this.storages.length) { | ||
return null; | ||
} | ||
|
||
const options = this.storages.map(this.generateOption, this); | ||
return ( | ||
<div class='storage-selector' onchange={this.updateStorage}> | ||
<select class='form-control'> | ||
<option value='1:/'>fileadmin/ (auto-created)</option> | ||
<option value='2:/'>also fileadmin/ (but another ID)</option> | ||
</select> | ||
</div> | ||
<span class='component-dropdown component-dropdown-inactive'> | ||
<button | ||
type='button' | ||
title={TYPO3.lang['StorageSelector.title']} | ||
aria-label={TYPO3.lang['StorageSelector.label']} | ||
class='component-dropdown-toggle' | ||
aria-haspopup='true' | ||
aria-expanded='false' | ||
onclick={StorageSelector.toggleDropdown} | ||
> | ||
<span class='component-dropdown-toggle-icon' role='presentation'> | ||
<Icon identifier={this.activeStorage.icon} /> | ||
</span> | ||
<span class='component-dropdown-toggle-text'> | ||
{this.activeStorage.name} | ||
</span> | ||
<span class='component-dropdown-toggle-icon' role='presentation'> | ||
<Icon identifier='apps-pagetree-expand' /> | ||
</span> | ||
</button> | ||
<div class='component-dropdown-container'> | ||
<ul class='component-dropdown-menu' role='menu'> | ||
{options} | ||
</ul> | ||
</div> | ||
</span> | ||
); | ||
} | ||
|
||
private generateOption(storage: StorageInterface): VNode { | ||
return( | ||
<li class='component-dropdown-menu-item'> | ||
<a | ||
class='component-dropdown-menu-link' | ||
title='{storage.storageName}' | ||
href='#' | ||
data-identifier={storage.identifier} | ||
onclick={this.updateStorage} | ||
> | ||
<span class='component-dropdown-menu-link-icon' role='presentation'> | ||
<Icon identifier={storage.icon} /> | ||
</span> | ||
<span class='component-dropdown-menu-link-text'>{storage.storageName}</span> | ||
</a> | ||
</li> | ||
); | ||
} | ||
|
||
private updateStorage(e: Event): void { | ||
const selectedStorage = (e.target as HTMLSelectElement).selectedOptions[0].value; | ||
this.setStorage(selectedStorage); | ||
const me = (e.target as HTMLElement); | ||
const link = me.closest('a'); | ||
if (link === null || typeof link.dataset.identifier === 'undefined') { | ||
return; | ||
} | ||
|
||
const storageId = parseInt(link.dataset.identifier, 10); | ||
if (storageId !== this.activeStorage.identifier) { | ||
this.setStorage({ | ||
id: storageId, | ||
browsableIdentifier: StorageSelector.getBrowsableIdentifier(storageId), | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
import FolderTreeNode from '@/interfaces/FolderTreeNode'; | ||
|
||
export interface StorageInterface { | ||
folders: Array<FolderTreeNode>; | ||
title: string; | ||
identifier: string; | ||
type: string; | ||
identifier: number; | ||
name: string; | ||
storageName: string; | ||
storageType: string; | ||
storageOnline: boolean; | ||
icon: string; | ||
} |
Oops, something went wrong.