Merge pull request #290 from standardnotes/3.0.9

3.0.9
This commit is contained in:
Mo Bitar
2019-05-17 11:13:26 -05:00
committed by GitHub
39 changed files with 2561 additions and 1926 deletions

View File

@@ -70,7 +70,7 @@ module.exports = function(grunt) {
},
app: {
src: [
'node_modules/sn-models/dist/sn-models.js',
'node_modules/snjs/dist/snjs.js',
'app/assets/javascripts/app/*.js',
'app/assets/javascripts/app/models/**/*.js',
'app/assets/javascripts/app/controllers/**/*.js',
@@ -136,7 +136,7 @@ module.exports = function(grunt) {
singleQuotes: true,
},
neeto: {
sn: {
files: {
'dist/javascripts/compiled.js': 'dist/javascripts/compiled.js',
},
@@ -149,6 +149,19 @@ module.exports = function(grunt) {
dest: 'dist/javascripts/compiled.min.js'
}
},
ngconstant: {
options: {
name: 'app',
dest: 'app/assets/javascripts/app/constants.js',
deps: false,
constants: {
appVersion: grunt.file.readJSON('package.json').version
}
},
build: {
}
},
});
grunt.loadNpmTasks('grunt-newer');
@@ -162,10 +175,13 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-babel');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-ng-constant');
grunt.registerTask('default', ['haml', 'ngtemplates', 'sass', 'concat:app', 'babel', 'browserify',
'concat:lib', 'concat:dist', 'ngAnnotate', 'concat:css', 'uglify']);
'concat:lib', 'concat:dist', 'ngAnnotate', 'concat:css', 'uglify', 'ngconstant:build']);
grunt.registerTask('vendor', ['concat:app', 'sass', 'babel', 'browserify',
'concat:lib', 'concat:dist', 'ngAnnotate', 'concat:css', 'uglify']);
grunt.registerTask('constants', ['ngconstant:build'])
};

View File

