diff --git a/public/js/app/attachment_upload.js b/public/js/app/attachment_upload.js new file mode 100644 index 0000000..8b25956 --- /dev/null +++ b/public/js/app/attachment_upload.js @@ -0,0 +1,212 @@ +// upload attachment +// 依赖note +var urlPrefix = UrlPrefix; +define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){ + // Helper function that formats the file sizes + function formatFileSize(bytes) { + if (typeof bytes !== 'number') { + return ''; + } + if (bytes >= 1000000000) { + return (bytes / 1000000000).toFixed(2) + ' GB'; + } + if (bytes >= 1000000) { + return (bytes / 1000000).toFixed(2) + ' MB'; + } + return (bytes / 1000).toFixed(2) + ' KB'; + } + + function setDropStyle(dropzoneId, formId) { + // drag css + var dropZone = $(dropzoneId); + $(formId).bind('dragover', function (e) { + e.preventDefault(); + var timeout = window.dropZoneTimeoutAttach; + if(timeout) { + clearTimeout(timeout); + } + + var found = false, + node = e.target; + do { + if (node === dropZone[0]) { + found = true; + break; + } + node = node.parentNode; + } while (node != null); + if (found) { + dropZone.addClass('hover'); + } else { + dropZone.removeClass('hover'); + } + window.dropZoneTimeoutAttach = setTimeout(function () { + window.dropZoneTimeoutAttach = null; + dropZone.removeClass('in hover'); + }, 100); + }); + } + + setDropStyle("#dropAttach", "#uploadAttach"); + setDropStyle("#dropAvatar", "#uploadAvatar"); + + var initUploader = function() { + $('.dropzone .btn-choose-file').click(function() { + $(this).parent().find('input').click(); + }); + + var $msg = $('#attachUploadMsg'); + // Initialize the jQuery File Upload plugin + $('#uploadAttach').fileupload({ + dataType: 'json', + // This element will accept file drag/drop uploading + dropZone: $('#dropAttach'), + formData: function(form) { + return [{name: 'noteId', value: Note.curNoteId}] // 传递笔记本过去 + }, + // This function is called when a file is added to the queue; + // either via the browse button, or via drag/drop: + add: function(e, data) { + var note = Note.getCurNote(); + if(!note || note.IsNew) { + alert("This note hasn't saved, please save it firstly!") + return; + } + var tpl = $('
'); + + // Append the file name and file size + tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); + + // Add the HTML to the UL element + $msg.html(tpl); + data.context = $msg; + + // 检查文件大小 + var size = data.files[0].size; + var maxFileSize = +GlobalConfigs["uploadAttachSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { + tpl.find("img").remove(); + tpl.removeClass("alert-info").addClass("alert-danger"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + return; + } + + // Automatically upload the file once it is added to the queue + var jqXHR; + setTimeout(function() { + jqXHR = data.submit(); + }, 10); + }, + /* + progress: function (e, data) { + }, + */ + done: function(e, data) { + if (data.result.Ok == true) { + data.context.html(""); + Attach.addAttach(data.result.Item); + } else { + var re = data.result; + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + $("#uploadAttachMsg").scrollTop(1000); + }, + fail: function(e, data) { + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + + $("#uploadAttachMsg").scrollTop(1000); + } + }); + + //------------------- + + var $msg2 = $('#avatarUploadMsg'); + $('#uploadAvatar').fileupload({ + dataType: 'json', + dropZone: $('#dropAvatar'), + add: function(e, data) { + var tpl = $(''); + + // Append the file name and file size + tpl.append(data.files[0].name + ' [' + formatFileSize(data.files[0].size) + ']'); + + // Add the HTML to the UL element + $msg2.html(tpl); + data.context = $msg2; + + // 检查文件大小 + var size = data.files[0].size; + var maxFileSize = +GlobalConfigs["uploadAvatarSize"] || 100; + if(typeof size == 'number' && size > 1024 * 1024 * maxFileSize) { + tpl.find("img").remove(); + tpl.removeClass("alert-info").addClass("alert-danger"); + tpl.append(" Warning: File size is bigger than " + maxFileSize + "M"); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + return; + } + + // Automatically upload the file once it is added to the queue + var jqXHR; + setTimeout(function() { + jqXHR = data.submit(); + }, 10); + }, + done: function(e, data) { + if (data.result.Ok == true) { + data.context.html(""); + var re = data.result; + $("#avatar").attr("src", UrlPrefix + "/" + re.Id); + } else { + var re = data.result; + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.result.Msg); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + }, + fail: function(e, data) { + data.context.html(""); + var tpl = $(''); + tpl.append('Error: ' + data.files[0].name + ' [' + formatFileSize(data.files[0].size) + '] ' + data.errorThrown); + data.context.html(tpl); + setTimeout((function(tpl) { + return function() { + tpl.remove(); + } + })(tpl), 3000); + } + }); + } + + initUploader(); +}); \ No newline at end of file diff --git a/public/js/app/blog/common.js b/public/js/app/blog/common.js new file mode 100644 index 0000000..be4e505 --- /dev/null +++ b/public/js/app/blog/common.js @@ -0,0 +1,207 @@ +// 返回是否是re.Ok == true +function reIsOk(re) { + return re && typeof re == "object" && re.Ok; +} +function showAlert(id, msg, type, id2Focus) { + $(id).html(msg).removeClass("alert-danger").removeClass("alert-success").removeClass("alert-warning").addClass("alert-" + type).show(); + if(id2Focus) { + $(id2Focus).focus(); + } +} +function hideAlert(id, timeout) { + if(timeout) { + setTimeout(function() { + $(id).hide(); + }, timeout); + } else { + $(id).hide(); + } +} +function ajaxGet(url, param, func) { + $.get(url, param, func); +} +function ajaxPost(url, param, func) { + $.post(url, param, func); +} +function goLogin(){ + var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); + location.href = loginUrl; +} +function goRegister() { + var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); + location.href = registerUrl; +} +function needLogin() { + if(typeof visitUserInfo == "undefined" || !visitUserInfo || !visitUserInfo.UserId) { + // 弹框之 + var loginUrl = urlPrefix + '/login?from=' + encodeURI(location.href); + var registerUrl = urlPrefix + '/register?from=' + encodeURI(location.href); + var modal = BootstrapDialog.show({ + title: "你还未登录", + message: '?
? ?
?
?
? ?
?
?
? ?
?
"+getMsg("historiesNum")+'
#? class="each-content">??> '+getMsg("datetime")+': ? |
'+note.Content+"")}else{$("#noteReadContent").html(note.Content)}};Note.lastSearch=null;Note.lastKey=null;Note.lastSearchTime=new Date;Note.isOver2Seconds=false;Note.isSameSearch=function(key){var now=new Date;var duration=now.getTime()-Note.lastSearchTime.getTime();Note.isOver2Seconds=duration>2e3?true:false;if(!Note.lastKey||Note.lastKey!=key||duration>1e3){Note.lastKey=key;Note.lastSearchTime=now;return false}if(key==Note.lastKey){return true}Note.lastSearchTime=now;Note.lastKey=key;return false};Note.searchNote=function(){var val=$("#searchNoteInput").val();if(!val){Notebook.changeNotebook("0");return}if(Note.isSameSearch(val)){return}if(Note.lastSearch){Note.lastSearch.abort()}Note.curChangedSaveIt();Note.clearAll();showLoading();Note.lastSearch=$.post("/note/searchNote",{key:val},function(notes){hideLoading();if(notes){Note.lastSearch=null;Note.renderNotes(notes);if(!isEmpty(notes)){Note.changeNote(notes[0].NoteId,false)}}else{}})};Note.setNote2Blog=function(target){var noteId=$(target).attr("noteId");var note=Note.cache[noteId];var isBlog=true;if(note.IsBlog!=undefined){isBlog=!note.IsBlog}if(isBlog){$(target).find(".item-blog").show()}else{$(target).find(".item-blog").hide()}ajaxPost("/note/setNote2Blog",{noteId:noteId,isBlog:isBlog},function(ret){if(ret){Note.setNoteCache({NoteId:noteId,IsBlog:isBlog},false)}})};Note.setAllNoteBlogStatus=function(notebookId,isBlog){if(!notebookId){return}var notes=Note.getNotesByNotebookId(notebookId);if(!isArray(notes)){return}var len=notes.length;if(len==0){for(var i in Note.cache){if(Note.cache[i].NotebookId==notebookId){Note.cache[i].IsBlog=isBlog}}}else{for(var i=0;i
?
? ?
?
?
? ?
?
?
? ?
?
" + getMsg("historiesNum") + '
#? class="each-content">??> ' + getMsg("datetime") + ': ? |
' + note.Content + ""); + } else { + $("#noteReadContent").html(note.Content); + } +} + +//--------------------------- +// 搜索 +// 有点小复杂, 因为速度过快会导致没加载完, 然后就保存上一个 => 致使标题没有 +// 为什么会标题没有? +Note.lastSearch = null; +Note.lastKey = null; // 判断是否与上一个相等, 相等就不查询, 如果是等了很久再按enter? +Note.lastSearchTime = new Date(); +Note.isOver2Seconds = false; +Note.isSameSearch = function(key) { + // 判断时间是否超过了1秒, 超过了就认为是不同的 + var now = new Date(); + var duration = now.getTime() - Note.lastSearchTime.getTime(); + Note.isOver2Seconds = duration > 2000 ? true : false; + if(!Note.lastKey || Note.lastKey != key || duration > 1000) { + Note.lastKey = key; + Note.lastSearchTime = now; + return false; + } + + if(key == Note.lastKey) { + return true; + } + + Note.lastSearchTime = now; + Note.lastKey = key; + return false; +} + +Note.searchNote = function() { + var val = $("#searchNoteInput").val(); + if(!val) { + // 定位到all + Notebook.changeNotebook("0"); + return; + } + // 判断是否与上一个是相同的搜索, 是则不搜索 + if(Note.isSameSearch(val)) { + return; + } + + // 之前有, 还有结束的 + if(Note.lastSearch) { + Note.lastSearch.abort(); + } + + // 步骤与tag的搜索一样 + // 1 + Note.curChangedSaveIt(); + + // 2 先清空所有 + Note.clearAll(); + + // 发送请求之 + // 先取消上一个 + showLoading(); + Note.lastSearch = $.post("/note/searchNote", {key: val}, function(notes) { + hideLoading(); + if(notes) { + // 成功后设为空 + Note.lastSearch = null; + // renderNotes只是note列表加载, 右侧笔记详情还没加载 + // 这个时候, 定位第一个, 保存之前的, + // 如果: 第一次搜索, renderNotes OK, 还没等到changeNote时 + // 第二次搜索来到, Note.curChangedSaveIt(); + // 导致没有标题了 + // 不是这个原因, 下面的Note.changeNote会导致保存 + + // 设空, 防止发生上述情况 + // Note.curNoteId = ""; + + Note.renderNotes(notes); + if(!isEmpty(notes)) { + Note.changeNote(notes[0].NoteId, false/*, true || Note.isOver2Seconds*/); // isShare, needSaveChanged?, 超过2秒就要保存 + } + } else { + // abort的 + } + }); + // Note.lastSearch.abort(); +} + +//---------- +//设为blog/unset +Note.setNote2Blog = function(target) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var isBlog = true; + if(note.IsBlog != undefined) { + isBlog = !note.IsBlog; + } + // 标志添加/去掉 + if(isBlog) { + $(target).find(".item-blog").show(); + } else { + $(target).find(".item-blog").hide(); + } + ajaxPost("/note/setNote2Blog", {noteId: noteId, isBlog: isBlog}, function(ret) { + if(ret) { + Note.setNoteCache({NoteId: noteId, IsBlog: isBlog}, false); // 不清空NotesByNotebookId缓存 + } + }); +} + +// 设置notebook的blog状态 +// 当修改notebook是否是blog时调用 +Note.setAllNoteBlogStatus = function(notebookId, isBlog) { + if(!notebookId) { + return; + } + var notes = Note.getNotesByNotebookId(notebookId); + if(!isArray(notes)) { + return; + } + var len = notes.length; + if(len == 0) { + for(var i in Note.cache) { + if(Note.cache[i].NotebookId == notebookId) { + Note.cache[i].IsBlog = isBlog; + } + } + } else { + for(var i = 0; i < len; ++i) { + notes[i].IsBlog = isBlog; + } + } +} + +// 移动 +Note.moveNote = function(target, data) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var notebookId = data.notebookId; + + if(!note.IsTrash && note.NotebookId == notebookId) { + return; + } + + // 修改数量 + Notebook.incrNotebookNumberNotes(notebookId); + if(!note.IsTrash) { + Notebook.minusNotebookNumberNotes(note.NotebookId); + } + + ajaxGet("/note/moveNote", {noteId: noteId, notebookId: notebookId}, function(ret) { + if(ret && ret.NoteId) { + if(note.IsTrash) { + Note.changeToNext(target); + $(target).remove(); + Note.clearCacheByNotebookId(notebookId); + } else { + // 不是trash, 移动, 那么判断是当前是否是all下 + // 不在all下, 就删除之 + // 如果当前是active, 那么clearNoteInfo之 + if(!Notebook.curActiveNotebookIsAll()) { + Note.changeToNext(target); + if($(target).hasClass("item-active")) { + Note.clearNoteInfo(); + } + $(target).remove(); + } else { + // 不移动, 那么要改变其notebook title + $(target).find(".note-notebook").html(Notebook.getNotebookTitle(notebookId)); + } + + // 重新清空cache 之前的和之后的 + Note.clearCacheByNotebookId(note.NotebookId); + Note.clearCacheByNotebookId(notebookId); + } + + // 改变缓存 + Note.setNoteCache(ret) + } + }); +} + +// 复制 +// data是自动传来的, 是contextmenu数据 +Note.copyNote = function(target, data, isShared) { + var noteId = $(target).attr("noteId"); + var note = Note.cache[noteId]; + var notebookId = data.notebookId; + + // trash不能复制, 不能复制给自己 + if(note.IsTrash || note.NotebookId == notebookId) { + return; + } + + var url = "/note/copyNote"; + var data = {noteId: noteId, notebookId: notebookId}; + if(isShared) { + url = "/note/copySharedNote"; + data.fromUserId = note.UserId; + } + + ajaxGet(url, data, function(ret) { + if(ret && ret.NoteId) { + // 重新清空cache 之后的 + Note.clearCacheByNotebookId(notebookId); + // 改变缓存, 添加之 + Note.setNoteCache(ret) + } + }); + + // 增加数量 + Notebook.incrNotebookNumberNotes(notebookId) +} + +// 这里速度不慢, 很快 +Note.getContextNotebooks = function(notebooks) { + var moves = []; + var copys = []; + var copys2 = []; + for(var i in notebooks) { + var notebook = notebooks[i]; + var move = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.moveNote} + var copy = {text: notebook.Title, notebookId: notebook.NotebookId, action: Note.copyNote} + var copy2 = {text: notebook.Title, notebookId: notebook.NotebookId, action: Share.copySharedNote} + if(!isEmpty(notebook.Subs)) { + var mc = Note.getContextNotebooks(notebook.Subs); + move.items = mc[0]; + copy.items = mc[1]; + copy2.items = mc[2]; + move.type = "group"; + move.width = 150; + copy.type = "group"; + copy.width = 150; + copy2.type = "group"; + copy2.width = 150; + } + moves.push(move); + copys.push(copy); + copys2.push(copy2); + } + return [moves, copys, copys2]; +} +// Notebook调用 +Note.contextmenu = null; +Note.notebooksCopy = []; // share会用到 +Note.initContextmenu = function() { + var self = Note; + if(Note.contextmenu) { + Note.contextmenu.destroy(); + } + // 得到可移动的notebook + var notebooks = Notebook.everNotebooks; + var mc = self.getContextNotebooks(notebooks); + + var notebooksMove = mc[0]; + var notebooksCopy = mc[1]; + self.notebooksCopy = mc[2]; + + //--------------------- + // context menu + //--------------------- + var noteListMenu = { + width: 180, + items: [ + { text: getMsg("shareToFriends"), alias: 'shareToFriends', icon: "", faIcon: "fa-share-square-o", action: Note.listNoteShareUserInfo}, + { type: "splitLine" }, + { text: getMsg("publicAsBlog"), alias: 'set2Blog', faIcon: "fa-bold", action: Note.setNote2Blog }, + { text: getMsg("cancelPublic"), alias: 'unset2Blog', faIcon: "fa-undo", action: Note.setNote2Blog }, + //{ type: "splitLine" }, + //{ text: "分享到社区", alias: 'html2Image', icon: "", action: Note.html2Image}, + { type: "splitLine" }, + { text: getMsg("delete"), icon: "", faIcon: "fa-trash-o", action: Note.deleteNote }, + { text: getMsg("move"), alias: "move", faIcon: "fa-arrow-right", + type: "group", + width: 180, + items: notebooksMove + }, + { text: getMsg("copy"), alias: "copy", icon:"", faIcon: "fa-copy", + type: "group", + width: 180, + items: notebooksCopy + } + ], + onShow: applyrule, + onContextMenu: beforeContextMenu, + + parent: "#noteItemList", + children: ".item-my", + } + + function menuAction(target) { + // $('#myModal').modal('show') + showDialog("dialogUpdateNotebook", {title: "修改笔记本", postShow: function() { + }}); + } + function applyrule(menu) { + var noteId = $(this).attr("noteId"); + var note = Note.cache[noteId]; + if(!note) { + return; + } + // 要disable的items + var items = []; + + // 如果是trash, 什么都不能做 + if(note.IsTrash) { + items.push("shareToFriends"); + items.push("shareStatus"); + items.push("unset2Blog"); + items.push("set2Blog"); + items.push("copy"); + } else { + // 是否已公开为blog + if(!note.IsBlog) { + items.push("unset2Blog"); + } else { + items.push("set2Blog"); + } + + // 移动与复制不能是本notebook下 + var notebookTitle = Notebook.getNotebookTitle(note.NotebookId); + items.push("move." + notebookTitle); + items.push("copy." + notebookTitle); + } + + menu.applyrule({ + name: "target..", + disable: true, + items: items + }); + + } + function beforeContextMenu() { + return this.id != "target3"; + } + + // 这里很慢!! + Note.contextmenu = $("#noteItemList .item-my").contextmenu(noteListMenu); +} + +// 附件 +// 笔记的附件需要ajax获取 +// 建一张附件表? attachId, noteId, 其它信息 +// note里有attach_nums字段记录个数 +// [ok] +var Attach = { + loadedNoteAttachs: {}, // noteId => [attch1Info, attach2Info...] // 按笔记 + attachsMap: {}, // attachId => attachInfo + init: function() { + var self = this; + // 显示attachs + $("#showAttach").click(function(){ + self.renderAttachs(Note.curNoteId); + }); + // 防止点击隐藏 + self.attachListO.click(function(e) { + e.stopPropagation(); + }); + // 删除 + self.attachListO.on("click", ".delete-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + var t = this; + if(confirm("Are you sure to delete it ?")) { + $(t).button("loading"); + ajaxPost("/attach/deleteAttach", {attachId: attachId}, function(re) { + $(t).button("reset"); + if(reIsOk(re)) { + self.deleteAttach(attachId); + } else { + alert(re.Msg); + } + }); + } + }); + // 下载 + self.attachListO.on("click", ".download-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + window.open(UrlPrefix + "/attach/download?attachId=" + attachId); + // location.href = "/attach/download?attachId=" + attachId; + }); + // 下载全部 + self.downloadAllBtnO.click(function() { + window.open(UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId); + // location.href = "/attach/downloadAll?noteId=" + Note.curNoteId; + }); + + // make link + self.attachListO.on("click", ".link-attach", function(e) { + e.stopPropagation(); + var attachId = $(this).closest('li').data("id"); + var attach = self.attachsMap[attachId]; + var src = UrlPrefix + "/attach/download?attachId=" + attachId; + if(LEA.isMarkdownEditor() && MarkdownEditor) { + MarkdownEditor.insertLink(src, attach.Title); + } else { + tinymce.activeEditor.insertContent('' + attach.Title + ''); + } + }); + + // make all link + self.linkAllBtnO.on("click",function(e) { + e.stopPropagation(); + var note = Note.getCurNote(); + if(!note) { + return; + } + var src = UrlPrefix + "/attach/downloadAll?noteId=" + Note.curNoteId + var title = note.Title ? note.Title + ".tar.gz" : "all.tar.gz"; + + if(LEA.isMarkdownEditor() && MarkdownEditor) { + MarkdownEditor.insertLink(src, title); + } else { + tinymce.activeEditor.insertContent('' + title + ''); + } + }); + }, + attachListO: $("#attachList"), + attachNumO: $("#attachNum"), + attachDropdownO: $("#attachDropdown"), + downloadAllBtnO: $("#downloadAllBtn"), + linkAllBtnO: $("#linkAllBtn"), + // 添加笔记时 + clearNoteAttachNum: function() { + var self = this; + self.attachNumO.html("").hide(); + }, + renderNoteAttachNum: function(noteId, needHide) { + var self = this; + var note = Note.getNote(noteId); + if(note.AttachNum) { + self.attachNumO.html("(" + note.AttachNum + ")").show(); + self.downloadAllBtnO.show(); + self.linkAllBtnO.show(); + } else { + self.attachNumO.hide(); + self.downloadAllBtnO.hide(); + self.linkAllBtnO.hide(); + } + + // 隐藏掉 + if(needHide) { + self.attachDropdownO.removeClass("open"); + } + }, + _renderAttachs: function(attachs) { + var self = this; + // foreach 循环之 + /* +