Resizable panels and user prefs
This commit is contained in:
@@ -36,3 +36,7 @@ function parametersFromURL(url) {
|
||||
function isDesktopApplication() {
|
||||
return window && window.process && window.process.type && window.process.versions["electron"];
|
||||
}
|
||||
|
||||
function isMacApplication() {
|
||||
return window && window.process && window.process.type && window.process.platform == "darwin";
|
||||
}
|
||||
|
||||
@@ -50,13 +50,20 @@ angular.module('app.frontend')
|
||||
this.showMenu = false;
|
||||
this.loadTagsString();
|
||||
|
||||
let onReady = () => {
|
||||
this.noteReady = true;
|
||||
$timeout(() => {
|
||||
this.loadPreferences();
|
||||
})
|
||||
}
|
||||
|
||||
let associatedEditor = this.editorForNote(note);
|
||||
if(associatedEditor) {
|
||||
// setting note to not ready will remove the editor from view in a flash,
|
||||
// so we only want to do this if switching between external editors
|
||||
this.noteReady = false;
|
||||
} else {
|
||||
this.noteReady = true;
|
||||
onReady();
|
||||
}
|
||||
|
||||
if(this.editorComponent && this.editorComponent != associatedEditor) {
|
||||
@@ -71,10 +78,10 @@ angular.module('app.frontend')
|
||||
$timeout(() => {
|
||||
this.enableComponent(associatedEditor);
|
||||
this.editorComponent = associatedEditor;
|
||||
this.noteReady = true;
|
||||
onReady();
|
||||
})
|
||||
} else {
|
||||
this.noteReady = true;
|
||||
onReady();
|
||||
}
|
||||
|
||||
if(note.safeText().length == 0 && note.dummy) {
|
||||
@@ -124,6 +131,10 @@ angular.module('app.frontend')
|
||||
this.note.setAppDataItem("prefersPlainEditor", true);
|
||||
this.note.setDirty(true);
|
||||
syncManager.sync();
|
||||
|
||||
$timeout(() => {
|
||||
this.reloadFont();
|
||||
})
|
||||
}
|
||||
|
||||
this.editorComponent = editorComponent;
|
||||
@@ -322,7 +333,73 @@ angular.module('app.frontend')
|
||||
}
|
||||
|
||||
|
||||
/* Resizability */
|
||||
|
||||
this.resizeControl = {};
|
||||
|
||||
this.onPanelResizeFinish = function(width, left, isMaxWidth) {
|
||||
if(isMaxWidth) {
|
||||
authManager.setUserPrefValue("editorWidth", null);
|
||||
} else {
|
||||
if(width !== undefined && width !== null) {
|
||||
authManager.setUserPrefValue("editorWidth", width);
|
||||
}
|
||||
}
|
||||
|
||||
if(left !== undefined && left !== null) {
|
||||
authManager.setUserPrefValue("editorLeft", left);
|
||||
}
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
$rootScope.$on("user-preferences-changed", () => {
|
||||
this.loadPreferences();
|
||||
});
|
||||
|
||||
this.loadPreferences = function() {
|
||||
this.monospaceFont = authManager.getUserPrefValue("monospaceFont", "monospace");
|
||||
|
||||
if(!document.getElementById("editor-content")) {
|
||||
// Elements have not yet loaded due to ng-if around wrapper
|
||||
return;
|
||||
}
|
||||
|
||||
this.reloadFont();
|
||||
|
||||
let width = authManager.getUserPrefValue("editorWidth", null);
|
||||
if(width !== null) {
|
||||
this.resizeControl.setWidth(width);
|
||||
}
|
||||
|
||||
let left = authManager.getUserPrefValue("editorLeft", null);
|
||||
if(left !== null) {
|
||||
this.resizeControl.setLeft(left);
|
||||
}
|
||||
}
|
||||
|
||||
this.reloadFont = function() {
|
||||
var editable = document.getElementById("note-text-editor");
|
||||
|
||||
if(!editable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.monospaceFont) {
|
||||
if(isMacApplication()) {
|
||||
editable.style.fontFamily = "Menlo, Consolas, 'DejaVu Sans Mono', monospace";
|
||||
} else {
|
||||
editable.style.fontFamily = "monospace";
|
||||
}
|
||||
} else {
|
||||
editable.style.fontFamily = "inherit";
|
||||
}
|
||||
}
|
||||
|
||||
this.toggleKey = function(key) {
|
||||
this[key] = !this[key];
|
||||
authManager.setUserPrefValue(key, this[key], true);
|
||||
this.reloadFont();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,21 +33,61 @@ angular.module('app.frontend')
|
||||
})
|
||||
.controller('NotesCtrl', function (authManager, $timeout, $rootScope, modelManager, storageManager) {
|
||||
|
||||
this.sortBy = storageManager.getItem("sortBy") || "created_at";
|
||||
this.showArchived = storageManager.getBooleanValue("showArchived") || false;
|
||||
this.sortDescending = this.sortBy != "title";
|
||||
this.panelController = {};
|
||||
|
||||
$rootScope.$on("user-preferences-changed", () => {
|
||||
this.loadPreferences();
|
||||
});
|
||||
|
||||
this.loadPreferences = function() {
|
||||
this.sortBy = authManager.getUserPrefValue("sortBy", "created_at");
|
||||
this.sortDescending = this.sortBy != "title";
|
||||
|
||||
this.showArchived = authManager.getUserPrefValue("showArchived", false);
|
||||
this.hidePinned = authManager.getUserPrefValue("hidePinned", false);
|
||||
this.hideNotePreview = authManager.getUserPrefValue("hideNotePreview", false);
|
||||
this.hideDate = authManager.getUserPrefValue("hideDate", false);
|
||||
this.hideTags = authManager.getUserPrefValue("hideTags", false);
|
||||
|
||||
let width = authManager.getUserPrefValue("notesPanelWidth");
|
||||
if(width) {
|
||||
this.panelController.setWidth(width);
|
||||
}
|
||||
}
|
||||
|
||||
this.loadPreferences();
|
||||
|
||||
this.onPanelResize = function(newWidth) {
|
||||
authManager.setUserPrefValue("notesPanelWidth", newWidth);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
angular.element(document).ready(() => {
|
||||
this.loadPreferences();
|
||||
});
|
||||
|
||||
$rootScope.$on("editorFocused", function(){
|
||||
this.showMenu = false;
|
||||
}.bind(this))
|
||||
|
||||
$rootScope.$on("noteDeleted", function() {
|
||||
this.selectFirstNote(false);
|
||||
$timeout(this.onNoteRemoval.bind(this));
|
||||
}.bind(this))
|
||||
|
||||
$rootScope.$on("noteArchived", function() {
|
||||
this.selectFirstNote(false);
|
||||
}.bind(this))
|
||||
$timeout(this.onNoteRemoval.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
|
||||
// When a note is removed from the list
|
||||
this.onNoteRemoval = function() {
|
||||
let visibleNotes = this.visibleNotes();
|
||||
if(this.selectedIndex < visibleNotes.length) {
|
||||
this.selectNote(visibleNotes[this.selectedIndex]);
|
||||
} else {
|
||||
this.selectNote(visibleNotes[visibleNotes.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
this.DefaultNotesToDisplayValue = 20;
|
||||
|
||||
@@ -56,26 +96,39 @@ angular.module('app.frontend')
|
||||
this.notesToDisplay += this.DefaultNotesToDisplayValue
|
||||
}
|
||||
|
||||
this.panelTitle = function() {
|
||||
if(this.noteFilter.text.length) {
|
||||
return `${this.tag.notes.filter((i) => {return i.visible;}).length} search results`;
|
||||
} else if(this.tag) {
|
||||
return `${this.tag.title} notes`;
|
||||
}
|
||||
}
|
||||
|
||||
this.optionsSubtitle = function() {
|
||||
var base = "Sorting by";
|
||||
var base = "";
|
||||
if(this.sortBy == "created_at") {
|
||||
base += " date added";
|
||||
base += " Date Added";
|
||||
} else if(this.sortBy == "updated_at") {
|
||||
base += " date modifed";
|
||||
base += " Date Modifed";
|
||||
} else if(this.sortBy == "title") {
|
||||
base += " title";
|
||||
base += " Title";
|
||||
}
|
||||
|
||||
if(this.showArchived && (!this.tag || !this.tag.archiveTag)) {
|
||||
base += " | Including archived"
|
||||
base += " | + Archived"
|
||||
}
|
||||
|
||||
if(this.hidePinned) {
|
||||
base += " | – Pinned"
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
this.toggleShowArchived = function() {
|
||||
this.showArchived = !this.showArchived;
|
||||
storageManager.setBooleanValue("showArchived", this.showArchived);
|
||||
this.toggleKey = function(key) {
|
||||
this[key] = !this[key];
|
||||
authManager.setUserPrefValue(key, this[key]);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
this.tagDidChange = function(tag, oldTag) {
|
||||
@@ -108,10 +161,14 @@ angular.module('app.frontend')
|
||||
this.selectFirstNote(createNew);
|
||||
}
|
||||
|
||||
this.selectFirstNote = function(createNew) {
|
||||
var visibleNotes = this.sortedNotes.filter(function(note){
|
||||
this.visibleNotes = function() {
|
||||
return this.sortedNotes.filter(function(note){
|
||||
return note.visible;
|
||||
});
|
||||
}
|
||||
|
||||
this.selectFirstNote = function(createNew) {
|
||||
var visibleNotes = this.visibleNotes();
|
||||
|
||||
if(visibleNotes.length > 0) {
|
||||
this.selectNote(visibleNotes[0]);
|
||||
@@ -121,6 +178,7 @@ angular.module('app.frontend')
|
||||
}
|
||||
|
||||
this.selectNote = function(note) {
|
||||
if(!note) { return; }
|
||||
this.selectedNote = note;
|
||||
note.conflict_of = null; // clear conflict
|
||||
this.selectionMade()(note);
|
||||
@@ -142,7 +200,7 @@ angular.module('app.frontend')
|
||||
return note.visible;
|
||||
}
|
||||
|
||||
if(note.archived && !this.showArchived) {
|
||||
if((note.archived && !this.showArchived) || (note.pinned && this.hidePinned)) {
|
||||
note.visible = false;
|
||||
return note.visible;
|
||||
}
|
||||
@@ -188,7 +246,8 @@ angular.module('app.frontend')
|
||||
|
||||
this.setSortBy = function(type) {
|
||||
this.sortBy = type;
|
||||
storageManager.setItem("sortBy", type);
|
||||
authManager.setUserPrefValue("sortBy", this.sortBy);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -34,10 +34,30 @@ angular.module('app.frontend')
|
||||
}
|
||||
}
|
||||
})
|
||||
.controller('TagsCtrl', function ($rootScope, modelManager, $timeout, componentManager) {
|
||||
.controller('TagsCtrl', function ($rootScope, modelManager, $timeout, componentManager, authManager) {
|
||||
|
||||
var initialLoad = true;
|
||||
|
||||
this.panelController = {};
|
||||
|
||||
$rootScope.$on("user-preferences-changed", () => {
|
||||
this.loadPreferences();
|
||||
});
|
||||
|
||||
this.loadPreferences = function() {
|
||||
let width = authManager.getUserPrefValue("tagsPanelWidth");
|
||||
if(width) {
|
||||
this.panelController.setWidth(width);
|
||||
}
|
||||
}
|
||||
|
||||
this.loadPreferences();
|
||||
|
||||
this.onPanelResize = function(newWidth) {
|
||||
authManager.setUserPrefValue("tagsPanelWidth", newWidth);
|
||||
authManager.syncUserPreferences();
|
||||
}
|
||||
|
||||
this.componentManager = componentManager;
|
||||
|
||||
componentManager.registerHandler({identifier: "tags", areas: ["tags-list"], activationHandler: function(component){
|
||||
|
||||
@@ -298,6 +298,7 @@ angular.module('app.frontend')
|
||||
singletonManager.registerSingleton({content_type: prefsContentType}, (resolvedSingleton) => {
|
||||
console.log("AuthManager received resolved UserPreferences", resolvedSingleton);
|
||||
this.userPreferences = resolvedSingleton;
|
||||
this.userPreferencesDidChange();
|
||||
}, () => {
|
||||
// Safe to create. Create and return object.
|
||||
var prefs = new Item({content_type: prefsContentType});
|
||||
@@ -308,5 +309,28 @@ angular.module('app.frontend')
|
||||
return prefs;
|
||||
});
|
||||
|
||||
this.userPreferencesDidChange = function() {
|
||||
$rootScope.$broadcast("user-preferences-changed");
|
||||
}
|
||||
|
||||
this.syncUserPreferences = function() {
|
||||
this.userPreferences.setDirty(true);
|
||||
$rootScope.sync();
|
||||
}
|
||||
|
||||
this.getUserPrefValue = function(key, defaultValue) {
|
||||
if(!this.userPreferences) { return; }
|
||||
var value = this.userPreferences.getAppDataItem(key);
|
||||
return (value !== undefined && value != null) ? value : defaultValue;
|
||||
}
|
||||
|
||||
this.setUserPrefValue = function(key, value, sync) {
|
||||
if(!this.userPreferences) { console.log("Prefs are null, not setting value", key); return; }
|
||||
this.userPreferences.setAppDataItem(key, value);
|
||||
if(sync) {
|
||||
this.syncUserPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
class PanelResizer {
|
||||
|
||||
constructor() {
|
||||
this.restrict = "E";
|
||||
this.templateUrl = "frontend/directives/panel-resizer.html";
|
||||
this.scope = {
|
||||
index: "=",
|
||||
panelId: "=",
|
||||
onResize: "&",
|
||||
onResizeFinish: "&",
|
||||
control: "=",
|
||||
alwaysVisible: "=",
|
||||
minWidth: "=",
|
||||
property: "=",
|
||||
hoverable: "=",
|
||||
collapsable: "="
|
||||
};
|
||||
}
|
||||
|
||||
link(scope, elem, attrs, ctrl) {
|
||||
scope.elem = elem;
|
||||
|
||||
scope.control.setWidth = function(value) {
|
||||
scope.setWidth(value, true);
|
||||
}
|
||||
|
||||
scope.control.setLeft = function(value) {
|
||||
scope.setLeft(value);
|
||||
}
|
||||
}
|
||||
|
||||
controller($scope, $element, modelManager, extensionManager) {
|
||||
'ngInject';
|
||||
|
||||
let panel = document.getElementById($scope.panelId);
|
||||
if(!panel) {
|
||||
console.log("Panel not found for", $scope.panelId);
|
||||
}
|
||||
let resizerColumn = $element[0];
|
||||
let resizerWidth = resizerColumn.offsetWidth;
|
||||
let minWidth = $scope.minWidth || resizerWidth;
|
||||
|
||||
function getParentRect() {
|
||||
return panel.parentNode.getBoundingClientRect();
|
||||
}
|
||||
|
||||
var pressed = false;
|
||||
var startWidth = panel.scrollWidth, startX, lastDownX, collapsed, lastWidth = startWidth, startLeft, lastLeft;
|
||||
let appFrame = document.getElementById("app").getBoundingClientRect();
|
||||
|
||||
if($scope.alwaysVisible) {
|
||||
console.log("Adding always visible", $scope.alwaysVisible);
|
||||
resizerColumn.classList.add("always-visible");
|
||||
}
|
||||
|
||||
if($scope.hoverable) {
|
||||
resizerColumn.classList.add("hoverable");
|
||||
}
|
||||
|
||||
$scope.setWidth = function(width, finish) {
|
||||
if(width < minWidth) {
|
||||
width = minWidth;
|
||||
}
|
||||
|
||||
let parentRect = getParentRect();
|
||||
|
||||
if(width > parentRect.width) {
|
||||
width = parentRect.width;
|
||||
}
|
||||
|
||||
if(width == parentRect.width) {
|
||||
panel.style.width = "100%";
|
||||
panel.style.flexBasis = "100%";
|
||||
} else {
|
||||
panel.style.flexBasis = width + "px";
|
||||
panel.style.width = width + "px";
|
||||
}
|
||||
|
||||
|
||||
lastWidth = width;
|
||||
|
||||
if(finish) {
|
||||
$scope.finishSettingWidth();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.setLeft = function(left) {
|
||||
panel.style.left = left + "px";
|
||||
lastLeft = left;
|
||||
}
|
||||
|
||||
$scope.finishSettingWidth = function() {
|
||||
if(!$scope.collapsable) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(lastWidth <= minWidth) {
|
||||
collapsed = true;
|
||||
} else {
|
||||
collapsed = false;
|
||||
}
|
||||
if(collapsed) {
|
||||
resizerColumn.classList.add("collapsed");
|
||||
} else {
|
||||
resizerColumn.classList.remove("collapsed");
|
||||
}
|
||||
}
|
||||
|
||||
resizerColumn.addEventListener("mousedown", function(event){
|
||||
pressed = true;
|
||||
lastDownX = event.clientX;
|
||||
startWidth = panel.scrollWidth;
|
||||
startLeft = panel.offsetLeft;
|
||||
panel.classList.add("no-selection");
|
||||
|
||||
if($scope.hoverable) {
|
||||
resizerColumn.classList.add("dragging");
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener("mousemove", function(event){
|
||||
if(!pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if($scope.property && $scope.property == 'left') {
|
||||
handleLeftEvent(event);
|
||||
} else {
|
||||
handleWidthEvent(event);
|
||||
}
|
||||
})
|
||||
|
||||
function handleWidthEvent(event) {
|
||||
var rect = panel.getBoundingClientRect();
|
||||
var panelMaxX = rect.left + (startWidth || panel.style.maxWidth);
|
||||
|
||||
var x = event.clientX;
|
||||
|
||||
let deltaX = x - lastDownX;
|
||||
var newWidth = startWidth + deltaX;
|
||||
|
||||
$scope.setWidth(newWidth, false);
|
||||
|
||||
if($scope.onResize()) {
|
||||
$scope.onResize()(lastWidth, panel);
|
||||
}
|
||||
}
|
||||
|
||||
function handleLeftEvent(event) {
|
||||
var panelRect = panel.getBoundingClientRect();
|
||||
var x = event.clientX;
|
||||
let deltaX = x - lastDownX;
|
||||
var newLeft = startLeft + deltaX;
|
||||
if(newLeft < 0) {
|
||||
newLeft = 0;
|
||||
deltaX = -startLeft;
|
||||
}
|
||||
|
||||
let parentRect = getParentRect();
|
||||
|
||||
var newWidth = startWidth - deltaX;
|
||||
if(newWidth < minWidth) {
|
||||
newWidth = minWidth;
|
||||
}
|
||||
|
||||
if(newWidth > parentRect.width) {
|
||||
newWidth = parentRect.width;
|
||||
}
|
||||
|
||||
|
||||
if(newLeft + newWidth > parentRect.width) {
|
||||
newLeft = parentRect.width - newWidth;
|
||||
}
|
||||
|
||||
$scope.setLeft(newLeft, false);
|
||||
$scope.setWidth(newWidth, false);
|
||||
}
|
||||
|
||||
document.addEventListener("mouseup", function(event){
|
||||
if(pressed) {
|
||||
pressed = false;
|
||||
resizerColumn.classList.remove("dragging");
|
||||
panel.classList.remove("no-selection");
|
||||
|
||||
let isMaxWidth = lastWidth == getParentRect().width;
|
||||
|
||||
if($scope.onResizeFinish) {
|
||||
$scope.onResizeFinish()(lastWidth, lastLeft, isMaxWidth);
|
||||
}
|
||||
|
||||
$scope.finishSettingWidth();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module('app.frontend').directive('panelResizer', () => new PanelResizer);
|
||||
Reference in New Issue
Block a user