@@ -55,11 +55,6 @@ Array.prototype.containsPrimitiveSubset = function(array) {
return !array.some(val => this.indexOf(val) === -1);
}
/* Use with numbers and strings, not objects */
Array.prototype.containsObjectSubset = function(array) {
return !array.some(val => !_.find(this, val));
}
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, 'includes', {

View File

@@ -0,0 +1,5 @@
angular.module('app')
.constant('appVersion', '3.0.9')
;

View File

@@ -23,7 +23,8 @@ angular.module('app')
}
})
.controller('EditorCtrl', function ($sce, $timeout, authManager, $rootScope, actionsManager,
syncManager, modelManager, themeManager, componentManager, storageManager, sessionHistory, privilegesManager) {
syncManager, modelManager, themeManager, componentManager, storageManager, sessionHistory,
privilegesManager, keyboardManager) {
this.spellcheck = true;
this.componentManager = componentManager;
@@ -121,6 +122,9 @@ angular.module('app')
this.showExtensions = false;
this.showMenu = false;
this.noteStatus = null;
// When setting alt key down and deleting note, an alert will come up and block the key up event when alt is released.
// We reset it on set note so that the alt menu restores to default.
this.altKeyDown = false;
this.loadTagsString();
let onReady = () => {
@@ -796,10 +800,41 @@ angular.module('app')
syncManager.sync();
}
this.altKeyObserver = keyboardManager.addKeyObserver({
modifiers: [KeyboardManager.KeyModifierAlt],
onKeyDown: () => {
$timeout(() => {
this.altKeyDown = true;
})
},
onKeyUp: () => {
$timeout(() => {
this.altKeyDown = false;
});
}
})
this.trashKeyObserver = keyboardManager.addKeyObserver({
key: KeyboardManager.KeyBackspace,
notElementIds: ["note-text-editor", "note-title-editor"],
modifiers: [KeyboardManager.KeyModifierMeta],
onKeyDown: () => {
$timeout(() => {
this.deleteNote();
});
},
})
this.deleteKeyObserver = keyboardManager.addKeyObserver({
key: KeyboardManager.KeyBackspace,
modifiers: [KeyboardManager.KeyModifierMeta, KeyboardManager.KeyModifierShift, KeyboardManager.KeyModifierAlt],
onKeyDown: (event) => {
event.preventDefault();
$timeout(() => {
this.deleteNote(true);
});
},
})
/*
Editor Customization
@@ -810,49 +845,59 @@ angular.module('app')
return;
}
this.loadedTabListener = true;
/**
* Insert 4 spaces when a tab key is pressed,
* only used when inside of the text editor.
* If the shift key is pressed first, this event is
* not fired.
*/
var parent = this;
var handleTab = function (event) {
if (!event.shiftKey && event.which == 9) {
if(parent.note.locked) {
const editor = document.getElementById("note-text-editor");
this.tabObserver = keyboardManager.addKeyObserver({
element: editor,
key: KeyboardManager.KeyTab,
onKeyDown: (event) => {
if(event.shiftKey) {
return;
}
if(this.note.locked) {
return;
}
event.preventDefault();
// Using document.execCommand gives us undo support
if(!document.execCommand("insertText", false, "\t")) {
let insertSuccessful = document.execCommand("insertText", false, "\t");
if(!insertSuccessful) {
// document.execCommand works great on Chrome/Safari but not Firefox
var start = this.selectionStart;
var end = this.selectionEnd;
var start = editor.selectionStart;
var end = editor.selectionEnd;
var spaces = " ";
// Insert 4 spaces
this.value = this.value.substring(0, start)
+ spaces + this.value.substring(end);
editor.value = editor.value.substring(0, start)
+ spaces + editor.value.substring(end);
// Place cursor 4 spaces away from where
// the tab key was pressed
this.selectionStart = this.selectionEnd = start + 4;
editor.selectionStart = editor.selectionEnd = start + 4;
}
parent.note.text = this.value;
parent.changesMade();
$timeout(() => {
this.note.text = editor.value;
this.changesMade({bypassDebouncer: true});
})
},
})
// This handles when the editor itself is destroyed, and not when our controller is destroyed.
angular.element(editor).on('$destroy', function(){
if(this.tabObserver) {
keyboardManager.removeKeyObserver(this.tabObserver);
this.loadedTabListener = false;
}
}
var element = document.getElementById("note-text-editor");
element.addEventListener('keydown', handleTab);
angular.element(element).on('$destroy', function(){
window.removeEventListener('keydown', handleTab);
this.loadedTabListener = false;
}.bind(this))
}.bind(this));
}
});
});

View File

