Merge branch 'master' of github.com:standardnotes/web into flexible-content
This commit is contained in:
@@ -40,6 +40,19 @@ angular.module('app')
|
||||
this.loadTagsString();
|
||||
}.bind(this));
|
||||
|
||||
// Right now this only handles offline saving status changes.
|
||||
this.syncStatusObserver = syncManager.registerSyncStatusObserver((status) => {
|
||||
if(status.localError) {
|
||||
$timeout(() => {
|
||||
this.showErrorStatus({
|
||||
message: "Offline Saving Issue",
|
||||
desc: "Changes not saved"
|
||||
});
|
||||
}, 500)
|
||||
} else {
|
||||
}
|
||||
})
|
||||
|
||||
modelManager.addItemSyncObserver("component-manager", "Note", (allItems, validItems, deletedItems, source) => {
|
||||
if(!this.note) { return; }
|
||||
|
||||
@@ -283,10 +296,16 @@ angular.module('app')
|
||||
this.noteStatus = $sce.trustAsHtml(status);
|
||||
}
|
||||
|
||||
this.showErrorStatus = function() {
|
||||
this.showErrorStatus = function(error) {
|
||||
if(!error) {
|
||||
error = {
|
||||
message: "Sync Unreachable",
|
||||
desc: "All changes saved offline"
|
||||
}
|
||||
}
|
||||
this.saveError = true;
|
||||
this.syncTakingTooLong = false;
|
||||
this.noteStatus = $sce.trustAsHtml("<span class='error bold'>Sync Unreachable</span><br>All changes saved offline")
|
||||
this.noteStatus = $sce.trustAsHtml(`<span class='error bold'>${error.message}</span><br>${error.desc}`)
|
||||
}
|
||||
|
||||
this.contentChanged = function() {
|
||||
@@ -488,7 +507,8 @@ angular.module('app')
|
||||
this.tagsComponent = component.active ? component : null;
|
||||
} else if(component.area == "editor-editor") {
|
||||
// An editor is already active, ensure the potential replacement is explicitely enabled for this item
|
||||
if(this.selectedEditor) {
|
||||
// We also check if the selectedEditor is active. If it's inactive, we want to treat it as an external reference wishing to deactivate this editor (i.e componentView)
|
||||
if(this.selectedEditor && this.selectedEditor.active) {
|
||||
if(component.isExplicitlyEnabledForItem(this.note)) {
|
||||
this.selectedEditor = component;
|
||||
}
|
||||
@@ -531,12 +551,20 @@ angular.module('app')
|
||||
if(data.item.content_type == "Tag") {
|
||||
var tag = modelManager.findItem(data.item.uuid);
|
||||
this.addTag(tag);
|
||||
|
||||
// Currently extensions are not notified of association until a full server sync completes.
|
||||
// We need a better system for this, but for now, we'll manually notify observers
|
||||
modelManager.notifySyncObserversOfModels([this.note], ModelManager.MappingSourceLocalSaved);
|
||||
}
|
||||
}
|
||||
|
||||
else if(action === "deassociate-item") {
|
||||
var tag = modelManager.findItem(data.item.uuid);
|
||||
this.removeTag(tag);
|
||||
|
||||
// Currently extensions are not notified of association until a full server sync completes.
|
||||
// We need a better system for this, but for now, we'll manually notify observers
|
||||
modelManager.notifySyncObserversOfModels([this.note], ModelManager.MappingSourceLocalSaved);
|
||||
}
|
||||
|
||||
else if(action === "save-items" || action === "save-success" || action == "save-error") {
|
||||
|
||||
@@ -128,7 +128,7 @@ angular.module('app')
|
||||
if(this.sortBy == "created_at") {
|
||||
base += " Date Added";
|
||||
} else if(this.sortBy == "client_updated_at") {
|
||||
base += " Date Modifed";
|
||||
base += " Date Modified";
|
||||
} else if(this.sortBy == "title") {
|
||||
base += " Title";
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class ComponentView {
|
||||
}
|
||||
|
||||
$scope.$on("ext-reload-complete", () => {
|
||||
$scope.reloadStatus();
|
||||
$scope.reloadStatus(false);
|
||||
})
|
||||
|
||||
$scope.reloadComponent = function() {
|
||||
@@ -87,7 +87,7 @@ class ComponentView {
|
||||
componentManager.reloadComponent($scope.component);
|
||||
}
|
||||
|
||||
$scope.reloadStatus = function() {
|
||||
$scope.reloadStatus = function(doManualReload = true) {
|
||||
let component = $scope.component;
|
||||
$scope.reloading = true;
|
||||
let previouslyValid = $scope.componentValid;
|
||||
@@ -116,9 +116,9 @@ class ComponentView {
|
||||
}
|
||||
}
|
||||
|
||||
if(expired && !$scope.triedReloading) {
|
||||
if(expired && doManualReload) {
|
||||
// Try reloading, handled by footer, which will open Extensions window momentarily to pull in latest data
|
||||
$scope.triedReloading = true;
|
||||
// Upon completion, this method, reloadStatus, will be called, upon where doManualReload will be false to prevent recursion.
|
||||
$rootScope.$broadcast("reload-ext-data");
|
||||
}
|
||||
|
||||
@@ -133,14 +133,18 @@ class ComponentView {
|
||||
return url;
|
||||
}
|
||||
|
||||
$scope.$on("$destroy", function() {
|
||||
// console.log("Deregistering handler", $scope.identifier, $scope.component.name);
|
||||
$scope.destroy = function() {
|
||||
componentManager.deregisterHandler($scope.identifier);
|
||||
if($scope.component && !$scope.manualDealloc) {
|
||||
componentManager.deactivateComponent($scope.component, true);
|
||||
}
|
||||
|
||||
desktopManager.deregisterUpdateObserver($scope.updateObserver);
|
||||
}
|
||||
|
||||
$scope.$on("$destroy", function() {
|
||||
// console.log("Deregistering handler", $scope.identifier, $scope.component.name);
|
||||
$scope.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -264,6 +264,11 @@ class Item {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Same as above, but keys inside appData[AppDomain]
|
||||
appDataKeysToIgnoreWhenCheckingContentEquality() {
|
||||
return ["client_updated_at"];
|
||||
}
|
||||
|
||||
isItemContentEqualWith(otherItem) {
|
||||
let omit = (obj, keys) => {
|
||||
for(var key of keys) {
|
||||
@@ -271,8 +276,14 @@ class Item {
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
var left = omit(this.structureParams(), this.keysToIgnoreWhenCheckingContentEquality());
|
||||
var right = omit(otherItem.structureParams(), otherItem.keysToIgnoreWhenCheckingContentEquality());
|
||||
|
||||
var left = this.structureParams();
|
||||
left.appData[AppDomain] = omit(left.appData[AppDomain], this.appDataKeysToIgnoreWhenCheckingContentEquality());
|
||||
left = omit(left, this.keysToIgnoreWhenCheckingContentEquality());
|
||||
|
||||
var right = otherItem.structureParams();
|
||||
right.appData[AppDomain] = omit(right.appData[AppDomain], otherItem.appDataKeysToIgnoreWhenCheckingContentEquality());
|
||||
right = omit(right, otherItem.keysToIgnoreWhenCheckingContentEquality());
|
||||
|
||||
return JSON.stringify(left) === JSON.stringify(right)
|
||||
}
|
||||
|
||||
@@ -49,15 +49,19 @@ class ComponentManager {
|
||||
this.handleMessage(this.componentForSessionKey(event.data.sessionKey), event.data);
|
||||
}.bind(this), false);
|
||||
|
||||
this.modelManager.addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source) => {
|
||||
this.modelManager.addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source, sourceKey) => {
|
||||
|
||||
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
|
||||
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
|
||||
will take care of that, like ModelManager.MappingSourceRemoteSaved
|
||||
|
||||
Update: We will now check sourceKey to determine whether the incoming change should be sent to
|
||||
a component. If sourceKey == component.uuid, it will be skipped. This way, if one component triggers a change,
|
||||
it's sent to other components.
|
||||
*/
|
||||
if(source == ModelManager.MappingSourceComponentRetrieved) {
|
||||
return;
|
||||
}
|
||||
// if(source == ModelManager.MappingSourceComponentRetrieved) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
var syncedComponents = allItems.filter(function(item) {
|
||||
return item.content_type === "SN|Component" || item.content_type == "SN|Theme"
|
||||
@@ -81,6 +85,11 @@ class ComponentManager {
|
||||
}
|
||||
|
||||
for(let observer of this.streamObservers) {
|
||||
if(sourceKey && sourceKey == observer.component.uuid) {
|
||||
// Don't notify source of change, as it is the originator, doesn't need duplicate event.
|
||||
continue;
|
||||
}
|
||||
|
||||
var relevantItems = allItems.filter(function(item){
|
||||
return observer.contentTypes.indexOf(item.content_type) !== -1;
|
||||
})
|
||||
@@ -108,6 +117,11 @@ class ComponentManager {
|
||||
];
|
||||
|
||||
for(let observer of this.contextStreamObservers) {
|
||||
if(sourceKey && sourceKey == observer.component.uuid) {
|
||||
// Don't notify source of change, as it is the originator, doesn't need duplicate event.
|
||||
continue;
|
||||
}
|
||||
|
||||
for(let handler of this.handlers) {
|
||||
if(!handler.areas.includes(observer.component.area) && !handler.areas.includes("*")) {
|
||||
continue;
|
||||
@@ -164,7 +178,9 @@ class ComponentManager {
|
||||
for(let observer of observers) {
|
||||
if(handler.contextRequestHandler) {
|
||||
var itemInContext = handler.contextRequestHandler(observer.component);
|
||||
this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
|
||||
if(itemInContext) {
|
||||
this.sendContextItemInReply(observer.component, itemInContext, observer.originalMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -452,7 +468,7 @@ class ComponentManager {
|
||||
We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
|
||||
this would update them server side via sync, but would never make its way back to the UI.
|
||||
*/
|
||||
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved);
|
||||
var localItems = this.modelManager.mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved, component.uuid);
|
||||
|
||||
for(var item of localItems) {
|
||||
var responseItem = _.find(responseItems, {uuid: item.uuid});
|
||||
@@ -799,6 +815,14 @@ class ComponentManager {
|
||||
}
|
||||
}
|
||||
|
||||
this.streamObservers = this.streamObservers.filter(function(o){
|
||||
return o.component !== component;
|
||||
})
|
||||
|
||||
this.contextStreamObservers = this.contextStreamObservers.filter(function(o){
|
||||
return o.component !== component;
|
||||
})
|
||||
|
||||
if(component.area == "themes") {
|
||||
this.postActiveThemeToAllComponents();
|
||||
}
|
||||
|
||||
@@ -90,11 +90,11 @@ class DBManager {
|
||||
this.saveModels([item]);
|
||||
}
|
||||
|
||||
saveModels(items, callback) {
|
||||
saveModels(items, onsuccess, onerror) {
|
||||
|
||||
if(items.length == 0) {
|
||||
if(callback) {
|
||||
callback();
|
||||
if(onsuccess) {
|
||||
onsuccess();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -109,6 +109,17 @@ class DBManager {
|
||||
console.log("Transaction error:", event.target.errorCode);
|
||||
};
|
||||
|
||||
transaction.onabort = function(event) {
|
||||
console.log("Offline saving aborted:", event);
|
||||
var error = event.target.error;
|
||||
if(error.name == "QuotaExceededError") {
|
||||
alert("Unable to save changes locally because your device is out of space. Please free up some disk space and try again, otherwise, your data may end up in an inconsistent state.");
|
||||
} else {
|
||||
alert(`Unable to save changes locally due to an unknown system issue. Issue Code: ${error.code} Issue Name: ${error.name}.`);
|
||||
}
|
||||
onerror && onerror(error);
|
||||
};
|
||||
|
||||
var itemObjectStore = transaction.objectStore("items");
|
||||
var i = 0;
|
||||
putNext();
|
||||
@@ -119,8 +130,8 @@ class DBManager {
|
||||
itemObjectStore.put(item).onsuccess = putNext;
|
||||
++i;
|
||||
} else {
|
||||
if(callback){
|
||||
callback();
|
||||
if(onsuccess){
|
||||
onsuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class HttpManager {
|
||||
} else {
|
||||
console.error("Request error:", response);
|
||||
this.$timeout(function(){
|
||||
onerror(response)
|
||||
onerror(response, xmlhttp.status)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,11 +120,11 @@ class ModelManager {
|
||||
this.notifySyncObserversOfModels(items, ModelManager.MappingSourceLocalSaved);
|
||||
}
|
||||
|
||||
mapResponseItemsToLocalModels(items, source) {
|
||||
return this.mapResponseItemsToLocalModelsOmittingFields(items, null, source);
|
||||
mapResponseItemsToLocalModels(items, source, sourceKey) {
|
||||
return this.mapResponseItemsToLocalModelsOmittingFields(items, null, source, sourceKey);
|
||||
}
|
||||
|
||||
mapResponseItemsToLocalModelsOmittingFields(items, omitFields, source) {
|
||||
mapResponseItemsToLocalModelsOmittingFields(items, omitFields, source, sourceKey) {
|
||||
var models = [], processedObjects = [], modelsToNotifyObserversOf = [];
|
||||
|
||||
// first loop should add and process items
|
||||
@@ -196,13 +196,13 @@ class ModelManager {
|
||||
}
|
||||
}
|
||||
|
||||
this.notifySyncObserversOfModels(modelsToNotifyObserversOf, source);
|
||||
this.notifySyncObserversOfModels(modelsToNotifyObserversOf, source, sourceKey);
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
/* Note that this function is public, and can also be called manually (desktopManager uses it) */
|
||||
notifySyncObserversOfModels(models, source) {
|
||||
notifySyncObserversOfModels(models, source, sourceKey) {
|
||||
for(var observer of this.itemSyncObservers) {
|
||||
var allRelevantItems = observer.type == "*" ? models : models.filter(function(item){return item.content_type == observer.type});
|
||||
var validItems = [], deletedItems = [];
|
||||
@@ -215,7 +215,7 @@ class ModelManager {
|
||||
}
|
||||
|
||||
if(allRelevantItems.length > 0) {
|
||||
observer.callback(allRelevantItems, validItems, deletedItems, source);
|
||||
observer.callback(allRelevantItems, validItems, deletedItems, source, sourceKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,11 +208,11 @@ class StorageManager {
|
||||
this.saveModels([item]);
|
||||
}
|
||||
|
||||
saveModels(items, callback) {
|
||||
saveModels(items, onsuccess, onerror) {
|
||||
if(this.modelStorageMode == StorageManager.Fixed) {
|
||||
this.dbManager.saveModels(items, callback);
|
||||
this.dbManager.saveModels(items, onsuccess, onerror);
|
||||
} else {
|
||||
callback && callback();
|
||||
onsuccess && onsuccess();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class SyncManager {
|
||||
this.storageManager = storageManager;
|
||||
this.passcodeManager = passcodeManager;
|
||||
this.syncStatus = {};
|
||||
this.syncStatusObservers = [];
|
||||
}
|
||||
|
||||
get serverURL() {
|
||||
@@ -21,6 +22,22 @@ class SyncManager {
|
||||
return this.storageManager.getItem("mk");
|
||||
}
|
||||
|
||||
registerSyncStatusObserver(callback) {
|
||||
var observer = {key: new Date(), callback: callback};
|
||||
this.syncStatusObservers.push(observer);
|
||||
return observer;
|
||||
}
|
||||
|
||||
removeSyncStatusObserver(observer) {
|
||||
_.pull(this.syncStatusObservers, observer);
|
||||
}
|
||||
|
||||
syncStatusDidChange() {
|
||||
this.syncStatusObservers.forEach((observer) => {
|
||||
observer.callback(this.syncStatus);
|
||||
})
|
||||
}
|
||||
|
||||
writeItemsToLocalStorage(items, offlineOnly, callback) {
|
||||
if(items.length == 0) {
|
||||
callback && callback();
|
||||
@@ -38,7 +55,18 @@ class SyncManager {
|
||||
}
|
||||
return itemParams;
|
||||
})).then((params) => {
|
||||
this.storageManager.saveModels(params, callback);
|
||||
this.storageManager.saveModels(params, () => {
|
||||
// on success
|
||||
if(this.syncStatus.localError) {
|
||||
this.syncStatus.localError = null;
|
||||
this.syncStatusDidChange();
|
||||
}
|
||||
callback && callback();
|
||||
}, (error) => {
|
||||
// on error
|
||||
this.syncStatus.localError = error;
|
||||
this.syncStatusDidChange();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -411,7 +439,7 @@ class SyncManager {
|
||||
) {
|
||||
this.$rootScope.$broadcast("major-data-change");
|
||||
}
|
||||
|
||||
|
||||
this.callQueuedCallbacksAndCurrent(callback, response);
|
||||
this.$rootScope.$broadcast("sync:completed", {retrievedItems: this.allRetreivedItems, savedItems: this.allSavedItems});
|
||||
|
||||
@@ -429,7 +457,10 @@ class SyncManager {
|
||||
console.log("Caught sync success exception:", e);
|
||||
}
|
||||
|
||||
}.bind(this), function(response){
|
||||
}.bind(this), function(response, statusCode){
|
||||
if(statusCode == 401) {
|
||||
alert("Your session has expired. New changes will not be pulled in. Please sign out and sign back in to refresh your session.");
|
||||
}
|
||||
console.log("Sync error: ", response);
|
||||
var error = response ? response.error : {message: "Could not connect to server."};
|
||||
|
||||
|
||||
@@ -87,13 +87,12 @@ $footer-height: 32px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
width: 6px;
|
||||
width: 8px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
cursor: col-resize;
|
||||
background-color: rgba(black, 0.05);
|
||||
background-color: rgba(black, 0.1);
|
||||
opacity: 0;
|
||||
border: 1px dashed rgba($blue-color, 0.15);
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
|
||||
|
||||
@@ -99,7 +99,11 @@
|
||||
.component-view {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
// overflow: auto; // not sure why we need this. Removed because it creates unncessary scroll bars. Tested on folders extension, creates horizontal scrollbar at bottom on windows
|
||||
|
||||
// not sure why we need this. Removed because it creates unncessary scroll bars. Tested on folders extension, creates horizontal scrollbar at bottom on windows
|
||||
// overflow: auto;
|
||||
// Update: we needed that because when we display the expired Extended view, it allows it to scroll vertically.
|
||||
overflow-y: auto;
|
||||
|
||||
.sn-component {
|
||||
min-width: 100%;
|
||||
|
||||
@@ -26,22 +26,34 @@
|
||||
.spinner.info.small{"ng-if" => "reloading"}
|
||||
|
||||
.panel-row
|
||||
.panel-row
|
||||
.panel-column
|
||||
%p <strong>Otherwise</strong>, please follow the steps below to disable any external editors, so you can edit your note using the plain text editor instead.
|
||||
.panel-section
|
||||
%p{"ng-if" => "component.isEditor()"}
|
||||
<strong>Otherwise</strong>, please follow the steps below to disable any external editors,
|
||||
so you can edit your note using the plain text editor instead.
|
||||
|
||||
%p
|
||||
%ol
|
||||
%li Click the "Editor" menu item above (under the note title).
|
||||
%li Select "Plain Editor".
|
||||
%li Repeat this for every note you'd like to access. You can also delete the editor completely to disable it for all notes. To do so, click "Extensions" in the lower left corner of the app, then, for every editor, click "Uninstall".
|
||||
%p To temporarily disable this extension:
|
||||
|
||||
%p
|
||||
Need help? Please email us at
|
||||
%a{"href" => "mailto:hello@standardnotes.org", "target" => "_blank"} hello@standardnotes.org
|
||||
or check out the
|
||||
%a{"href" => "https://standardnotes.org/help", "target" => "_blank"} Help
|
||||
page.
|
||||
.panel-row
|
||||
.button.info{"ng-click" => "destroy()"}
|
||||
.label Disable Extension
|
||||
.spinner.info.small{"ng-if" => "reloading"}
|
||||
|
||||
.panel-row
|
||||
|
||||
%div{"ng-if" => "component.isEditor()"}
|
||||
%p To disassociate this note from this editor:
|
||||
|
||||
%ol
|
||||
%li Click the "Editor" menu item above (under the note title).
|
||||
%li Select "Plain Editor".
|
||||
%li Repeat this for every note you'd like to access. You can also delete the editor completely to disable it for all notes. To do so, click "Extensions" in the lower left corner of the app, then, for every editor, click "Uninstall".
|
||||
|
||||
%p
|
||||
Need help? Please email us at
|
||||
%a{"href" => "mailto:hello@standardnotes.org", "target" => "_blank"} hello@standardnotes.org
|
||||
or check out the
|
||||
%a{"href" => "https://standardnotes.org/help", "target" => "_blank"} Help
|
||||
page.
|
||||
|
||||
.sn-component{"ng-if" => "error == 'offline-restricted'"}
|
||||
.panel.static
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
%component-view.component-view{"ng-if" => "ctrl.selectedEditor", "component" => "ctrl.selectedEditor", "ng-style" => "ctrl.note.locked && {'pointer-events' : 'none'}", "ng-class" => "{'locked' : ctrl.note.locked }"}
|
||||
|
||||
%textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text", "ng-disabled" => "ctrl.note.locked",
|
||||
%textarea.editable#note-text-editor{"ng-if" => "!ctrl.selectedEditor", "ng-model" => "ctrl.note.text", "ng-readonly" => "ctrl.note.locked",
|
||||
"ng-change" => "ctrl.contentChanged()", "ng-trim" => "false", "ng-click" => "ctrl.clickedTextArea()",
|
||||
"ng-focus" => "ctrl.onContentFocus()", "dir" => "auto", "ng-attr-spellcheck" => "{{ctrl.spellcheck}}"}
|
||||
{{ctrl.onSystemEditorLoad()}}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
.note{"ng-repeat" => "note in (ctrl.sortedNotes = (ctrl.tag.notes | filter: ctrl.filterNotes | sortBy: ctrl.sortBy | limitTo:ctrl.notesToDisplay)) track by note.uuid",
|
||||
"ng-click" => "ctrl.selectNote(note, true)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
|
||||
%strong.red.medium-text{"ng-if" => "note.conflict_of"} Conflicted copy
|
||||
%strong.red.medium-text{"ng-if" => "note.errorDecrypting"} Error decrypting
|
||||
%strong.red.medium-text{"ng-if" => "note.errorDecrypting"} Unable to Decrypt
|
||||
|
||||
.pinned.tinted{"ng-if" => "note.pinned", "ng-class" => "{'tinted-selected' : ctrl.selectedNote == note}"}
|
||||
%i.icon.ion-bookmark
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
.count {{ctrl.noteCount(tag)}}
|
||||
|
||||
.red.small-text.bold{"ng-if" => "tag.conflict_of"} Conflicted copy
|
||||
.red.small-text.bold{"ng-if" => "tag.errorDecrypting"} Error decrypting
|
||||
.red.small-text.bold{"ng-if" => "tag.errorDecrypting"} Unable to Decrypt
|
||||
|
||||
.menu{"ng-if" => "ctrl.selectedTag == tag"}
|
||||
%a.item{"ng-click" => "ctrl.selectedRenameTag($event, tag)", "ng-if" => "!ctrl.editingTag"} Rename
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -5721,9 +5721,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"standard-file-js": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.0.tgz",
|
||||
"integrity": "sha512-P2NGrzAHlik6/Hu+2lJ6dOjvevZEyXOSCuI4hvFAsTL9Fn3Ixl0AR+y1M6CjKBF2NxAGtDviVR1YctO5MGee9Q==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.1.tgz",
|
||||
"integrity": "sha512-UEYlIiIMJJeqZSjmeJnLPlWH6SYa8x4HW9tuklF4mqSdGuZvUc1eJcUPiJ2n1Tv+rHEmKeX5IHAhSFOFoiSKag==",
|
||||
"dev": true
|
||||
},
|
||||
"statuses": {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"karma-jasmine": "^1.1.0",
|
||||
"karma-phantomjs-launcher": "^1.0.2",
|
||||
"sn-stylekit": "1.0.15",
|
||||
"standard-file-js": "0.3.0"
|
||||
"standard-file-js": "0.3.1"
|
||||
},
|
||||
"license": "GPL-3.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user