tags input in editor, #41
This commit is contained in:
@@ -5,7 +5,8 @@ angular.module('app.frontend')
|
|||||||
scope: {
|
scope: {
|
||||||
save: "&",
|
save: "&",
|
||||||
remove: "&",
|
remove: "&",
|
||||||
note: "="
|
note: "=",
|
||||||
|
updateTags: "&"
|
||||||
},
|
},
|
||||||
templateUrl: 'frontend/editor.html',
|
templateUrl: 'frontend/editor.html',
|
||||||
replace: true,
|
replace: true,
|
||||||
@@ -16,7 +17,7 @@ angular.module('app.frontend')
|
|||||||
link:function(scope, elem, attrs, ctrl) {
|
link:function(scope, elem, attrs, ctrl) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert 4 spaces when a tab key is pressed,
|
* Insert 4 spaces when a tab key is pressed,
|
||||||
* only used when inside of the text editor.
|
* only used when inside of the text editor.
|
||||||
*/
|
*/
|
||||||
var handleTab = function (event) {
|
var handleTab = function (event) {
|
||||||
@@ -85,6 +86,7 @@ angular.module('app.frontend')
|
|||||||
this.editorMode = 'edit';
|
this.editorMode = 'edit';
|
||||||
this.showExtensions = false;
|
this.showExtensions = false;
|
||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
|
this.loadTagsString();
|
||||||
|
|
||||||
if(note.safeText().length == 0 && note.dummy) {
|
if(note.safeText().length == 0 && note.dummy) {
|
||||||
this.focusTitle(100);
|
this.focusTitle(100);
|
||||||
@@ -236,4 +238,29 @@ angular.module('app.frontend')
|
|||||||
this.focusEditor(100);
|
this.focusEditor(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tags */
|
||||||
|
|
||||||
|
this.loadTagsString = function() {
|
||||||
|
var string = "";
|
||||||
|
for(var tag of this.note.tags) {
|
||||||
|
string += "#" + tag.title + " ";
|
||||||
|
}
|
||||||
|
this.tagsString = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateTagsFromTagsString = function($event) {
|
||||||
|
$event.target.blur();
|
||||||
|
|
||||||
|
var tags = this.tagsString.split("#");
|
||||||
|
tags = _.filter(tags, function(tag){
|
||||||
|
return tag.length > 0;
|
||||||
|
})
|
||||||
|
tags = _.map(tags, function(tag){
|
||||||
|
return tag.trim();
|
||||||
|
})
|
||||||
|
|
||||||
|
this.note.dummy = false;
|
||||||
|
this.updateTags()(this.note, tags);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,23 @@ angular.module('app.frontend')
|
|||||||
$scope.tags = modelManager.tags;
|
$scope.tags = modelManager.tags;
|
||||||
$scope.allTag.notes = modelManager.notes;
|
$scope.allTag.notes = modelManager.notes;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Editor Callbacks
|
||||||
|
*/
|
||||||
|
|
||||||
|
$scope.updateTagsForNote = function(note, stringTags) {
|
||||||
|
note.removeAllRelationships();
|
||||||
|
var tags = [];
|
||||||
|
for(var tagString of stringTags) {
|
||||||
|
tags.push(modelManager.findOrCreateTagByTitle(tagString));
|
||||||
|
}
|
||||||
|
for(var tag of tags) {
|
||||||
|
modelManager.createRelationshipBetweenItems(note, tag);
|
||||||
|
}
|
||||||
|
console.log("updating tags for note", note, tags);
|
||||||
|
apiController.sync();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tags Ctrl Callbacks
|
Tags Ctrl Callbacks
|
||||||
*/
|
*/
|
||||||
@@ -43,20 +60,6 @@ angular.module('app.frontend')
|
|||||||
apiController.sync(callback);
|
apiController.sync(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Called to update the tag of a note after drag and drop change
|
|
||||||
The note object is a copy of the original
|
|
||||||
*/
|
|
||||||
$scope.tagsUpdateNoteTag = function(noteCopy, newTag, oldTag) {
|
|
||||||
|
|
||||||
var originalNote = _.find(modelManager.notes, {uuid: noteCopy.uuid});
|
|
||||||
if(!newTag.all) {
|
|
||||||
modelManager.createRelationshipBetweenItems(newTag, originalNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
apiController.sync(function(){});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Notes Ctrl Callbacks
|
Notes Ctrl Callbacks
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -102,9 +102,4 @@ angular.module('app.frontend')
|
|||||||
return validNotes.length;
|
return validNotes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.handleDrop = function(e, newTag, note) {
|
|
||||||
this.updateNoteTag()(note, newTag, this.selectedTag);
|
|
||||||
}.bind(this)
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class Item {
|
|||||||
|
|
||||||
removeAllRelationships() {
|
removeAllRelationships() {
|
||||||
// must override
|
// must override
|
||||||
|
this.setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeMetadataFromItem(item) {
|
mergeMetadataFromItem(item) {
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
angular
|
|
||||||
.module('app.frontend')
|
|
||||||
.directive('draggable', function() {
|
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
note: "="
|
|
||||||
},
|
|
||||||
link: function(scope, element) {
|
|
||||||
// this gives us the native JS object
|
|
||||||
var el = element[0];
|
|
||||||
|
|
||||||
el.draggable = true;
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'dragstart',
|
|
||||||
function(e) {
|
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
|
||||||
e.dataTransfer.setData('Note', JSON.stringify(scope.note));
|
|
||||||
this.classList.add('drag');
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'dragend',
|
|
||||||
function(e) {
|
|
||||||
this.classList.remove('drag');
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
angular
|
|
||||||
.module('app.frontend')
|
|
||||||
.directive('droppable', function() {
|
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
drop: '&',
|
|
||||||
bin: '=',
|
|
||||||
tag: "="
|
|
||||||
},
|
|
||||||
link: function(scope, element) {
|
|
||||||
// again we need the native object
|
|
||||||
var el = element[0];
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'dragover',
|
|
||||||
function(e) {
|
|
||||||
e.dataTransfer.dropEffect = 'move';
|
|
||||||
// allows us to drop
|
|
||||||
if (e.preventDefault) e.preventDefault();
|
|
||||||
this.classList.add('over');
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
var counter = 0;
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'dragenter',
|
|
||||||
function(e) {
|
|
||||||
counter++;
|
|
||||||
this.classList.add('over');
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'dragleave',
|
|
||||||
function(e) {
|
|
||||||
counter--;
|
|
||||||
if (counter === 0) {
|
|
||||||
this.classList.remove('over');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
el.addEventListener(
|
|
||||||
'drop',
|
|
||||||
function(e) {
|
|
||||||
// Stops some browsers from redirecting.
|
|
||||||
if (e.stopPropagation) e.stopPropagation();
|
|
||||||
|
|
||||||
this.classList.remove('over');
|
|
||||||
|
|
||||||
var binId = this.uuid;
|
|
||||||
var note = new Note(JSON.parse(e.dataTransfer.getData('Note')));
|
|
||||||
scope.$apply(function(scope) {
|
|
||||||
var fn = scope.drop();
|
|
||||||
if ('undefined' !== typeof fn) {
|
|
||||||
fn(e, scope.tag, note);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -32,6 +32,17 @@ class ModelManager {
|
|||||||
return _.find(this.items, {uuid: itemId});
|
return _.find(this.items, {uuid: itemId});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findOrCreateTagByTitle(title) {
|
||||||
|
console.log("looking for tag", title);
|
||||||
|
var tag = _.find(this.tags, {title: title})
|
||||||
|
if(!tag) {
|
||||||
|
console.log("not found, creating");
|
||||||
|
tag = this.createItem({content_type: "Tag", title: title});
|
||||||
|
this.addItem(tag);
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
mapResponseItemsToLocalModels(items) {
|
mapResponseItemsToLocalModels(items) {
|
||||||
return this.mapResponseItemsToLocalModelsOmittingFields(items, null);
|
return this.mapResponseItemsToLocalModelsOmittingFields(items, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$heading-height: 90px;
|
$heading-height: 100px;
|
||||||
|
|
||||||
.editor-heading {
|
.editor-heading {
|
||||||
|
|
||||||
@@ -77,7 +77,17 @@
|
|||||||
color: rgba(black, 0.23);
|
color: rgba(black, 0.23);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
clear: left;
|
||||||
|
width: 100%;
|
||||||
|
height: 25px;
|
||||||
|
|
||||||
|
.tags-input {
|
||||||
|
background-color: transparent;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreen-ghost-bar {
|
.fullscreen-ghost-bar {
|
||||||
@@ -86,17 +96,6 @@
|
|||||||
width: 20%;
|
width: 20%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
//
|
|
||||||
// &:hover + .section-title-bar {
|
|
||||||
// // show section title bar when hover over ghost bar
|
|
||||||
// opacity: 1.0;
|
|
||||||
// z-index: 100;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// &:not(:hover) + .section-title-bar {
|
|
||||||
// // display: none;
|
|
||||||
// opacity: 1.0;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -167,6 +166,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.markdown {
|
.markdown {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
float: right;
|
float: right;
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
"ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()",
|
"ng-change" => "ctrl.nameChanged()", "ng-focus" => "ctrl.onNameFocus()",
|
||||||
"select-on-click" => "true"}
|
"select-on-click" => "true"}
|
||||||
.save-status {{ctrl.noteStatus}}
|
.save-status {{ctrl.noteStatus}}
|
||||||
|
.tags
|
||||||
|
%input.tags-input{"type" => "text", "ng-keyup" => "$event.keyCode == 13 && ctrl.updateTagsFromTagsString($event, ctrl.tagsString)",
|
||||||
|
"ng-model" => "ctrl.tagsString", "placeholder" => "#tags"}
|
||||||
.section-menu
|
.section-menu
|
||||||
%ul.nav.nav-pills
|
%ul.nav.nav-pills
|
||||||
%li.dropdown
|
%li.dropdown
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
.app-container
|
.app-container
|
||||||
.app
|
.app
|
||||||
%tags-section{"save" => "tagsSave", "add-new" => "tagsAddNew", "will-select" => "tagsWillMakeSelection", "selection-made" => "tagsSelectionMade", "all-tag" => "allTag",
|
%tags-section{"save" => "tagsSave", "add-new" => "tagsAddNew", "will-select" => "tagsWillMakeSelection", "selection-made" => "tagsSelectionMade", "all-tag" => "allTag",
|
||||||
"tags" => "tags", "update-note-tag" => "tagsUpdateNoteTag"}
|
"tags" => "tags"}
|
||||||
|
|
||||||
%notes-section{"remove-tag" => "notesRemoveTag", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade",
|
%notes-section{"remove-tag" => "notesRemoveTag", "add-new" => "notesAddNew", "selection-made" => "notesSelectionMade",
|
||||||
"tag" => "selectedTag", "remove" => "deleteNote"}
|
"tag" => "selectedTag", "remove" => "deleteNote"}
|
||||||
|
|
||||||
%editor-section{"ng-if" => "selectedNote", "note" => "selectedNote", "remove" => "deleteNote", "save" => "saveNote"}
|
%editor-section{"ng-if" => "selectedNote", "note" => "selectedNote", "remove" => "deleteNote", "save" => "saveNote", "update-tags" => "updateTagsForNote"}
|
||||||
%header{"user" => "defaultUser"}
|
%header{"user" => "defaultUser"}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag
|
%a.text{"ng-click" => "ctrl.selectedMenuItem(); ctrl.selectedTagDelete()"} Delete Tag
|
||||||
|
|
||||||
.note{"ng-repeat" => "note in ctrl.tag.notes | filter: ctrl.filterNotes",
|
.note{"ng-repeat" => "note in ctrl.tag.notes | filter: ctrl.filterNotes",
|
||||||
"ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}",
|
"ng-click" => "ctrl.selectNote(note)", "ng-class" => "{'selected' : ctrl.selectedNote == note}"}
|
||||||
"ng-attr-draggable" => "{{note.dummy ? undefined : 'true'}}", "note" => "note"}
|
|
||||||
.name
|
.name
|
||||||
{{note.title}}
|
{{note.title}}
|
||||||
.date {{(note.created_at | appDateTime) || 'Now'}}
|
.date {{(note.created_at | appDateTime) || 'Now'}}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
.title Tags
|
.title Tags
|
||||||
.add-button.tag-add-button{"ng-click" => "ctrl.clickedAddNewTag()"} +
|
.add-button.tag-add-button{"ng-click" => "ctrl.clickedAddNewTag()"} +
|
||||||
{{ctrl.test}}
|
{{ctrl.test}}
|
||||||
.tag{"ng-if" => "ctrl.allTag", "ng-click" => "ctrl.selectTag(ctrl.allTag)", "ng-class" => "{'selected' : ctrl.selectedTag == ctrl.allTag}",
|
.tag{"ng-if" => "ctrl.allTag", "ng-click" => "ctrl.selectTag(ctrl.allTag)", "ng-class" => "{'selected' : ctrl.selectedTag == ctrl.allTag}"}
|
||||||
"droppable" => true, "drop" => "ctrl.handleDrop", "tag" => "ctrl.allTag"}
|
|
||||||
%input.title{"ng-disabled" => "true", "ng-model" => "ctrl.allTag.title"}
|
%input.title{"ng-disabled" => "true", "ng-model" => "ctrl.allTag.title"}
|
||||||
.count {{ctrl.noteCount(ctrl.allTag)}}
|
.count {{ctrl.noteCount(ctrl.allTag)}}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user