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 e80e425b..bb525bba 100755 --- a/note.html +++ b/note.html @@ -182,10 +182,6 @@ function log(o) { @@ -468,26 +464,15 @@ function log(o) {
-
+
+
- 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..79f6df57 100644 --- a/public/js/app/tag.js +++ b/public/js/app/tag.js @@ -1,440 +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 = text.substring(0, text.length - 1); // 把X去掉 - 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); - } +/** + * 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); }; -// tag最初状态 -function revertTagStatus() { - $("#addTagTrigger").show(); - $("#addTagInput").hide(); - // hideTagList(); -} +TagNav.prototype = { + constructor: TagNav, + _searchByTag: function(tag, noteId) { + Note.curChangedSaveIt(); + // 清空所有,也会把curNoteId清空 + Note.clearAll(); -function hideTagList(event) { - $("#tagDropdown").removeClass("open"); - if (event) { - event.stopPropagation() - } -} -function showTagList(event) { - $("#tagDropdown").addClass("open"); - if (event) { - event.stopPropagation() - } -} + var tagTitle = '' + trimTitle(tag) + ''; -// 只读模式下显示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); - } -} + Notebook.changeCurNotebookTitle(tagTitle, false, '', true); + this.curTag = tag; -// 添加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); - } + 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(); + } + }, - text = trimTitle(text); + // 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); + }, - tag = tt('?X', classes, rawText, text); + // 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)); + } - // 避免重复 - 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到左边, 放在第一个位置 -// 重新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); - } - }); + if(this.tags.length == 0) { + $('#tagNav').html('

    ' + getMsg('No tag') + '

    '); + } + }, }; -// 事件 -$(function() { - // tag - $("#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); - }); - // 这是个问题, 为什么? 捕获不了事件?, 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()); - }); - //---------- - // - 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(); - } - }); - }; - } - - //------------- - // nav 标签搜索 - function searchTag() { - var $li = $(this).closest('li'); - var tag = $.trim($li.data("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()); + }); - Tag.searchTag(tag); - /* + // 使用click事件的话,就无法阻止input的blur事件触发 + me.$suggestions.on('mousedown', 'li', function(e) { + var $li = $(this); + me._addTag($li.text(), true); + e.preventDefault(); + me.$input.val(''); + }); +} - // tag = Tag.mapCn2En[tag] || tag; - - // 学习changeNotebook - - // 1 - Note.curChangedSaveIt(); - - // 2 先清空所有 - // 也会把curNoteId清空 - Note.clearAll(); - - // $("#tagSearch").html($li.html()).show(); +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(''); + }, - 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); - } - } - }); - */ - }; + // 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; + } + }); - $("#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 + 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/themes/default.css b/public/themes/default.css index ec73628a..29a2e46a 100644 --- a/public/themes/default.css +++ b/public/themes/default.css @@ -317,23 +317,33 @@ 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 { + /*magical height to vertically center label*/ + /*height: 36px;*/ display: block; - float: left; - line-height: 25px; - height: 25px; - margin-top: 0; + padding: 0; + margin: 0; + margin-top: -2px; } #tags .label { + /*line-height: 26;*/ margin-right: 2px; } -#tagDropdown { - float: left; -} + #editor, #mdEditor { position: absolute; @@ -567,7 +577,7 @@ h3 { visibility: hidden; display: block; } -#tagDropdown.open > .dropdown-menu { +#tagInputGroup.open > .dropdown-menu { animation: none; -webkit-animation: none; } @@ -993,22 +1003,31 @@ h3 { height: 30px; border-top: 1px solid #eee; } -#tag { +#tagInputBox { position: absolute; right: 0; top: 0; left: 5px; bottom: 0; } -#tagColor { - left: 10px; - top: -130px; + +#tagSuggestion { + left: unset; + right: unset; } -#tagColor:before { +#tagSuggestion li { + line-height: 20px; + height: 20px; +} +#tagSuggestion li.selected { + background-color: #4d9cfb; + color: white; +} +#tagSuggestion:before { content: ""; background-image: none; } -#addTagInput { +#tagInput { width: 100px; } #notesAndSort { @@ -2573,14 +2592,14 @@ a.raw:hover { } /*标签与其它工具*/ /* tag */ -#addTagInput { +#tagInput { line-height: 25px; display: none; padding: 0; border: none; background-color: #ffffff; } -#addTagInput:focus { +#tagInput:focus { outline: none; } .label-default {