Dock shortcuts
This commit is contained in:
@@ -138,11 +138,68 @@ angular.module('app')
|
|||||||
|
|
||||||
this.componentManager = componentManager;
|
this.componentManager = componentManager;
|
||||||
this.rooms = [];
|
this.rooms = [];
|
||||||
|
this.themes = [];
|
||||||
|
|
||||||
modelManager.addItemSyncObserver("room-bar", "SN|Component", (allItems, validItems, deletedItems, source) => {
|
modelManager.addItemSyncObserver("room-bar", "SN|Component", (allItems, validItems, deletedItems, source) => {
|
||||||
this.rooms = modelManager.components.filter((candidate) => {return candidate.area == "rooms" && !candidate.deleted});
|
this.rooms = modelManager.components.filter((candidate) => {return candidate.area == "rooms" && !candidate.deleted});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelManager.addItemSyncObserver("footer-bar-themes", "SN|Theme", (allItems, validItems, deletedItems, source) => {
|
||||||
|
let themes = modelManager.validItemsForContentType("SN|Theme").filter((candidate) => {return !candidate.deleted}).sort((a, b) => {
|
||||||
|
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
let differ = themes.length != this.themes.length;
|
||||||
|
|
||||||
|
this.themes = themes;
|
||||||
|
|
||||||
|
if(differ) {
|
||||||
|
this.reloadDockShortcuts();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.reloadDockShortcuts = function() {
|
||||||
|
let shortcuts = [];
|
||||||
|
for(var theme of this.themes) {
|
||||||
|
var icon = theme.content.package_info.dock_icon;
|
||||||
|
if(!icon) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
shortcuts.push({
|
||||||
|
component: theme,
|
||||||
|
icon: icon
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dockShortcuts = shortcuts.sort((a, b) => {
|
||||||
|
// circles first, then images
|
||||||
|
|
||||||
|
var aType = a.icon.type;
|
||||||
|
var bType = b.icon.type;
|
||||||
|
|
||||||
|
if(aType == bType) {
|
||||||
|
return 0;
|
||||||
|
} else if(aType == "circle" && bType == "svg") {
|
||||||
|
return -1;
|
||||||
|
} else if(bType == "circle" && aType == "svg") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initSvgForShortcut = function(shortcut) {
|
||||||
|
var id = "dock-svg-" + shortcut.component.uuid;
|
||||||
|
var element = document.getElementById(id);
|
||||||
|
var parser = new DOMParser();
|
||||||
|
var svg = shortcut.component.content.package_info.dock_icon.source;
|
||||||
|
var doc = parser.parseFromString(svg, "image/svg+xml");
|
||||||
|
element.appendChild(doc.documentElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectShortcut = function(shortcut) {
|
||||||
|
componentManager.toggleComponent(shortcut.component);
|
||||||
|
}
|
||||||
|
|
||||||
componentManager.registerHandler({identifier: "roomBar", areas: ["rooms", "modal"], activationHandler: (component) => {
|
componentManager.registerHandler({identifier: "roomBar", areas: ["rooms", "modal"], activationHandler: (component) => {
|
||||||
// RIP: There used to be code here that checked if component.active was true, and if so, displayed the component.
|
// RIP: There used to be code here that checked if component.active was true, and if so, displayed the component.
|
||||||
// However, we no longer want to persist active state for footer extensions. If you open Extensions on one computer,
|
// However, we no longer want to persist active state for footer extensions. If you open Extensions on one computer,
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
angular
|
||||||
|
.module('app')
|
||||||
|
.directive( 'elemReady', function( $parse ) {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function( $scope, elem, attrs ) {
|
||||||
|
elem.ready(function(){
|
||||||
|
$scope.$apply(function(){
|
||||||
|
var func = $parse(attrs.elemReady);
|
||||||
|
func($scope);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -81,6 +81,7 @@ class ComponentView {
|
|||||||
|
|
||||||
// Add small timeout to, as $scope.loading controls loading overlay,
|
// Add small timeout to, as $scope.loading controls loading overlay,
|
||||||
// which is used to avoid flicker when enabling extensions while having an enabled theme
|
// which is used to avoid flicker when enabling extensions while having an enabled theme
|
||||||
|
// we don't use ng-show because it causes problems with rendering iframes after timeout, for some reason.
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
$scope.issueLoading = false;
|
$scope.issueLoading = false;
|
||||||
|
|||||||
@@ -631,22 +631,33 @@ class ComponentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleToggleComponentMessage(sourceComponent, targetComponent, message) {
|
handleToggleComponentMessage(sourceComponent, targetComponent, message) {
|
||||||
if(targetComponent.area == "modal") {
|
this.toggleComponent(targetComponent);
|
||||||
this.openModalComponent(targetComponent);
|
}
|
||||||
|
|
||||||
|
toggleComponent(component) {
|
||||||
|
if(component.area == "modal") {
|
||||||
|
this.openModalComponent(component);
|
||||||
} else {
|
} else {
|
||||||
if(targetComponent.active) {
|
if(component.active) {
|
||||||
this.deactivateComponent(targetComponent);
|
this.deactivateComponent(component);
|
||||||
} else {
|
} else {
|
||||||
if(targetComponent.content_type == "SN|Theme" && !targetComponent.isLayerable()) {
|
if(component.content_type == "SN|Theme") {
|
||||||
// Deactive currently active theme if new theme is not layerable
|
// Deactive currently active theme if new theme is not layerable
|
||||||
var activeThemes = this.getActiveThemes();
|
var activeThemes = this.getActiveThemes();
|
||||||
for(var theme of activeThemes) {
|
|
||||||
if(theme && !theme.isLayerable()) {
|
// Activate current before deactivating others, so as not to flicker
|
||||||
this.deactivateComponent(theme);
|
this.activateComponent(component);
|
||||||
}
|
|
||||||
|
if(!component.isLayerable()) {
|
||||||
|
setTimeout(() => {
|
||||||
|
for(var theme of activeThemes) {
|
||||||
|
if(theme && !theme.isLayerable()) {
|
||||||
|
this.deactivateComponent(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.activateComponent(targetComponent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,20 @@
|
|||||||
z-index: $z-index-footer-bar-item-panel;
|
z-index: $z-index-footer-bar-item-panel;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.dock-shortcut:hover .sk-app-bar-item-column {
|
||||||
|
border-bottom: 2px solid var(--sn-stylekit-info-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
fill: var(--sn-stylekit-foreground-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
fill: var(--sn-stylekit-info-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#account-panel {
|
#account-panel {
|
||||||
@@ -41,6 +55,5 @@ a.disabled {
|
|||||||
|
|
||||||
#footer-lock-icon {
|
#footer-lock-icon {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
padding-left: 8px;
|
padding-left: 5px;
|
||||||
border-left: 1px solid gray;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
.sn-component
|
.sn-component
|
||||||
#footer-bar.sk-app-bar.no-edges
|
#footer-bar.sk-app-bar.no-edges
|
||||||
.left
|
.left
|
||||||
|
|
||||||
.sk-app-bar-item{"ng-click" => "ctrl.accountMenuPressed()", "click-outside" => "ctrl.clickOutsideAccountMenu()", "is-open" => "ctrl.showAccountMenu"}
|
.sk-app-bar-item{"ng-click" => "ctrl.accountMenuPressed()", "click-outside" => "ctrl.clickOutsideAccountMenu()", "is-open" => "ctrl.showAccountMenu"}
|
||||||
.sk-app-bar-item-column
|
.sk-app-bar-item-column
|
||||||
.sk-circle.small{"ng-class" => "ctrl.error ? 'danger' : (ctrl.getUser() ? 'info' : 'neutral')"}
|
.sk-circle.small{"ng-class" => "ctrl.error ? 'danger' : (ctrl.getUser() ? 'info' : 'neutral')"}
|
||||||
@@ -39,6 +40,16 @@
|
|||||||
.sk-app-bar-item{"ng-if" => "!ctrl.offline", "ng-click" => "ctrl.refreshData()"}
|
.sk-app-bar-item{"ng-if" => "!ctrl.offline", "ng-click" => "ctrl.refreshData()"}
|
||||||
.sk-label Refresh
|
.sk-label Refresh
|
||||||
|
|
||||||
|
.sk-app-bar-item.border{"ng-if" => "ctrl.dockShortcuts.length > 0"}
|
||||||
|
|
||||||
|
.sk-app-bar-item.dock-shortcut{"ng-repeat" => "shortcut in ctrl.dockShortcuts"}
|
||||||
|
.sk-app-bar-item-column{"ng-click" => "ctrl.selectShortcut(shortcut)", "ng-class" => "{'underline': shortcut.component.active}"}
|
||||||
|
.div{"ng-if" => "shortcut.icon.type == 'circle'"}
|
||||||
|
.sk-circle.small{"ng-style" => "{'background-color': shortcut.icon.background_color, 'border-color': shortcut.icon.border_color}"}
|
||||||
|
.div{"ng-if" => "shortcut.icon.type == 'svg'"}
|
||||||
|
.svg-item{"ng-attr-id" => "dock-svg-{{shortcut.component.uuid}}", "elem-ready" => "ctrl.initSvgForShortcut(shortcut)"}
|
||||||
|
|
||||||
|
.sk-app-bar-item.border{"ng-if" => "ctrl.hasPasscode()"}
|
||||||
.sk-app-bar-item#lock-item{"ng-if" => "ctrl.hasPasscode()", "title" => "Locks application and wipes unencrypted data from memory."}
|
.sk-app-bar-item#lock-item{"ng-if" => "ctrl.hasPasscode()", "title" => "Locks application and wipes unencrypted data from memory."}
|
||||||
.sk-label
|
.sk-label
|
||||||
%i.icon.ion-locked#footer-lock-icon{"ng-if" => "ctrl.hasPasscode()", "ng-click" => "ctrl.lockApp()"}
|
%i.icon.ion-locked#footer-lock-icon{"ng-if" => "ctrl.hasPasscode()", "ng-click" => "ctrl.lockApp()"}
|
||||||
|
|||||||
Reference in New Issue
Block a user