From 48519b48adde158accfc9a5f040660b5cdb89842 Mon Sep 17 00:00:00 2001 From: LucasYuNju Date: Sun, 11 Sep 2016 16:52:23 +0800 Subject: [PATCH 1/4] Separate tag.js it into tagNav and tagInput. --- node_modules/api.js | 2 - node_modules/web.js | 4 +- note.html | 25 ++-- public/js/app/note.js | 8 +- public/js/app/page.js | 6 +- public/js/app/tag.js | 108 +---------------- public/js/app/tagNew.js | 243 ++++++++++++++++++++++++++++++++++++++ public/themes/default.css | 30 +++-- 8 files changed, 290 insertions(+), 136 deletions(-) create mode 100644 public/js/app/tagNew.js diff --git a/node_modules/api.js b/node_modules/api.js index 2d36b2a2..4420c475 100644 --- a/node_modules/api.js +++ b/node_modules/api.js @@ -193,7 +193,6 @@ var Api = { } var ret = response.body; console.log('--getSyncState--ret---') - console.log(ret); if(Common.isOk(ret)) { callback && callback(ret); } else { @@ -570,7 +569,6 @@ var Api = { } console.log('update note :'); - console.log(data); // files处理 var needMultiple = false; diff --git a/node_modules/web.js b/node_modules/web.js index e76cb888..9e8b59da 100644 --- a/node_modules/web.js +++ b/node_modules/web.js @@ -98,9 +98,9 @@ var Web = { // console.log("是啊"); // console.error(tagSyncInfo); var adds = tagSyncInfo.adds; - me.Tag.addTagsNav(adds); + me.Tag.nav.addTags(adds); var deletes = tagSyncInfo.deletes; - me.Tag.deleteTagsNav(deletes); + me.Tag.nav.deleteTags(deletes); }, addTag: function(tag) { diff --git a/note.html b/note.html index 8753d311..ee56d8b3 100755 --- a/note.html +++ b/note.html @@ -181,10 +181,6 @@ function log(o) { @@ -467,26 +463,22 @@ function log(o) {
-
+
+ +
- @@ -676,6 +668,7 @@ window.debug = false; + diff --git a/public/js/app/note.js b/public/js/app/note.js index 9b9c7101..9f3a1e43 100644 --- a/public/js/app/note.js +++ b/public/js/app/note.js @@ -247,7 +247,7 @@ Note.curHasChanged = function(force) { // 收集当前信息, 与cache比对 var title = $('#noteTitle').val(); - var tags = Tag.getTags(); + var tags = Tag.input.getTags(); var hasChanged = { hasChanged: false, // 总的是否有改变 @@ -811,7 +811,7 @@ Note.renderChangedNote = function(changedNote) { // 此时需要清空只读的, 且切换到note edit模式下 Note.clearNoteInfo = function() { Note.clearCurNoteId(); - Tag.clearTags(); + Tag.input.clearTags(); $("#noteTitle").val(""); setEditorContent(""); @@ -849,7 +849,7 @@ Note.renderNote = function(note) { // 当前正在编辑的 // tags - Tag.renderTags(note.Tags); + Tag.input.setTags(note.Tags); }; // render content @@ -1760,7 +1760,7 @@ Note.deleteNoteTag = function(item, tag) { } // 如果当前笔记是展示的笔记, 则重新renderTags if(noteId == Note.curNoteId) { - Tag.renderTags(note.Tags); + Tag.input.setTags(note.Tags); } } } diff --git a/public/js/app/page.js b/public/js/app/page.js index d6b93a28..45c743fc 100644 --- a/public/js/app/page.js +++ b/public/js/app/page.js @@ -1283,7 +1283,7 @@ var State = { if(Notebook.isStarred) { CurIsStarred = true; } else if(Notebook.isTag) { - CurTag = Tag.curTag; + CurTag = Tag.nav.curTag; } CurNotebookId = Notebook.curNotebookId; @@ -1363,7 +1363,7 @@ var State = { } // 搜索标签 else if(state.CurTag) { - Tag.searchTag(state.CurTag, state.CurNoteId); + Tag.nav.searchByTag(state.CurTag, state.CurNoteId); } // 搜索笔记 else if(state.CurSearchKey) { @@ -1484,7 +1484,7 @@ function initPage(initedCallback) { // 标签 TagService.getTags(function(tags) { - Tag.renderTagNav(tags); + Tag.nav.setTags(tags); ok(); }); diff --git a/public/js/app/tag.js b/public/js/app/tag.js index ab27b8a2..cb9b7da4 100644 --- a/public/js/app/tag.js +++ b/public/js/app/tag.js @@ -1,7 +1,5 @@ // Tag -// 蓝色, 红色怎么存到数据库中? 直接存蓝色 - Tag.classes = { "蓝色": "label label-blue", "红色": "label label-red", @@ -37,7 +35,6 @@ Tag.getTags = function() { var tags = []; Tag.t.children().each(function(){ var text = $(this).data('tag'); - // text = text.substring(0, text.length - 1); // 把X去掉 text = Tag.mapCn2En[text] || text; tags.push(text); }); @@ -64,13 +61,6 @@ Tag.renderTags = function(tags) { } }; -// tag最初状态 -function revertTagStatus() { - $("#addTagTrigger").show(); - $("#addTagInput").hide(); - // hideTagList(); -} - function hideTagList(event) { $("#tagDropdown").removeClass("open"); if (event) { @@ -84,39 +74,6 @@ function showTagList(event) { } } -// 只读模式下显示tags -// called by Note -Tag.renderReadOnlyTags = function(tags) { - // 先清空 - $("#noteReadTags").html(""); - if(isEmpty(tags)) { - $("#noteReadTags").html(getMsg("noTag")); - } - - var i = true; - function getNextDefaultClasses() { - if (i) { - return "label label-default"; - i = false - } else { - i = true; - return "label label-info"; - } - } - - for(var i in tags) { - var text = tags[i]; - text = Tag.mapEn2Cn[text] || text; - var classes = Tag.classes[text]; - if(!classes) { - classes = getNextDefaultClasses(); - } - tag = tt('?', classes, text); - - $("#noteReadTags").append(tag); - } -} - // 添加tag // tag = {classes:"label label-red", text:"红色"} // tag = life @@ -265,7 +222,6 @@ Tag.renderTagNav = function(tags) { }; // 添加的标签重新render到左边, 放在第一个位置 -// 重新render Tag.addTagNav = function(newTag) { var me = this; for(var i in me.tags) { @@ -312,7 +268,7 @@ Tag.searchTag = function(tag, noteId) { // 事件 $(function() { - // tag + // tag input box $("#addTagTrigger").click(function() { $(this).hide(); $("#addTagInput").show().focus().val(""); @@ -358,29 +314,17 @@ $(function() { text : a.text() }, true); }); - // 这是个问题, 为什么? 捕获不了事件?, input的blur造成 - /* - $(".label").click(function(event) { - var a = $(this); - Tag.appendTag({ - classes : a.attr("class"), - text : a.text() - }); - // event.stopPropagation(); - }); - */ $("#tags").on("click", "i", function() { Tag.removeTag($(this).parent()); }); - //---------- - // + + // tag nav function deleteTag() { $li = $(this).closest('li'); var tag = $.trim($li.data("tag")); if(confirm(getMsg("Are you sure ?"))) { TagService.deleteTag(tag, function(re) { - // re = {NoteId => note} if(typeof re == "object" && re.Ok !== false) { Note.deleteNoteTag(re, tag); $li.remove(); @@ -389,52 +333,12 @@ $(function() { }; } - //------------- - // nav 标签搜索 function searchTag() { var $li = $(this).closest('li'); var tag = $.trim($li.data("tag")); - Tag.searchTag(tag); - /* - - // tag = Tag.mapCn2En[tag] || tag; - - // 学习changeNotebook - - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - // 也会把curNoteId清空 - Note.clearAll(); - - // $("#tagSearch").html($li.html()).show(); - - var h = $li.html(); - Notebook.changeCurNotebookTitle(h, false, '', true); - Tag.curTag = h; - $('#curNotebookForListNote').find('i, em').remove(); - // $("#tagSearch .tag-delete").remove(); - - showLoading(); - NoteService.searchNoteByTag(tag, function(notes) { - hideLoading(); - if(notes) { - // 和note搜索一样 - // 设空, 防止发生上述情况 - // Note.curNoteId = ""; - Note.renderNotes(notes); - if(!isEmpty(notes)) { - Note.changeNote(notes[0].NoteId); - } - } - }); - */ }; - $("#myTag .folderBody").on("click", "li .label", searchTag); - // $("#minTagNav").on("click", "li", searchTag); - - $("#myTag .folderBody").on("click", "li .tag-delete", deleteTag); -}); \ No newline at end of file + $("#tagNav").on("click", "li .label", searchTag); + $("#tagNav").on("click", "li .tag-delete", deleteTag); +}); diff --git a/public/js/app/tagNew.js b/public/js/app/tagNew.js new file mode 100644 index 00000000..0dfb48d9 --- /dev/null +++ b/public/js/app/tagNew.js @@ -0,0 +1,243 @@ +/** + * tag navigator + */ +var TagNav = function() { + this.tags = []; + this.curTag = null; + this.$element = $("tagNav"); + this.$element.on("click", "li .label", function() { + var tagValue = $(this).closest('li').data("tag").trim(); + this._searchByTag(tagValue); + }); + this.$element.on("click", "li .tag-delete", this._deleteTag); +}; + +TagNav.prototype = { + constructor: TagNav, + _searchByTag: function(tag, noteId) { + Note.curChangedSaveIt(); + // 清空所有,也会把curNoteId清空 + Note.clearAll(); + + var tagTitle = '' + trimTitle(tag) + ''; + + Notebook.changeCurNotebookTitle(tagTitle, false, '', true); + this.curTag = tag; + + NoteService.searchNoteByTag(tag, function(notes) { + hideLoading(); + if(notes) { + Note.renderNotes(notes); + Note.renderNotesAndTargetNote(notes, noteId); + } + }); + }, + + _deleteTag: function() { + $li = $(this).closest('li'); + var tag = $.trim($li.data("tag")); + if(confirm(getMsg("Are you sure ?"))) { + TagService.deleteTag(tag, function(re) { + if(typeof re == "object" && re.Ok !== false) { + Note.deleteNoteTag(re, tag); + $li.remove(); + } + }); + }; + }, + + // called by node: web.js + deleteTags: function(tags) { + tags = tags || []; + for(var i = 0; i < tags.length; ++i) { + var title = tags[i]; + $('#myTag li[data-tag="' + title + '"]').remove(); + } + }, + + // called by node: web.js + // 添加标签,并重绘到左侧 + addTags: function(tags) { + console.warn("nav addtags", tags); + tags = tags || []; + // 去重,将添加的标签放在第一个位置 + for(var i = 0; i < tags.length; ++i) { + for(var j in this.tags) { + if(this.tags[j].Tag == tags[i].Tag) { + this.tags.splice(j, 1); + break; + } + } + this.tags.unshift(tags[i]); + } + this.setTags(this.tags); + }, + + // called by page.js + // 更新tags,并重绘到左侧 + setTags: function(tags) { + console.warn("nav settags", tags); + this.tags = tags || []; + $("#tagNav").html(''); + for(var i in this.tags) { + var noteTag = this.tags[i]; + var tag = noteTag.Tag; + var text = tag; + + text = trimTitle(text); + var classes = "label label-default"; + // 笔记数量先隐藏, 不准确 + $("#tagNav").append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); + } + + if(this.tags.length == 0) { + $("#tagNav").html('

    ' + getMsg('No tag') + '

    '); + } + }, +}; + +/** + * tag edit area of editor + */ +var TagInput = function() { + this.tags = []; //array of strings + var me = this; + this.$tags = $("#tags"); + this.$input = $("#tagInput"); + this.$inputTrigger = $("#tagInputTrigger"); + this.$suggestion = $("#tagSuggestion"); + this.$suggestion.hide(); + + this.$inputTrigger.click(function() { + me.$inputTrigger.hide(); + me.$input.show().focus().val(""); + }); + + this.$input.blur(function() { + var val = me.$input.val(); + if(val) { + me._addTag(val, true); + } + }); + + this.$input.keydown(function(e) { + if (e.keyCode == 13) { + me._hideSuggestion(); + $(this).trigger("blur"); + } + else { + me._showSuggestion(me.$input.val()); + } + }); + // 点击下拉时也会触发input的blur事件 + $("#tagColor li").click(function(event) { + var a; + if($(this).attr("role")) { + a = $(this).find("span"); + } else { + a = $(this); + } + Tag.appendTag({ + classes : a.attr("class"), + text : a.text() + }, true); + }); + + this.$tags.on("click", "i", function() { + me._removeTag($(this).parent()); + }); +} + +TagInput.prototype = { + constructor: TagInput, + + // called by Note + getTags: function() { + var tags = []; + this.$tags.children().each(function(){ + var text = $(this).data('tag'); + tags.push(text); + }); + // 正常情况下不会重复 + return tags; + }, + + // called by Note + clearTags: function() { + this.$tags.html(""); + }, + + // called by Note + setTags: function(tags) { + if(isEmpty(tags) || !Array.isArray(tags)) { + return; + } + console.warn("input settags", tags); + this.$tags.html(""); + for(var i = 0; i < tags.length; ++i) { + this._addTag(tags[i]); + } + }, + + // tag应该是string的,也可能是number + _addTag: function(tag, save) { + if(!tag) { + return; + } + var classes = "label label-default", + text = (tag + "").trim(), + escapedText = trimTitle(text); + + // 取出tags中重复 + var duplicate = false; + this.$tags.children().each(function() { + if (escapedText + "X" == $(this).text()) { + $(this).remove(); + duplicate = true; + } + }); + + this._hideSuggestion(); + this.$tags.append(tt('?X', classes, text, escapedText)); + + if(save && !duplicate) { + this._saveTag(text); + } + }, + + // 保存tag + _saveTag(text) { + Note.curChangedSaveIt(true, function() { + TagService.addOrUpdateTag(text, function(ret) { + if(typeof ret == 'object' && ret.Ok !== false) { + Tag.nav.addTags([ret]); + } + }); + }); + }, + + // 删除tag + _removeTag: function($target) { + var tag = $target.data('tag'); + $target.remove(); + Note.curChangedSaveIt(true, function() { + TagService.addOrUpdateTag(tag, function(ret) { + console.error("delete ret", ret); + if(typeof ret == 'object' && ret.Ok !== false) { + Tag.nav.addTags([ret]); + } + }); + }); + }, + + _showSuggestion: function(keyword) { + this.$suggestion.show(); + }, + + _hideSuggestion: function() { + this.$suggestion.hide(); + }, +}; + +Tag.nav = new TagNav(); +Tag.input = new TagInput(); diff --git a/public/themes/default.css b/public/themes/default.css index d3b6dd66..94460ce6 100644 --- a/public/themes/default.css +++ b/public/themes/default.css @@ -317,16 +317,32 @@ h3 { border-bottom: 1px solid #ddd; height: 36px; } -#tag { - height: 36px; - line-height: 36px; +#tagInputBox { + height: 30px; + line-height: 30px; +} +#tagInputBox > * { + float: left; + height: 30px; + line-height: 30px; +} +#tagIcon { + display: block; + text-align: center; + margin-right: 4px; } #tags { display: block; + padding: 0; + margin: 0; + list-style: none; +} +#tags li { float: left; - line-height: 25px; - height: 25px; - margin-top: 0; + height: 20px; + line-height: 20px; + margin-top: 5px; + margin-right: 2px; } #tags .label { margin-right: 2px; @@ -993,7 +1009,7 @@ h3 { height: 30px; border-top: 1px solid #eee; } -#tag { +#tagInputBox { position: absolute; right: 0; top: 0; From 7488d42472227e8e534ceaf5e0202ee357e99271 Mon Sep 17 00:00:00 2001 From: LucasYuNju Date: Sun, 11 Sep 2016 23:33:25 +0800 Subject: [PATCH 2/4] Tag auto suggest. --- note.html | 11 +- public/js/app/tag.js | 688 +++++++++++++++++++------------------- public/js/app/tagNew.js | 92 +++-- public/themes/default.css | 28 +- 4 files changed, 431 insertions(+), 388 deletions(-) diff --git a/note.html b/note.html index ee56d8b3..daacb9d5 100755 --- a/note.html +++ b/note.html @@ -465,19 +465,16 @@ function log(o) {
    -
    -
    @@ -664,7 +660,6 @@ window.debug = false; - diff --git a/public/js/app/tagNew.js b/public/js/app/tagNew.js index 864cc7b8..aec38681 100644 --- a/public/js/app/tagNew.js +++ b/public/js/app/tagNew.js @@ -4,12 +4,12 @@ var TagNav = function() { this.tags = []; this.curTag = null; - this.$element = $("#tagNav"); - this.$element.on("click", "li .label", function() { - var tagValue = $(this).closest('li').data("tag").trim(); + this.$element = $('#tagNav'); + this.$element.on('click', 'li .label', function() { + var tagValue = $(this).closest('li').data('tag').trim(); this._searchByTag(tagValue); }); - this.$element.on("click", "li .tag-delete", this._deleteTag); + this.$element.on('click', 'li .tag-delete', this._deleteTag); }; TagNav.prototype = { @@ -35,10 +35,10 @@ TagNav.prototype = { _deleteTag: function() { $li = $(this).closest('li'); - var tag = $.trim($li.data("tag")); - if(confirm(getMsg("Are you sure ?"))) { + var tag = $.trim($li.data('tag')); + if(confirm(getMsg('Are you sure ?'))) { TagService.deleteTag(tag, function(re) { - if(typeof re == "object" && re.Ok !== false) { + if(typeof re == 'object' && re.Ok !== false) { Note.deleteNoteTag(re, tag); $li.remove(); } @@ -58,7 +58,6 @@ TagNav.prototype = { // called by node: web.js // 添加标签,并重绘到左侧 addTags: function(tags) { - // console.warn("nav addtags", tags); tags = tags || []; // 去重,将添加的标签放在第一个位置 for(var i = 0; i < tags.length; ++i) { @@ -76,22 +75,21 @@ TagNav.prototype = { // called by page.js // 更新tags,并重绘到左侧 setTags: function(tags) { - // console.warn("nav settags", tags); this.tags = tags || []; - $("#tagNav").html(''); + $('#tagNav').html(''); for(var i in this.tags) { var noteTag = this.tags[i]; var tag = noteTag.Tag; var text = tag; text = trimTitle(text); - var classes = "label label-default"; + var classes = 'label label-default'; // 笔记数量先隐藏, 不准确 - $("#tagNav").append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); + $('#tagNav').append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); } if(this.tags.length == 0) { - $("#tagNav").html('

    ' + getMsg('No tag') + '

    '); + $('#tagNav').html('

    ' + getMsg('No tag') + '

    '); } }, }; @@ -101,22 +99,22 @@ TagNav.prototype = { * tag edit area of editor */ var TagInput = function() { - this.tags = []; //array of strings var me = this; - this.$tags = $("#tags"); - this.$input = $("#tagInput"); - this.$inputPrompt = $("#tagInputPrompt"); - this.$suggestion = $("#tagSuggestion"); - this._hideSuggestion(); + me.tags = []; //array of strings + me.$tags = $("#tags"); + me.$input = $("#tagInput"); + me.$inputPrompt = $("#tagInputPrompt"); + me.$suggestion = $("#tagSuggestion"); + me._hideSuggestion(); - this.$inputPrompt.click(function(e) { + me.$inputPrompt.click(function(e) { me.$inputPrompt.hide(); me.$input.show().focus().val(""); e.preventDefault(); }); // 保存tag - this.$input.blur(function() { + me.$input.blur(function() { var val = me.$input.val(); if(val) { me.$input.val(""); @@ -125,19 +123,18 @@ var TagInput = function() { } }); - this.$input.keydown(function(e) { + me.$input.keydown(function(e) { if (e.keyCode == 13) { $(this).trigger("blur"); e.preventDefault(); } // TODO tag颜色调淡 - // TODO 目前不能选取suggested tag // TODO arrow key up // TODO arrow key down - // TODO delete + // TODO delete with backspace }); - this.$input.on("input", function(e) { + me.$input.on('input', function(e) { me.timer = setTimeout(function() { const val = me.$input.val(); if(val) { @@ -148,16 +145,18 @@ var TagInput = function() { } }, 200); }); - - this.$suggestion.delegate("click", "li", function(event) { - var $li = $(this); - console.error($li); - me._addTag($li.text(), true); - }); - this.$tags.on("click", "i", function() { + me.$tags.on('click', 'i', function() { me._removeTag($(this).parent()); }); + + // 不能使用click事件,否则会在input的blur事件之后触发 + me.$suggestion.on('mousedown', 'li', function(e) { + var $li = $(this); + me._addTag($li.text(), true); + e.preventDefault(); + me.$input.val(''); + }); } TagInput.prototype = { @@ -176,7 +175,7 @@ TagInput.prototype = { // called by Note clearTags: function() { - this.$tags.html(""); + this.$tags.html(''); }, // called by Note @@ -184,8 +183,7 @@ TagInput.prototype = { if(isEmpty(tags) || !Array.isArray(tags)) { return; } - // console.warn("input settags", tags); - this.$tags.html(""); + this.$tags.html(''); for(var i = 0; i < tags.length; ++i) { this._addTag(tags[i]); } @@ -242,10 +240,10 @@ TagInput.prototype = { }, _showSuggestion: function(keyword) { + var me = this; if(!keyword) { return; } - var me = this; this.$suggestion.html(''); TagService.getTags(function(tags) { var texts = tags @@ -255,12 +253,13 @@ TagInput.prototype = { .filter(function(text) { return text.startsWith(keyword); }) - .slice(0, 6) - .sort(); + .sort() + .slice(0, 6); texts.forEach(function(text) { me.$suggestion.prepend($('
  • ' + text + '
  • ')); }); me.$suggestion.children().last().addClass("selected"); + if(texts.length > 0) { $('#tagInputGroup').addClass('open'); } @@ -271,7 +270,7 @@ TagInput.prototype = { }, _hideSuggestion: function() { - $("#tagInputGroup").removeClass("open"); + $('#tagInputGroup').removeClass('open'); }, }; diff --git a/public/themes/default.css b/public/themes/default.css index 9ca11c37..a33e68d4 100644 --- a/public/themes/default.css +++ b/public/themes/default.css @@ -1020,7 +1020,7 @@ h3 { #tagSuggestion { left: unset; - right: unset; + right: unset; } #tagSuggestion li { line-height: 20px; From 912bfbe161fb5dc88501d52f651f15be3b7d52be Mon Sep 17 00:00:00 2001 From: LucasYuNju Date: Thu, 15 Sep 2016 21:36:11 +0800 Subject: [PATCH 4/4] allow user to delete last tag by typing backspace --- note.html | 2 +- public/js/app/tag.js | 692 +++++++++++++++++++------------------- public/js/app/tagNew.js | 278 --------------- public/themes/default.css | 15 +- 4 files changed, 353 insertions(+), 634 deletions(-) delete mode 100644 public/js/app/tagNew.js diff --git a/note.html b/note.html index 4e088cbc..b7f241ef 100755 --- a/note.html +++ b/note.html @@ -660,7 +660,7 @@ window.debug = false; - + diff --git a/public/js/app/tag.js b/public/js/app/tag.js index eed56079..79f6df57 100644 --- a/public/js/app/tag.js +++ b/public/js/app/tag.js @@ -1,344 +1,348 @@ -// // Tag -// -// Tag.classes = { -// "蓝色": "label label-blue", -// "红色": "label label-red", -// "绿色": "label label-green", -// "黄色": "label label-yellow", -// "blue": "label label-blue", -// "red": "label label-red", -// "green": "label label-green", -// "yellow": "label label-yellow" -// } -// -// // 数据库中统一存En -// Tag.mapCn2En = { -// "蓝色": "blue", -// "红色": "red", -// "绿色": "green", -// "黄色": "yellow", -// } -// Tag.mapEn2Cn = { -// "blue": "蓝色", -// "red": "红色", -// "green": "绿色", -// "yellow": "黄色", -// } -// Tag.isColorTag = function(tag) { -// return tag == 'blue' || tag == 'red' || tag == 'green' || tag == 'yellow'; -// } -// -// Tag.t = $("#tags"); -// -// // called by Note -// Tag.getTags = function() { -// var tags = []; -// Tag.t.children().each(function(){ -// var text = $(this).data('tag'); -// text = Tag.mapCn2En[text] || text; -// tags.push(text); -// }); -// // 需要去重吗? 正常情况下不会重复 -// return tags; -// } -// -// // called by Note -// Tag.clearTags = function() { -// Tag.t.html(""); -// } -// -// // 设置tags -// // called by Note -// Tag.renderTags = function(tags) { -// Tag.t.html(""); -// if(isEmpty(tags)) { -// return; -// } -// // TODO 重构, 这样不高效 -// for(var i = 0; i < tags.length; ++i) { -// var tag = tags[i]; -// Tag.appendTag(tag); -// } -// }; -// -// function hideTagList(event) { -// $("#tagDropdown").removeClass("open"); -// if (event) { -// event.stopPropagation() -// } -// } -// function showTagList(event) { -// $("#tagDropdown").addClass("open"); -// if (event) { -// event.stopPropagation() -// } -// } -// -// // 添加tag -// // tag = {classes:"label label-red", text:"红色"} -// // tag = life -// Tag.appendTag = function(tag, save) { -// var isColor = false; -// var classes, text; -// -// if (typeof tag == "object") { -// classes = tag.classes; -// text = tag.text; -// if(!text) { -// return; -// } -// } else { -// tag = $.trim(tag); -// text = tag; -// if(!text) { -// return; -// } -// var classes = Tag.classes[text]; -// if(classes) { -// isColor = true; -// } else { -// classes = "label label-default"; -// } -// } -// var rawText = text; -// if(Tag.isColorTag(text)) { -// text = getMsg(text); -// } -// -// text = trimTitle(text); -// -// tag = tt('?X', classes, rawText, text); -// -// // 避免重复 -// var isExists = false; -// $("#tags").children().each(function() { -// if (isColor) { -// var tagHtml = $("
    ").append($(this).clone()).html(); -// if (tagHtml == tag) { -// $(this).remove(); -// isExists = true; -// } -// } else if (text + "X" == $(this).text()) { -// $(this).remove(); -// isExists = true; -// } -// }); -// -// $("#tags").append(tag); -// -// hideTagList(); -// -// if (!isColor) { -// reRenderTags(); -// } -// -// if(save) { -// // 如果之前不存, 则添加之 -// if(!isExists) { -// Note.curChangedSaveIt(true, function() { -// TagService.addOrUpdateTag(rawText, function(ret) { -// if(typeof ret == 'object' && ret.Ok !== false) { -// Tag.addTagNav(ret); -// } -// }); -// }); -// } -// } -// }; -// -// // nodejs端调用 -// Tag.addTagsNav = function(tags) { -// tags = tags || []; -// for(var i = 0; i < tags.length; ++i) { -// Tag.addTagNav(tags[i]); -// } -// }; -// -// // 删除, nodejs调用 -// Tag.deleteTagsNav = function(tags) { -// tags = tags || []; -// for(var i = 0; i < tags.length; ++i) { -// var title = tags[i]; -// $('#myTag li[data-tag="' + title + '"]').remove(); -// } -// }; -// -// // 为了颜色间隔, add, delete时调用 -// function reRenderTags() { -// var defautClasses = [ "label label-default", "label label-info" ]; -// var i = 0; -// $("#tags").children().each( -// function() { -// var thisClasses = $(this).attr("class"); -// if (thisClasses == "label label-default" -// || thisClasses == "label label-info") { -// $(this).removeClass(thisClasses).addClass( -// defautClasses[i % 2]); -// i++; -// } -// }); -// }; -// -// // 删除tag -// Tag.removeTag = function($target) { -// var tag = $target.data('tag'); -// $target.remove(); -// reRenderTags(); -// Note.curChangedSaveIt(true, function() { -// TagService.addOrUpdateTag(tag, function(ret) { -// if(typeof ret == 'object' && ret.Ok !== false) { -// Tag.addTagNav(ret); -// } -// }); -// }); -// }; -// -// //----------- -// // 左侧nav en -> cn -// Tag.tags = []; -// Tag.renderTagNav = function(tags) { -// var me = this; -// tags = tags || []; -// Tag.tags = tags; -// $("#tagNav").html(''); -// for(var i in tags) { -// var noteTag = tags[i]; -// var tag = noteTag.Tag; -// var text = tag; -// -// if(Tag.isColorTag(text)) { -// text = getMsg(text); -// } -// -// text = trimTitle(text); -// var classes = Tag.classes[tag] || "label label-default"; -// // 笔记数量先隐藏, 不准确 -// $("#tagNav").append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); -// } -// -// if(tags.length == 0) { -// $("#tagNav").html('

    ' + getMsg('No tag') + '

    '); -// } -// }; -// -// // 添加的标签重新render到左边, 放在第一个位置 -// Tag.addTagNav = function(newTag) { -// var me = this; -// for(var i in me.tags) { -// var noteTag = me.tags[i]; -// if(noteTag.Tag == newTag.Tag) { -// me.tags.splice(i, 1); -// break; -// } -// } -// me.tags.unshift(newTag); -// me.renderTagNav(me.tags); -// }; -// -// Tag.searchTag = function(tag, noteId) { -// // 1 -// Note.curChangedSaveIt(); -// -// // 2 先清空所有 -// // 也会把curNoteId清空 -// Note.clearAll(); -// -// var tagCn = tag; -// if(Tag.isColorTag(tag)) { -// tagCn = getMsg(tag); -// } -// -// var tagTitle = '' + trimTitle(tagCn) + ''; -// -// Notebook.changeCurNotebookTitle(tagTitle, false, '', true); -// Tag.curTag = tag; -// -// NoteService.searchNoteByTag(tag, function(notes) { -// hideLoading(); -// if(notes) { -// // 和note搜索一样 -// // 设空, 防止发生上述情况 -// // Note.curNoteId = ""; -// Note.renderNotes(notes); -// Note.renderNotesAndTargetNote(notes, noteId); -// } -// }); -// }; -// -// -// // 事件 -// $(function() { -// // tag input box -// $("#addTagTrigger").click(function() { -// $(this).hide(); -// $("#addTagInput").show().focus().val(""); -// }); -// -// $("#addTagInput").click(function(event) { -// showTagList(event); -// }); -// -// $("#addTagInput").blur(function() { -// var val = $(this).val(); -// if(val) { -// Tag.appendTag(val, true); -// } -// return; -// // 下面不能有, 有就有问题 -// $("#addTagTrigger").show(); -// $("#addTagInput").hide(); -// // revertTagStatus(); -// }); -// $('#addTagInput').keydown(function(e) { -// if (e.keyCode == 13) { -// hideTagList(); -// // 如果有值, 再生成, 没值直接隐藏 -// if ($("#addTagInput").val()) { -// $(this).trigger("blur"); -// $("#addTagTrigger").trigger("click"); -// } else { -// $(this).trigger("blur"); -// } -// } -// }); -// // 点击下拉时也会触发input的blur事件 -// $("#tagColor li").click(function(event) { -// var a; -// if($(this).attr("role")) { -// a = $(this).find("span"); -// } else { -// a = $(this); -// } -// Tag.appendTag({ -// classes : a.attr("class"), -// text : a.text() -// }, true); -// }); -// -// $("#tags").on("click", "i", function() { -// Tag.removeTag($(this).parent()); -// }); -// -// // tag nav -// function deleteTag() { -// $li = $(this).closest('li'); -// var tag = $.trim($li.data("tag")); -// if(confirm(getMsg("Are you sure ?"))) { -// TagService.deleteTag(tag, function(re) { -// if(typeof re == "object" && re.Ok !== false) { -// Note.deleteNoteTag(re, tag); -// $li.remove(); -// } -// }); -// }; -// } -// -// function searchTag() { -// var $li = $(this).closest('li'); -// var tag = $.trim($li.data("tag")); -// Tag.searchTag(tag); -// }; -// -// $("#tagNav").on("click", "li .label", searchTag); -// $("#tagNav").on("click", "li .tag-delete", deleteTag); -// }); +/** + * tag navigator + */ +var TagNav = function() { + this.tags = []; + this.curTag = null; + this.$element = $('#tagNav'); + this.$element.on('click', 'li .label', function() { + var tagValue = $(this).closest('li').data('tag').trim(); + this._searchByTag(tagValue); + }); + this.$element.on('click', 'li .tag-delete', this._deleteTag); +}; + +TagNav.prototype = { + constructor: TagNav, + _searchByTag: function(tag, noteId) { + Note.curChangedSaveIt(); + // 清空所有,也会把curNoteId清空 + Note.clearAll(); + + var tagTitle = '' + trimTitle(tag) + ''; + + Notebook.changeCurNotebookTitle(tagTitle, false, '', true); + this.curTag = tag; + + NoteService.searchNoteByTag(tag, function(notes) { + hideLoading(); + if(notes) { + Note.renderNotes(notes); + Note.renderNotesAndTargetNote(notes, noteId); + } + }); + }, + + _deleteTag: function() { + $li = $(this).closest('li'); + var tag = $.trim($li.data('tag')); + if(confirm(getMsg('Are you sure ?'))) { + TagService.deleteTag(tag, function(re) { + if(typeof re == 'object' && re.Ok !== false) { + Note.deleteNoteTag(re, tag); + $li.remove(); + } + }); + }; + }, + + // called by node: web.js + deleteTags: function(tags) { + tags = tags || []; + for(var i = 0; i < tags.length; ++i) { + var title = tags[i]; + $('#myTag li[data-tag="' + title + '"]').remove(); + } + }, + + // called by node: web.js + // 添加标签,并重绘到左侧 + addTags: function(tags) { + tags = tags || []; + // 去重,将添加的标签放在第一个位置 + for(var i = 0; i < tags.length; ++i) { + for(var j in this.tags) { + if(this.tags[j].Tag == tags[i].Tag) { + this.tags.splice(j, 1); + break; + } + } + this.tags.unshift(tags[i]); + } + this.setTags(this.tags); + }, + + // called by page.js + // 更新tags,并重绘到左侧 + setTags: function(tags) { + this.tags = tags || []; + $('#tagNav').html(''); + for(var i in this.tags) { + var noteTag = this.tags[i]; + var tag = noteTag.Tag; + var text = tag; + + text = trimTitle(text); + var classes = 'label label-default'; + // 笔记数量先隐藏, 不准确 + $('#tagNav').append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); + } + + if(this.tags.length == 0) { + $('#tagNav').html('

    ' + getMsg('No tag') + '

    '); + } + }, +}; + + +/** + * tag edit area of editor + */ +var TagInput = function() { + var me = this; + me.tags = []; //array of strings + me.numSuggestions = 0; + me.selectedSuggestion = 0; + me.$tags = $("#tags"); + me.$input = $("#tagInput"); + me.$inputPrompt = $("#tagInputPrompt"); + me.$suggestions = $("#tagSuggestion"); + me._hideSuggestion(); + + me.$inputPrompt.click(function(e) { + me.$inputPrompt.hide(); + me.$input.show().focus().val(""); + }); + + // 保存tag + me.$input.blur(function() { + var val = me.$input.val(); + me._hideSuggestion(); + if(val) { + me.$input.val(''); + me._addTag(val, true); + } + }); + + me.$input.keydown(function(e) { + switch (e.keyCode) { + case 8: + me._onBackSpace(e); + break; + case 13: + me._onEnter(e); + break; + case 27: + me._onEscape(e); + break; + case 38: + me._onUpArrow(e); + break; + case 40: + me._onDownArrow(e); + break; + default: + } + }); + + me.$input.on('input', function(e) { + if(me.timer) { + clearTimeout(me.timer); + } + me.timer = setTimeout(function() { + var val = me.$input.val(); + if(val) { + me._showSuggestion(val); + } + else { + me._hideSuggestion(); + } + }, 200); + }); + + me.$tags.on('click', 'i', function() { + me._removeTag($(this).parent()); + }); + + // 使用click事件的话,就无法阻止input的blur事件触发 + me.$suggestions.on('mousedown', 'li', function(e) { + var $li = $(this); + me._addTag($li.text(), true); + e.preventDefault(); + me.$input.val(''); + }); +} + +TagInput.prototype = { + constructor: TagInput, + + // called by Note + getTags: function() { + var tags = []; + this.$tags.children().each(function(){ + var text = $(this).data('tag'); + tags.push(text); + }); + // 正常情况下不会重复 + return tags; + }, + + // called by Note + clearTags: function() { + this.$tags.html(''); + }, + + // called by Note + setTags: function(tags) { + if(!Array.isArray(tags)) { + return; + } + this.$tags.html(''); + for(var i = 0; i < tags.length; ++i) { + this._addTag(tags[i]); + } + }, + + // tag应该是string的,也可能是number + _addTag: function(tag, save) { + if(!tag) { + return; + } + var classes = "label label-default", + text = (tag + "").trim(), + escapedText = trimTitle(text); + + // 取出tags中重复 + var duplicate = false; + this.$tags.children().each(function() { + if (escapedText + "X" == $(this).text()) { + $(this).remove(); + duplicate = true; + } + }); + + this.$tags.append(tt('?X', classes, text, escapedText)); + + if(save && !duplicate) { + this._saveTag(text); + } + }, + + // 保存tag + _saveTag(text) { + if(text) + { + Note.curChangedSaveIt(true, function() { + TagService.addOrUpdateTag(text, function(ret) { + if(typeof ret == 'object' && ret.Ok !== false) { + Tag.nav.addTags([ret]); + } + }); + }); + } + }, + + // 删除tag + _removeTag: function($target) { + var text = $target.data('tag'); + $target.remove(); + if(text) { + Note.curChangedSaveIt(true, function() { + TagService.addOrUpdateTag(text, function(ret) { + if(typeof ret == 'object' && ret.Ok !== false) { + // 刚删除的tag不需要放到nav的第一个 + // Tag.nav.addTags([ret]); + } + }); + }); + } + }, + + _showSuggestion: function(keyword) { + // alert("show suggest"); + var me = this; + if(!keyword) { + return; + } + keyword = keyword.toLowerCase(); + this.$suggestions.html(''); + TagService.getTags(function(tags) { + var texts = tags + .map(function(tag) { + return tag.Tag + ''; + }) + .filter(function(text) { + return text.toLowerCase().startsWith(keyword); + }) + .sort() + .slice(0, 6); + texts.forEach(function(text) { + me.$suggestions.append($(`
  • ${text}
  • `)); + }); + + // placeholder tag that represent current input + me.$suggestions.prepend($(``)); + me.selectedSuggestion = 0; + me.numSuggestions = texts.length; + + if(texts.length > 0) { + $('#tagInputGroup').addClass('open'); + } + else { + $('#tagInputGroup').removeClass('open'); + } + }); + }, + + _hideSuggestion: function() { + $('#tagInputGroup').removeClass('open'); + }, + + _selectSuggestion: function(index) { + if(this.numSuggestions) { + this.$suggestions.children().eq(this.selectedSuggestion).removeClass("selected"); + var $suggestion = this.$suggestions.children().eq(index); + $suggestion.addClass("selected"); + this.$input.val($suggestion.text()); + this.$input[0].setSelectionRange($suggestion.text().length, $suggestion.text().length); + this.selectedSuggestion = index; + } + }, + + _onBackSpace: function(e) { + var val = this.$input.val(); + if(!val) { + this._removeTag(this.$tags.children().last()); + e.preventDefault(); + } + }, + + _onEnter: function(e) { + var val = this.$input.val(); + this._hideSuggestion(); + if(val) { + this.$input.val(''); + this._addTag(val, true); + } + }, + + _onEscape: function(e) { + this.$input.val(''); + this.$input.trigger('blur'); + }, + + _onUpArrow: function(e) { + var index = (this.selectedSuggestion - 1) % (this.numSuggestions + 1); + this._selectSuggestion(index); + e.preventDefault(); + }, + + _onDownArrow: function(e) { + var index = (this.selectedSuggestion + 1) % (this.numSuggestions + 1); + this._selectSuggestion(index); + e.preventDefault(); + } +}; + +Tag.nav = new TagNav(); +Tag.input = new TagInput(); diff --git a/public/js/app/tagNew.js b/public/js/app/tagNew.js deleted file mode 100644 index aec38681..00000000 --- a/public/js/app/tagNew.js +++ /dev/null @@ -1,278 +0,0 @@ -/** - * tag navigator - */ -var TagNav = function() { - this.tags = []; - this.curTag = null; - this.$element = $('#tagNav'); - this.$element.on('click', 'li .label', function() { - var tagValue = $(this).closest('li').data('tag').trim(); - this._searchByTag(tagValue); - }); - this.$element.on('click', 'li .tag-delete', this._deleteTag); -}; - -TagNav.prototype = { - constructor: TagNav, - _searchByTag: function(tag, noteId) { - Note.curChangedSaveIt(); - // 清空所有,也会把curNoteId清空 - Note.clearAll(); - - var tagTitle = '' + trimTitle(tag) + ''; - - Notebook.changeCurNotebookTitle(tagTitle, false, '', true); - this.curTag = tag; - - NoteService.searchNoteByTag(tag, function(notes) { - hideLoading(); - if(notes) { - Note.renderNotes(notes); - Note.renderNotesAndTargetNote(notes, noteId); - } - }); - }, - - _deleteTag: function() { - $li = $(this).closest('li'); - var tag = $.trim($li.data('tag')); - if(confirm(getMsg('Are you sure ?'))) { - TagService.deleteTag(tag, function(re) { - if(typeof re == 'object' && re.Ok !== false) { - Note.deleteNoteTag(re, tag); - $li.remove(); - } - }); - }; - }, - - // called by node: web.js - deleteTags: function(tags) { - tags = tags || []; - for(var i = 0; i < tags.length; ++i) { - var title = tags[i]; - $('#myTag li[data-tag="' + title + '"]').remove(); - } - }, - - // called by node: web.js - // 添加标签,并重绘到左侧 - addTags: function(tags) { - tags = tags || []; - // 去重,将添加的标签放在第一个位置 - for(var i = 0; i < tags.length; ++i) { - for(var j in this.tags) { - if(this.tags[j].Tag == tags[i].Tag) { - this.tags.splice(j, 1); - break; - } - } - this.tags.unshift(tags[i]); - } - this.setTags(this.tags); - }, - - // called by page.js - // 更新tags,并重绘到左侧 - setTags: function(tags) { - this.tags = tags || []; - $('#tagNav').html(''); - for(var i in this.tags) { - var noteTag = this.tags[i]; - var tag = noteTag.Tag; - var text = tag; - - text = trimTitle(text); - var classes = 'label label-default'; - // 笔记数量先隐藏, 不准确 - $('#tagNav').append(tt('
  • ? (?) X
  • ', tag, classes, text, noteTag.Count)); - } - - if(this.tags.length == 0) { - $('#tagNav').html('

    ' + getMsg('No tag') + '

    '); - } - }, -}; - - -/** - * tag edit area of editor - */ -var TagInput = function() { - var me = this; - me.tags = []; //array of strings - me.$tags = $("#tags"); - me.$input = $("#tagInput"); - me.$inputPrompt = $("#tagInputPrompt"); - me.$suggestion = $("#tagSuggestion"); - me._hideSuggestion(); - - me.$inputPrompt.click(function(e) { - me.$inputPrompt.hide(); - me.$input.show().focus().val(""); - e.preventDefault(); - }); - - // 保存tag - me.$input.blur(function() { - var val = me.$input.val(); - if(val) { - me.$input.val(""); - me._addTag(val, true); - me._hideSuggestion(); - } - }); - - me.$input.keydown(function(e) { - if (e.keyCode == 13) { - $(this).trigger("blur"); - e.preventDefault(); - } - // TODO tag颜色调淡 - // TODO arrow key up - // TODO arrow key down - // TODO delete with backspace - }); - - me.$input.on('input', function(e) { - me.timer = setTimeout(function() { - const val = me.$input.val(); - if(val) { - me._showSuggestion(val); - } - else { - me._hideSuggestion(); - } - }, 200); - }); - - me.$tags.on('click', 'i', function() { - me._removeTag($(this).parent()); - }); - - // 不能使用click事件,否则会在input的blur事件之后触发 - me.$suggestion.on('mousedown', 'li', function(e) { - var $li = $(this); - me._addTag($li.text(), true); - e.preventDefault(); - me.$input.val(''); - }); -} - -TagInput.prototype = { - constructor: TagInput, - - // called by Note - getTags: function() { - var tags = []; - this.$tags.children().each(function(){ - var text = $(this).data('tag'); - tags.push(text); - }); - // 正常情况下不会重复 - return tags; - }, - - // called by Note - clearTags: function() { - this.$tags.html(''); - }, - - // called by Note - setTags: function(tags) { - if(isEmpty(tags) || !Array.isArray(tags)) { - return; - } - this.$tags.html(''); - for(var i = 0; i < tags.length; ++i) { - this._addTag(tags[i]); - } - }, - - // tag应该是string的,也可能是number - _addTag: function(tag, save) { - if(!tag) { - return; - } - var classes = "label label-default", - text = (tag + "").trim(), - escapedText = trimTitle(text); - - // 取出tags中重复 - var duplicate = false; - this.$tags.children().each(function() { - if (escapedText + "X" == $(this).text()) { - $(this).remove(); - duplicate = true; - } - }); - - this.$tags.append(tt('?X', classes, text, escapedText)); - - if(save && !duplicate) { - this._saveTag(text); - } - }, - - // 保存tag - _saveTag(text) { - Note.curChangedSaveIt(true, function() { - TagService.addOrUpdateTag(text, function(ret) { - if(typeof ret == 'object' && ret.Ok !== false) { - Tag.nav.addTags([ret]); - } - }); - }); - }, - - // 删除tag - _removeTag: function($target) { - // TODO 这里调的服务不对吧 - var tag = $target.data('tag'); - $target.remove(); - Note.curChangedSaveIt(true, function() { - TagService.addOrUpdateTag(tag, function(ret) { - if(typeof ret == 'object' && ret.Ok !== false) { - Tag.nav.addTags([ret]); - } - }); - }); - }, - - _showSuggestion: function(keyword) { - var me = this; - if(!keyword) { - return; - } - this.$suggestion.html(''); - TagService.getTags(function(tags) { - var texts = tags - .map(function(tag) { - return tag.Tag + ''; - }) - .filter(function(text) { - return text.startsWith(keyword); - }) - .sort() - .slice(0, 6); - texts.forEach(function(text) { - me.$suggestion.prepend($('
  • ' + text + '
  • ')); - }); - me.$suggestion.children().last().addClass("selected"); - - if(texts.length > 0) { - $('#tagInputGroup').addClass('open'); - } - else { - $('#tagInputGroup').removeClass('open'); - } - }); - }, - - _hideSuggestion: function() { - $('#tagInputGroup').removeClass('open'); - }, -}; - -Tag.nav = new TagNav(); -Tag.input = new TagInput(); diff --git a/public/themes/default.css b/public/themes/default.css index a33e68d4..11b0e6a8 100644 --- a/public/themes/default.css +++ b/public/themes/default.css @@ -332,24 +332,17 @@ h3 { margin-right: 4px; } #tags { + /*magical height to vertically center label*/ + /*height: 36px;*/ display: block; padding: 0; margin: 0; - list-style: none; -} -#tags li { - float: left; - height: 20px; - line-height: 20px; - margin-top: 5px; - margin-right: 2px; + margin-top: -2px; } #tags .label { + /*line-height: 26;*/ margin-right: 2px; } -#tagInputGroup { - float: left; -} #editor, #mdEditor {