@@ -23,13 +23,14 @@ angular.module('app')
}
})
.controller('NotesCtrl', function (authManager, $timeout, $rootScope, modelManager,
syncManager, storageManager, desktopManager, privilegesManager) {
syncManager, storageManager, desktopManager, privilegesManager, keyboardManager) {
this.panelController = {};
this.searchSubmitted = false;
$rootScope.$on("user-preferences-changed", () => {
this.loadPreferences();
this.reloadNotes();
});
authManager.addEventHandler((event) => {
@@ -335,6 +336,25 @@ angular.module('app')
}
}
this.selectNextNote = function() {
var visibleNotes = this.visibleNotes();
let currentIndex = visibleNotes.indexOf(this.selectedNote);
if(currentIndex + 1 < visibleNotes.length) {
this.selectNote(visibleNotes[currentIndex + 1]);
}
}
this.selectPreviousNote = function() {
var visibleNotes = this.visibleNotes();
let currentIndex = visibleNotes.indexOf(this.selectedNote);
if(currentIndex - 1 >= 0) {
this.selectNote(visibleNotes[currentIndex - 1]);
return true;
} else {
return false;
}
}
this.selectNote = async function(note, viaClick = false) {
if(!note) {
return;
@@ -398,7 +418,6 @@ angular.module('app')
this.noteFilter = {text : ''};
this.onFilterEnter = function() {
// For Desktop, performing a search right away causes input to lose focus.
// We wait until user explicity hits enter before highlighting desktop search results.
@@ -566,4 +585,59 @@ angular.module('app')
return result;
};
/*
Keyboard Shortcuts
*/
// In the browser we're not allowed to override cmd/ctrl + n, so we have to use Control modifier as well.
// These rules don't apply to desktop, but probably better to be consistent.
this.newNoteKeyObserver = keyboardManager.addKeyObserver({
key: "n",
modifiers: [KeyboardManager.KeyModifierMeta, KeyboardManager.KeyModifierCtrl],
onKeyDown: (event) => {
event.preventDefault();
$timeout(() => {
this.createNewNote();
});
}
})
this.getSearchBar = function() {
return document.getElementById("search-bar");
}
this.nextNoteKeyObserver = keyboardManager.addKeyObserver({
key: KeyboardManager.KeyDown,
elements: [document.body, this.getSearchBar()],
onKeyDown: (event) => {
let searchBar = this.getSearchBar();
if(searchBar == document.activeElement) {
searchBar.blur()
}
$timeout(() => {
this.selectNextNote();
});
}
})
this.nextNoteKeyObserver = keyboardManager.addKeyObserver({
key: KeyboardManager.KeyUp,
element: document.body,
onKeyDown: (event) => {
$timeout(() => {
this.selectPreviousNote();
});
}
});
this.searchKeyObserver = keyboardManager.addKeyObserver({
key: "f",
modifiers: [KeyboardManager.KeyModifierMeta, KeyboardManager.KeyModifierShift],
onKeyDown: (event) => {
let searchBar = this.getSearchBar();
if(searchBar) {searchBar.focus()};
}
})
});

View File

@@ -10,9 +10,10 @@ class AccountMenu {
}
controller($scope, $rootScope, authManager, modelManager, syncManager, storageManager, dbManager, passcodeManager,
$timeout, $compile, archiveManager, privilegesManager) {
$timeout, $compile, archiveManager, privilegesManager, appVersion) {
'ngInject';
$scope.appVersion = "v" + appVersion;
$scope.formData = {mergeLocal: true, ephemeral: false};
$scope.user = authManager.user;

View File

@@ -111,15 +111,16 @@ class ComponentView {
}
$timeout.cancel($scope.loadTimeout);
componentManager.registerComponentWindow(component, iframe.contentWindow);
componentManager.registerComponentWindow(component, iframe.contentWindow).then(() => {
// Add small timeout to, as $scope.loading controls loading overlay,
// 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(() => {
$scope.loading = false;
$scope.issueLoading = desktopError; /* Typically we'd just set this to false at this point, but we now account for desktopError */
}, 7)
})
// Add small timeout to, as $scope.loading controls loading overlay,
// 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(() => {
$scope.loading = false;
$scope.issueLoading = desktopError; /* Typically we'd just set this to false at this point, but we now account for desktopError */
}, 7)
};
}
}
@@ -160,7 +161,7 @@ class ComponentView {
$scope.componentValid = false;
componentManager.reloadComponent($scope.component).then(() => {
$scope.reloadStatus();
});
})
}
$scope.reloadStatus = function(doManualReload = true) {

View File

@@ -6,7 +6,7 @@ class PermissionsModal {
this.scope = {
show: "=",
component: "=",
permissions: "=",
permissionsString: "=",
callback: "="
};
}
@@ -31,68 +31,6 @@ class PermissionsModal {
controller($scope, modelManager) {
'ngInject';
$scope.permissionsString = function() {
var finalString = "";
let permissionsCount = $scope.permissions.length;
let addSeparator = (index, length) => {
if(index > 0) {
if(index == length - 1) {
if(length == 2) {
return " and ";
} else {
return ", and "
}
} else {
return ", ";
}
}
return "";
}
$scope.permissions.forEach((permission, index) => {
if(permission.name === "stream-items") {
var types = permission.content_types.map(function(type){
var desc = modelManager.humanReadableDisplayForContentType(type);
if(desc) {
return desc + "s";
} else {
return "items of type " + type;
}
})
var typesString = "";
for(var i = 0;i < types.length;i++) {
var type = types[i];
typesString += addSeparator(i, types.length + permissionsCount - index - 1);
typesString += type;
}
finalString += addSeparator(index, permissionsCount);
finalString += typesString;
if(types.length >= 2 && index < permissionsCount - 1) {
// If you have a list of types, and still an additional root-level permission coming up, add a comma
finalString += ", ";
}
} else if(permission.name === "stream-context-item") {
var mapping = {
"editor-stack" : "working note",
"note-tags" : "working note",
"editor-editor": "working note"
}
finalString += addSeparator(index, permissionsCount, true);
finalString += mapping[$scope.component.area];
}
})
return finalString + ".";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
class KeyboardManager {
constructor() {
this.observers = [];
KeyboardManager.KeyTab = "Tab";
KeyboardManager.KeyBackspace = "Backspace";
KeyboardManager.KeyUp = "ArrowUp";
KeyboardManager.KeyDown = "ArrowDown";
KeyboardManager.KeyModifierShift = "Shift";
KeyboardManager.KeyModifierCtrl = "Control";
// ⌘ key on Mac, ⊞ key on Windows
KeyboardManager.KeyModifierMeta = "Meta";
KeyboardManager.KeyModifierAlt = "Alt";
KeyboardManager.KeyEventDown = "KeyEventDown";
KeyboardManager.KeyEventUp = "KeyEventUp";
KeyboardManager.AllModifiers = [
KeyboardManager.KeyModifierShift,
KeyboardManager.KeyModifierCtrl,
KeyboardManager.KeyModifierMeta,
KeyboardManager.KeyModifierAlt
]
window.addEventListener('keydown', this.handleKeyDown.bind(this));
window.addEventListener('keyup', this.handleKeyUp.bind(this));
}
modifiersForEvent(event) {
let eventModifiers = KeyboardManager.AllModifiers.filter((modifier) => {
// For a modifier like ctrlKey, must check both event.ctrlKey and event.key.
// That's because on keyup, event.ctrlKey would be false, but event.key == Control would be true.
let matches = (
((event.ctrlKey || event.key == KeyboardManager.KeyModifierCtrl) && modifier === KeyboardManager.KeyModifierCtrl) ||
((event.metaKey || event.key == KeyboardManager.KeyModifierMeta) && modifier === KeyboardManager.KeyModifierMeta) ||
((event.altKey || event.key == KeyboardManager.KeyModifierAlt) && modifier === KeyboardManager.KeyModifierAlt) ||
((event.shiftKey || event.key == KeyboardManager.KeyModifierShift) && modifier === KeyboardManager.KeyModifierShift)
)
return matches;
})
return eventModifiers;
}
eventMatchesKeyAndModifiers(event, key, modifiers = []) {
let eventModifiers = this.modifiersForEvent(event);
if(eventModifiers.length != modifiers.length) {
return false;
}
for(let modifier of modifiers) {
if(!eventModifiers.includes(modifier)) {
return false;
}
}
// Modifers match, check key
if(!key) {
return true;
}
// In the browser, shift + f results in key 'f', but in Electron, shift + f results in 'F'
// In our case we don't differentiate between the two.
return key.toLowerCase() == event.key.toLowerCase();
}
notifyObserver(event, keyEventType) {
for(let observer of this.observers) {
if(observer.element && event.target != observer.element) {
continue;
}
if(observer.elements && !observer.elements.includes(event.target)) {
continue;
}
if(observer.notElement && observer.notElement == event.target) {
continue;
}
if(observer.notElementIds && observer.notElementIds.includes(event.target.id)) {
continue;
}
if(this.eventMatchesKeyAndModifiers(event, observer.key, observer.modifiers)) {
let callback = keyEventType == KeyboardManager.KeyEventDown ? observer.onKeyDown : observer.onKeyUp;
if(callback) {
callback(event);
}
}
}
}
handleKeyDown(event) {
this.notifyObserver(event, KeyboardManager.KeyEventDown);
}
handleKeyUp(event) {
this.notifyObserver(event, KeyboardManager.KeyEventUp);
}
addKeyObserver({key, modifiers, onKeyDown, onKeyUp, element, elements, notElement, notElementIds}) {
let observer = {key, modifiers, onKeyDown, onKeyUp, element, elements, notElement, notElementIds};
this.observers.push(observer);
return observer;
}
removeKeyObserver(observer) {
this.observers.splice(this.observers.indexOf(observer), 1);
}
}
angular.module('app').service('keyboardManager', KeyboardManager);

View File

@@ -41,6 +41,13 @@ class NativeExtManager {
}
}
// Handle addition of SN|ExtensionRepo permission
let permission = resolvedSingleton.content.permissions.find((p) => p.name == "stream-items");
if(!permission.content_types.includes("SN|ExtensionRepo")) {
permission.content_types.push("SN|ExtensionRepo");
needsSync = true;
}
if(needsSync) {
resolvedSingleton.setDirty(true);
this.syncManager.sync();
@@ -68,7 +75,10 @@ class NativeExtManager {
permissions: [
{
name: "stream-items",
content_types: ["SN|Component", "SN|Theme", "SF|Extension", "Extension", "SF|MFA", "SN|Editor"]
content_types: [
"SN|Component", "SN|Theme", "SF|Extension",
"Extension", "SF|MFA", "SN|Editor", "SN|ExtensionRepo"
]
}
]
}
@@ -141,7 +151,12 @@ class NativeExtManager {
permissions: [
{
name: "stream-items",
content_types: ["Note", "Tag", "SN|Component", "SN|Theme", "SF|Extension", "Extension", "SF|MFA", "SN|Editor", "SN|UserPreferences"]
content_types: [
"Note", "Tag", "SN|SmartTag",
"SN|Component", "SN|Theme", "SN|UserPreferences",
"SF|Extension", "Extension", "SF|MFA", "SN|Editor",
"SN|FileSafe|Credentials", "SN|FileSafe|FileMetadata", "SN|FileSafe|Integration"
]
}
]
}

View File

@@ -108,6 +108,7 @@ $heading-height: 75px;
overflow-y: hidden;
height: 100%;
display: flex;
tab-size: 2;
background-color: var(--sn-stylekit-background-color);
position: relative;
@@ -135,6 +136,8 @@ $heading-height: 75px;
#editor-pane-component-stack {
width: 100%;
// To keep glued to bottom when editor is in loading state and not visible.
margin-top: auto;
// When two component stack items are expired and eat up full screen, this is required to scroll them.
// overflow: auto;

View File

@@ -20,7 +20,7 @@
#notes-title-bar {
padding-top: 16px;
font-weight: normal;
font-size: 18px;
font-size: var(--sn-stylekit-font-size-h1);
.section-title-bar-header .title {
color: var(--sn-stylekit-neutral-color);
@@ -35,7 +35,7 @@
.filter-section {
clear: left;
height: 32px;
height: 29px;
margin-top: 14px;
position: relative;
@@ -46,7 +46,7 @@
color: #909090;
text-align: center;
font-weight: normal;
font-size: 16px;
font-size: var(--sn-stylekit-font-size-h3);
line-height: 35px;
border: none;
@@ -120,8 +120,9 @@
}
.note-preview {
font-size: 15px;
margin-top: 1px;
font-size: var(--sn-stylekit-font-size-h3);
margin-top: 2px;
overflow: hidden;
text-overflow: ellipsis;
@@ -140,12 +141,6 @@
}
}
.preview-hidden {
font-size: 14px;
margin-top: 2px;
opacity: 0.6;
}
.note-flag {
color: var(--sn-stylekit-info-color);
}

View File

@@ -53,12 +53,22 @@
> .tag-info {
height: 20px;
display: flex;
flex-direction: row;
align-items: center;
> .tag-icon {
width: 10px;
opacity: 0.2;
font-size: var(--sn-stylekit-font-size-h2);
font-weight: bold;
margin-right: 6px;
}
> .title {
width: 80%;
background-color: transparent;
font-weight: 600;
float: left;
color: var(--sn-stylekit-secondary-foreground-color);
border: none;
cursor: pointer;

View File

@@ -194,7 +194,9 @@
.sk-panel-row
.sk-spinner.small.info{"ng-if" => "importData.loading"}
.sk-panel-footer
%a.sk-a.right{"ng-if" => "formData.showLogin || formData.showRegister", "ng-click" => "formData.showLogin = false; formData.showRegister = false;"}
Cancel
%a.sk-a.right.danger{"ng-if" => "!formData.showLogin && !formData.showRegister", "ng-click" => "destroyLocalData()"}
{{ user ? "Sign out and clear local data" : "Clear all local data" }}
.sk-panel-row
.sk-p.left.neutral.faded {{appVersion}}
%a.sk-a.right{"ng-if" => "formData.showLogin || formData.showRegister", "ng-click" => "formData.showLogin = false; formData.showRegister = false;"}
Cancel
%a.sk-a.right.danger{"ng-if" => "!formData.showLogin && !formData.showRegister", "ng-click" => "destroyLocalData()"}
{{ user ? "Sign out and clear local data" : "Clear all local data" }}

View File

@@ -12,7 +12,7 @@
.sk-h2
%strong {{component.name}}
would like to interact with your
{{permissionsString()}}
{{permissionsString}}
.sk-panel-row
%p.sk-p

View File

@@ -38,13 +38,13 @@
%menu-row{"label" => "ctrl.note.locked ? 'Unlock' : 'Lock'", "action" => "ctrl.selectedMenuItem(true); ctrl.toggleLockNote()", "desc" => "'Locking notes prevents unintentional editing'"}
%menu-row{"label" => "ctrl.note.content.protected ? 'Unprotect' : 'Protect'", "action" => "ctrl.selectedMenuItem(true); ctrl.toggleProtectNote()", "desc" => "'Protecting a note will require credentials to view it (Manage Privileges via Account menu)'"}
%menu-row{"label" => "'Preview'", "circle" => "ctrl.note.content.hidePreview ? 'danger' : 'success'", "circle-align" => "'right'", "action" => "ctrl.selectedMenuItem(true); ctrl.toggleNotePreview()", "desc" => "'Hide or unhide the note preview from the list of notes'"}
%menu-row{"ng-show" => "!ctrl.note.content.trashed && !ctrl.note.errorDecrypting", "label" => "'Move to Trash'", "action" => "ctrl.selectedMenuItem(); ctrl.deleteNote()", "stylekit-class" => "'warning'", "desc" => "'Send this note to the trash'"}
%menu-row{"ng-show" => "!ctrl.altKeyDown && !ctrl.note.content.trashed && !ctrl.note.errorDecrypting", "label" => "'Move to Trash'", "action" => "ctrl.selectedMenuItem(); ctrl.deleteNote()", "stylekit-class" => "'warning'", "desc" => "'Send this note to the trash'"}
%menu-row{"ng-show" => "!ctrl.note.content.trashed && ctrl.note.errorDecrypting", "label" => "'Delete Permanently'", "action" => "ctrl.selectedMenuItem(); ctrl.deleteNotePermanantely()", "stylekit-class" => "'danger'", "desc" => "'Delete this note permanently from all your devices'"}
%div{"ng-if" => "ctrl.note.content.trashed"}
%menu-row{"label" => "'Restore'", "action" => "ctrl.selectedMenuItem(true); ctrl.restoreTrashedNote()", "stylekit-class" => "'info'", "desc" => "'Undelete this note and restore it back into your notes'"}
%div{"ng-if" => "ctrl.note.content.trashed || ctrl.altKeyDown"}
%menu-row{"label" => "'Restore'", "ng-show" => "ctrl.note.content.trashed", "action" => "ctrl.selectedMenuItem(true); ctrl.restoreTrashedNote()", "stylekit-class" => "'info'", "desc" => "'Undelete this note and restore it back into your notes'"}
%menu-row{"label" => "'Delete Permanently'", "action" => "ctrl.selectedMenuItem(true); ctrl.deleteNotePermanantely()", "stylekit-class" => "'danger'", "desc" => "'Delete this note permanently from all your devices'"}
%menu-row{"label" => "'Empty Trash'", "subtitle" => "ctrl.getTrashCount() + ' notes in trash'", "action" => "ctrl.selectedMenuItem(true); ctrl.emptyTrash()", "stylekit-class" => "'danger'", "desc" => "'Permanently delete all notes in the trash'"}
%menu-row{"label" => "'Empty Trash'", "ng-show" => "ctrl.note.content.trashed || !ctrl.altKeyDown", "subtitle" => "ctrl.getTrashCount() + ' notes in trash'", "action" => "ctrl.selectedMenuItem(true); ctrl.emptyTrash()", "stylekit-class" => "'danger'", "desc" => "'Permanently delete all notes in the trash'"}
.sk-menu-panel-section
.sk-menu-panel-header

View File

@@ -8,7 +8,7 @@
.sk-label
%i.icon.ion-plus.add-button
.filter-section{"role" => "search"}
%input.filter-bar#search-bar.mousetrap{"select-on-click" => "true", "ng-model" => "ctrl.noteFilter.text", "placeholder" => "Search",
%input.filter-bar#search-bar{"select-on-click" => "true", "ng-model" => "ctrl.noteFilter.text", "placeholder" => "Search",
"ng-change" => "ctrl.filterTextChanged()", "lowercase" => "true", "ng-blur" => "ctrl.onFilterEnter()", "ng-keyup" => "$event.keyCode == 13 && ctrl.onFilterEnter();",
"title" => "Searches notes in the currently selected tag"}
#search-clear-button{"ng-show" => "ctrl.noteFilter.text", "ng-click" => "ctrl.clearFilterText();"} ✕
@@ -56,7 +56,8 @@
.name{"ng-show" => "note.title"}
{{note.title}}
.note-preview{"ng-show" => "!ctrl.hideNotePreview && !note.content.hidePreview && !note.content.protected"}
-# Use ng-if and not ng-show here. We don't want previews in the dom at all if protected.
.note-preview{"ng-if" => "!ctrl.hideNotePreview && !note.content.hidePreview && !note.content.protected"}
.html-preview{"ng-show" => "note.content.preview_html", "ng-bind-html" => "note.content.preview_html"}
.plain-preview{"ng-show" => "!note.content.preview_html && note.content.preview_plain"} {{note.content.preview_plain}}
.default-preview{"ng-show" => "!note.content.preview_html && !note.content.preview_plain"} {{note.text}}

View File

@@ -26,6 +26,7 @@
%span.sk-bold Tags
.tag{"ng-repeat" => "tag in ctrl.tags track by tag.uuid", "ng-click" => "ctrl.selectTag(tag)", "ng-class" => "{'selected' : ctrl.selectedTag == tag}"}
.tag-info
.tag-icon #
%input.title{"ng-class" => "{'editing' : ctrl.editingTag == tag}", "ng-attr-id" => "tag-{{tag.uuid}}", "ng-click" => "ctrl.selectTag(tag)", "ng-model" => "tag.title",
"ng-keyup" => "$event.keyCode == 13 && $event.target.blur()", "sn-autofocus" => "true", "should-focus" => "ctrl.newTag || ctrl.editingTag == tag",
"ng-change" => "ctrl.tagTitleDidChange(tag)", "ng-blur" => "ctrl.saveTag($event, tag)", "spellcheck" => "false"}

View File

@@ -8,7 +8,7 @@
<link href="favicon/apple-touch-icon.png" rel="apple-touch-icon" sizes="180x180"></link>
<link href="favicon/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png"></link>
<link href="favicon/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png"></link>
<link href="favicon/manifest.json" rel="manifest"></link>
<link href="favicon/site.webmanifest" rel="manifest"></link>
<link color="#5bbad5" href="favicon/safari-pinned-tab.svg" rel="mask-icon"></link>
<meta name="theme-color" content="#ffffff">
@@ -17,7 +17,7 @@
<meta ng-bind="title" content="Standard Notes" name="application-name"/>
<base href="/"></base>
<title>Notes — Standard Notes</title>
<title>Notes · Standard Notes</title>
<meta name="description" content="Standard Notes is a basic notes app that delivers only the essentials in note taking. Because of its simplicity and resistance to growth, users can count on durability and convenience."/>
<meta name="twitter:title" content="Standard Notes, a private and secure notes app."/>

View File

@@ -14,7 +14,7 @@ require "rails/test_unit/railtie"
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Neeto
module StandardNotes
class Application < Rails::Application
# Cross-Origin Resource Sharing (CORS) for Rack compatible web applications.
config.middleware.insert_before 0, Rack::Cors do

View File

@@ -1,15 +1,15 @@
default: &default
key_path: /path/to/key.pem
repo_url: https://github.com/neeto-project/neeto-web-client.git
repo_url: https://github.com/sn-project/sn-web-client.git
user: ssh_username
staging:
<<: *default
server: staging.yourdomain.com
branch: staging
deploy_to: ~/neeto-staging-client
deploy_to: ~/sn-staging-client
production:
<<: *default
server: yourdomain.com
deploy_to: ~/neeto-prod-client
deploy_to: ~/sn-prod-client

View File

@@ -1,6 +1,6 @@
CAP_CONFIG = YAML.load_file("config/cap.yml")
set :application, 'neeto'
set :application, 'standard-notes'
set :repo_url, CAP_CONFIG["default"]["repo_url"]
# Default branch is :master

View File

@@ -1,3 +1,3 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_neeto_session'
Rails.application.config.session_store :cookie_store, key: '_sn_session'

2804
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "standard-notes-web",
"version": "3.0.8",
"version": "3.0.9",
"license": "AGPL-3.0-or-later",
"repository": {
"type": "git",
@@ -34,11 +34,12 @@
"grunt-haml2html": "^0.3.1",
"grunt-newer": "^1.2.0",
"grunt-ng-annotate": "^3.0.0",
"grunt-ng-constant": "^2.0.2",
"grunt-shell": "^2.1.0",
"mocha": "^5.2.0",
"serve-static": "^1.13.2",
"sn-models": "0.1.14",
"sn-stylekit": "2.0.13",
"standard-file-js": "0.3.57",
"grunt-shell": "^2.1.0"
"sn-stylekit": "2.0.14",
"snjs": "0.2.1",
"standard-file-js": "0.3.58"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -2,7 +2,7 @@
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<square150x150logo src="favicon/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,16.000000) scale(0.003200,-0.003200)"
fill="#000000" stroke="none">
<path d="M230 2490 l0 -2270 2270 0 2270 0 0 2270 0 2270 -2270 0 -2270 0 0
-2270z m4340 0 l0 -2070 -2070 0 -2070 0 0 2070 0 2070 2070 0 2070 0 0 -2070z"/>
<path d="M2368 3475 c-2 -1 -23 -5 -48 -8 -298 -37 -515 -205 -603 -467 -14
-41 -29 -91 -33 -110 -4 -19 -9 -328 -11 -687 l-4 -651 168 1 168 2 2 606 c2
648 4 683 54 782 82 162 231 240 449 234 255 -7 412 -140 454 -387 3 -14 5
-298 5 -632 l1 -606 168 1 167 2 0 645 c-1 634 -1 646 -23 730 -81 306 -261
468 -597 535 -31 7 -311 15 -317 10z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1005 B

View File

@@ -1,14 +1,15 @@
{
"name": "Standard Notes",
"name": "",
"short_name": "",
"icons": [
{
"src": "/favicon/android-chrome-192x192.png",
"src": "favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicon/android-chrome-384x384.png",
"sizes": "384x384",
"src": "favicon/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],