Merge branch 'develop-feature'

This commit is contained in:
life
2014-09-21 22:20:29 +08:00
49 changed files with 1783 additions and 261 deletions

2
.gitignore vendored
View File

@ -17,4 +17,4 @@ app/tmp/main.go
.settings
.project
public/config.codekit
files

View File

@ -0,0 +1,212 @@
package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"strings"
"time"
"io"
"archive/tar"
"compress/gzip"
)
// 附件
type Attach struct {
BaseController
}
// 上传附件
func (c Attach) UploadAttach(noteId string) revel.Result {
re := c.uploadAttach(noteId)
return c.RenderJson(re)
}
func (c Attach) uploadAttach(noteId string) (re info.Re) {
var fileId = ""
var resultMsg = "error" // 错误信息
var Ok = false
var fileInfo info.Attach
re = info.NewRe()
defer func() {
re.Id = fileId // 只是id, 没有其它信息
re.Msg = resultMsg
re.Ok = Ok
re.Item = fileInfo
}()
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(noteId, c.GetUserId()) {
return re
}
file, handel, err := c.Request.FormFile("file")
if err != nil {
return re
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return re
}
// > 5M?
if(len(data) > 5 * 1024 * 1024) {
resultMsg = "File is bigger than 5M"
return re
}
// 生成上传路径
filePath := "files/" + c.GetUserId() + "/attachs"
dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755)
if err != nil {
return re
}
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename) // .doc
filename = NewGuid() + ext
toPath := dir + "/" + filename;
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return re
}
// add File to db
fileType := ""
if ext != "" {
fileType = strings.ToLower(ext[1:])
}
filesize := GetFilesize(toPath)
fileInfo = info.Attach{Name: filename,
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
UploadUserId: c.GetObjectUserId(),
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
id := bson.NewObjectId();
fileInfo.AttachId = id
fileId = id.Hex()
Ok = attachService.AddAttach(fileInfo)
fileInfo.Path = ""; // 不要返回
resultMsg = "success"
return re
}
// 删除附件
func (c Attach) DeleteAttach(attachId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
return c.RenderJson(re)
}
// get all attachs by noteId
func (c Attach) GetAttachs(noteId string) revel.Result {
re := info.NewRe()
re.Ok = true
re.List = attachService.ListAttachs(noteId, c.GetUserId())
return c.RenderJson(re)
}
// 下载附件
// 权限判断
func (c Attach) Download(attachId string) revel.Result {
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
path := attach.Path
if path == "" {
return c.RenderText("")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
}
func (c Attach) DownloadAll(noteId string) revel.Result {
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
return c.RenderText("")
}
// 得到文件列表
attachs := attachService.ListAttachs(noteId, c.GetUserId())
if attachs == nil || len(attachs) == 0 {
return c.RenderText("")
}
/*
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
*/
filename := note.Title + ".tar.gz"
if note.Title == "" {
filename = "all.tar.gz"
}
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}

View File

@ -3,11 +3,13 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"strconv"
"strings"
)
// 首页
@ -15,7 +17,7 @@ type File struct {
BaseController
}
// 上传图片 editor
// 过时 已弃用!
func (c File) UploadImage(renderHtml string) revel.Result {
if renderHtml == "" {
renderHtml = "file/image.html"
@ -30,36 +32,60 @@ func (c File) UploadImage(renderHtml string) revel.Result {
return c.RenderTemplate(renderHtml)
}
// 已弃用
func (c File) UploadImageJson(from, noteId string) revel.Result {
re := c.uploadImage(from, "");
return c.RenderJson(re)
}
// 上传的是博客logo
// TODO logo不要设置权限, 另外的目录
func (c File) UploadBlogLogo() revel.Result {
return c.UploadImage("file/blog_logo.html");
}
// 拖拉上传, pasteImage
func (c File) UploadImageJson(renderHtml, from string) revel.Result {
re := c.uploadImage(from, "");
re.Id = siteUrl + re.Id
// re.Id = re.Id
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
func (c File) PasteImage(noteId string) revel.Result {
re := c.uploadImage("pasteImage", "");
userId := c.GetUserId()
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
// 是否是有权限协作的
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
// 复制图片之, 图片复制给noteUserId
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
} else {
// 怎么可能在这个笔记下paste图片呢?
// 正常情况下不会
}
}
}
return c.RenderJson(re)
}
// leaui image plugin
// leaui image plugin upload image
func (c File) UploadImageLeaui(albumId string) revel.Result {
re := c.uploadImage("", albumId);
re.Id = siteUrl + re.Id
// re.Id = re.Id
return c.RenderJson(re)
}
// 上传图片, 公用方法
// upload image common func
func (c File) uploadImage(from, albumId string) (re info.Re) {
var fileUrlPath = ""
var fileId = ""
var resultCode = 0 // 1表示正常
var resultMsg = "内部错误" // 错误信息
var Ok = false
defer func() {
re.Id = fileUrlPath
re.Id = fileId // 只是id, 没有其它信息
re.Code = resultCode
re.Msg = resultMsg
re.Ok = Ok
@ -71,11 +97,10 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
}
defer file.Close()
// 生成上传路径
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
dir := revel.BasePath + "/public/" + fileUrlPath
fileUrlPath = "files/" + c.GetUserId() + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
Log(err)
return re
}
// 生成新的文件名
@ -126,8 +151,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
Path: fileUrlPath,
Size: filesize}
id := bson.NewObjectId();
fileInfo.FileId = id
fileId = id.Hex()
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
fileInfo.Path = ""; // 不要返回
re.Item = fileInfo
return re
@ -197,4 +226,27 @@ func (c File) UpgradeLeauiImage() revel.Result {
re.Msg = msg
return c.RenderJson(re)
}
}
//-----------
// 输出image
// 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
if path == "" {
return c.RenderText("")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderFile(file, revel.Inline) // revel.Attachment
}
// 协作时复制图片到owner
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
re := info.NewRe()
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re)
}

View File

@ -117,7 +117,6 @@ type NoteOrContent struct {
// 这里不能用json, 要用post
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
// 新添加note
LogJ(noteOrContent)
if noteOrContent.IsNew {
userId := c.GetObjectUserId();
myUserId := userId

View File

@ -25,6 +25,7 @@ var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var fileService *service.FileService
var attachService *service.AttachService
var pageSize = 1000
var defaultSortField = "UpdatedTime"
@ -56,12 +57,13 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail":true,
},
"oauth": map[string]bool{"githubCallback": true},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
// 在commonUrl里
// 在commonUrl里
if _, ok2 := v[method]; ok2 {
return false
}

View File

@ -36,6 +36,9 @@ var Suggestions *mgo.Collection
// Album & file(image)
var Albums *mgo.Collection
var Files *mgo.Collection
var Attachs *mgo.Collection
var NoteImages *mgo.Collection
// 初始化时连接数据库
func Init() {
@ -104,6 +107,9 @@ func Init() {
// Album & file
Albums = Session.DB(dbname).C("albums")
Files = Session.DB(dbname).C("files")
Attachs = Session.DB(dbname).C("attachs")
NoteImages = Session.DB(dbname).C("note_images")
}
func init() {

21
app/info/AttachInfo.go Normal file
View File

@ -0,0 +1,21 @@
package info
import (
"gopkg.in/mgo.v2/bson"
"time"
)
// Attach belongs to note
type Attach struct {
AttachId bson.ObjectId `bson:"_id,omitempty"` //
NoteId bson.ObjectId `bson:"NoteId"` //
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
Name string `Name` // file name, md5, such as 13232312.doc
Title string `Title` // raw file name
Size int64 `Size` // file size (byte)
Type string `Type` // file type, "doc" = word
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
CreatedTime time.Time `CreatedTime`
// FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
}

View File

@ -11,9 +11,11 @@ type File struct {
AlbumId bson.ObjectId `bson:"AlbumId"`
Name string `Name` // file name
Title string `Title` // file name or user defined for search
Size int64 `Size` // file size (byte)
Type string `Type` // file type, such as image/jpg
Path string `Path` // the file path, based on /upload
Size int64 `Size` // file size (byte)
Type string `Type` // file type, "" = image, "doc" = word
Path string `Path` // the file path
IsDefaultAlbum bool `IsDefaultAlbum`
CreatedTime time.Time `CreatedTime`
FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
}

12
app/info/NoteImage.go Normal file
View File

@ -0,0 +1,12 @@
package info
import (
"gopkg.in/mgo.v2/bson"
)
// 笔记内部图片
type NoteImage struct {
NoteImageId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
NoteId bson.ObjectId `bson:"NoteId"` // 笔记
ImageId bson.ObjectId `bson:"ImageId"` // 图片fileId
}

View File

@ -24,6 +24,8 @@ type Note struct {
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
AttachNum int `AttachNum` // 2014/9/21, attachments num
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
@ -54,11 +56,11 @@ type NoteAndContent struct {
// 每一个历史记录对象
type EachHistory struct {
UpdatedUserId bson.ObjectId `UpdatedUserId`
UpdatedTime time.Time `UpdatedTime`
Content string `Content`
UpdatedTime time.Time `UpdatedTime`
Content string `Content`
}
type NoteContentHistory struct {
NoteId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `bson:"UserId"` // 所属者
Histories []EachHistory `Histories`
}
NoteId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `bson:"UserId"` // 所属者
Histories []EachHistory `Histories`
}

View File

@ -4,6 +4,7 @@ import (
"strings"
"path/filepath"
"os"
"io"
)
// 分离文件名与扩展名(包含.)
@ -62,4 +63,18 @@ func ListDir(dir string) []string {
}
names, _ := f.Readdirnames(0)
return names
}
func CopyFile(srcName, dstName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}

View File

@ -266,4 +266,16 @@ func RandomPwd(num int) string {
}
return str
}
func InArray(arr []string, str string) bool {
if arr == nil {
return false
}
for _, v := range arr {
if v == str {
return true
}
}
return false
}

View File

@ -0,0 +1,175 @@
package service
import (
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"time"
"os"
"strings"
)
type AttachService struct {
}
// add attach
func (this *AttachService) AddAttach(attach info.Attach) bool {
attach.CreatedTime = time.Now()
ok := db.Insert(db.Attachs, attach)
if ok {
// 更新笔记的attachs num
this.updateNoteAttachNum(attach.NoteId, 1)
}
return ok
}
// 更新笔记的附件个数
// addNum 1或-1
func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int) bool {
num := db.Count(db.Attachs, bson.M{"NoteId": noteId})
/*
note := info.Note{}
note = noteService.GetNoteById(noteId.Hex())
note.AttachNum += addNum
if note.AttachNum < 0 {
note.AttachNum = 0
}
Log(note.AttachNum)
*/
return db.UpdateByQField(db.Notes, bson.M{"_id": noteId}, "AttachNum", num)
}
// list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs
}
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
return attachs
}
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
// Delete note to delete attas firstly
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
note := noteService.GetNoteById(noteId)
if note.UserId.Hex() == userId {
attachs := []info.Attach{}
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
for _, attach := range attachs {
attach.Path = strings.TrimLeft(attach.Path, "/")
os.Remove(revel.BasePath + "/" + attach.Path)
}
return true
}
return false
}
// delete attach
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
if(attach.AttachId != "") {
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
return false, "No Perm"
}
if db.Delete(db.Attachs, bson.M{"_id": bson.ObjectIdHex(attachId)}) {
this.updateNoteAttachNum(attach.NoteId, -1)
attach.Path = strings.TrimLeft(attach.Path, "/")
err := os.Remove(revel.BasePath + "/" + attach.Path)
if err == nil {
return true, "delete file error"
}
return false, "delete file error"
}
return false, "db error"
}
return false, "no such item"
}
// 获取文件路径
// 要判断是否具有权限
// userId是否具有attach的访问权限
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
if attachId == "" {
return
}
attach = info.Attach{}
db.Get(db.Attachs, attachId, &attach)
path := attach.Path
if path == "" {
return
}
note := noteService.GetNoteById(attach.NoteId.Hex())
// 判断权限
// 笔记是否是公开的
if note.IsBlog {
return
}
// 笔记是否是我的
if note.UserId.Hex() == userId {
return
}
// 我是否有权限查看或协作
if shareService.HasReadNotePerm(attach.NoteId.Hex(), userId) {
return
}
attach = info.Attach{}
return
}
// 复制笔记时需要复制附件
// noteService调用, 权限已判断
func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
attachs := []info.Attach{}
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
// 复制之
toNoteIdO := bson.ObjectIdHex(toNoteId)
for _, attach := range attachs {
attach.AttachId = ""
attach.NoteId = toNoteIdO
// 文件复制一份
_, ext := SplitFilename(attach.Name)
newFilename := NewGuid() + ext
dir := "files/" + toUserId + "/attachs"
filePath := dir + "/" + newFilename
err := os.MkdirAll(revel.BasePath + "/" + dir, 0755)
if err != nil {
return false
}
_, err = CopyFile(revel.BasePath + "/" + attach.Path, revel.BasePath + "/" + filePath)
if err != nil {
return false
}
attach.Name = newFilename
attach.Path = filePath
this.AddAttach(attach)
}
return true
}

View File

@ -1,7 +1,7 @@
package service
import (
// . "github.com/leanote/leanote/app/lea"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
@ -35,7 +35,7 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
files := []info.File{}
q := bson.M{"UserId": bson.ObjectIdHex(userId)}
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
if albumId != "" {
q["AlbumId"] = bson.ObjectIdHex(albumId);
} else {
@ -89,6 +89,7 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
if(file.FileId != "") {
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
// delete image
// TODO
err := os.Remove(revel.BasePath + "/public/" + file.Path)
if err == nil {
return true, ""
@ -103,4 +104,125 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
// update image title
func (this *FileService) UpdateImage(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
}
// 获取文件路径
// 要判断是否具有权限
// userId是否具有fileId的访问权限
func (this *FileService) GetFile(userId, fileId string) string {
if fileId == "" {
return ""
}
file := info.File{}
db.Get(db.Files, fileId, &file)
path := file.Path
if path == "" {
return ""
}
// 1. 判断权限
// 是否是我的文件
if userId != "" && file.UserId.Hex() == userId {
return path
}
// 得到使用过该fileId的所有笔记NoteId
// 这些笔记是否有public的, 若有则ok
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
noteIds := noteImageService.GetNoteIds(fileId)
if noteIds != nil && len(noteIds) > 0 {
// 这些笔记是否有public的
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
return path
}
// 若有共享给我的笔记?
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
return path
}
// 笔记本是否共享给我?
// 通过笔记得到笔记本
notes := []info.Note{}
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, &notes)
if notes != nil && len(notes) > 0 {
notebookIds := make([]bson.ObjectId, len(notes))
for i := 0; i < len(notes); i++ {
notebookIds[i] = notes[i].NotebookId
}
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
return path
}
}
}
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
if file.FromFileId != "" {
fromFile := info.File{}
db.Get2(db.Files, file.FromFileId, &fromFile)
if fromFile.UserId.Hex() == userId {
return fromFile.Path
}
}
return ""
}
// 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了
file2 := info.File{}
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
if file2.FileId != "" {
return true, file2.FileId.Hex();
}
// 复制之
file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
if file.FileId == "" || file.UserId.Hex() != userId {
return false, ""
}
_, ext := SplitFilename(file.Name)
newFilename := NewGuid() + ext
dir := "files/" + toUserId + "/images"
filePath := dir + "/" + newFilename
err := os.MkdirAll(dir, 0755)
if err != nil {
return false, ""
}
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
if err != nil {
Log(err)
return false, ""
}
fileInfo := info.File{Name: newFilename,
Title: file.Title,
Path: filePath,
Size: file.Size,
FromFileId: file.FileId}
id := bson.NewObjectId();
fileInfo.FileId = id
fileId = id.Hex()
Ok := this.AddImage(fileInfo, "", toUserId)
if Ok {
return Ok, id.Hex()
}
return false, ""
}
// 是否是我的文件
func (this *FileService) IsMyFile(userId, fileId string) bool {
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
}

View File

@ -0,0 +1,102 @@
package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"regexp"
// "time"
)
type NoteImageService struct {
}
// 通过id, userId得到noteIds
func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages)
if noteImages != nil && len(noteImages) > 0 {
noteIds := make([]bson.ObjectId, len(noteImages))
cnt := len(noteImages)
for i := 0; i < cnt; i++ {
noteIds[i] = noteImages[i].NoteId
}
return noteIds
}
return nil
}
// 解析内容中的图片, 建立图片与note的关系
// <img src="/file/outputImage?fileId=12323232" />
// 图片必须是我的, 不然不添加
func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
// 删除旧的
db.DeleteAll(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(noteId)})
// 添加新的
var fileId string
noteImage := info.NoteImage{NoteId: bson.ObjectIdHex(noteId)}
hasAdded := make(map[string]bool)
if find != nil && len(find) > 0 {
for _, each := range find {
if each != nil && len(each) == 2 {
fileId = each[1]
// 之前没能添加过的
if _, ok := hasAdded[fileId]; !ok {
Log(fileId)
// 判断是否是我的文件
if fileService.IsMyFile(userId, fileId) {
noteImage.ImageId = bson.ObjectIdHex(fileId)
db.Insert(db.NoteImages, noteImage)
}
hasAdded[fileId] = true
}
}
}
}
return true
}
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, &noteImages)
if len(noteImages) == 0 {
return content;
}
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
for _, noteImage := range noteImages {
imageId := noteImage.ImageId.Hex()
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
if ok {
replaceMap[imageId] = newImageId
}
}
if len(replaceMap) > 0 {
// 替换之
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
content = reg.ReplaceAllStringFunc(content, func(each string) string {
// each=outputImage?fileId=541bd2f599c37b4f3r000003
fileId := each[len(each)-24:] // 得到后24位, 也即id
if replaceFileId, ok := replaceMap[fileId]; ok {
return "outputImage?fileId=" + replaceFileId
}
return each
});
}
return content;
}

View File

@ -17,6 +17,12 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
db.GetByIdAndUserId(db.Notes, noteId, userId, &note)
return
}
// fileService调用
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
note = info.Note{}
db.Get(db.Notes, noteId, &note)
return
}
// 得到blog, blogService用
// 不要传userId, 因为是公开的
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
@ -148,6 +154,10 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
noteContent.UpdatedTime = noteContent.CreatedTime
noteContent.UpdatedUserId = noteContent.UserId
db.Insert(db.NoteContents, noteContent)
// 更新笔记图片
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
return noteContent;
}
@ -237,11 +247,23 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
Content: content,
UpdatedTime: time.Now(),
})
// 更新笔记图片
noteImageService.UpdateNoteImages(userId, noteId, content)
return true
}
return false
}
// ?????
// 这种方式太恶心, 改动很大
// 通过content修改笔记的imageIds列表
// src="http://localhost:9000/file/outputImage?fileId=541ae75499c37b6b79000005&noteId=541ae63c19807a4bb9000000"
func (this *NoteService) updateNoteImages(noteId string, content string) bool {
return true
}
// 更新tags
// [ok] [del]
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
@ -316,9 +338,12 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
}
// 复制别人的共享笔记给我
// TODO 判断是否共享了给我
// 将别人可用的图片转为我的图片, 复制图片
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
if notebookService.IsMyNotebook(notebookId, myUserId) {
Log(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId))
// 判断是否共享了给我
if notebookService.IsMyNotebook(notebookId, myUserId) &&
(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId)) {
note := this.GetNote(noteId, fromUserId)
if note.NoteId == "" {
return info.Note{}
@ -332,10 +357,18 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
note.IsTop = false
note.IsBlog = false // 别人的可能是blog
note.ImgSrc = "" // 为什么清空, 因为图片需要复制, 先清空
// content
noteContent.NoteId = note.NoteId
noteContent.UserId = note.UserId
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
noteContent.Content = noteImageService.CopyNoteImages(noteId, fromUserId, note.NoteId.Hex(), noteContent.Content, myUserId)
// 复制附件
attachService.CopyAttachs(noteId, note.NoteId.Hex(), myUserId)
// 添加之
note = this.AddNoteAndContent(note, noteContent, note.UserId);
@ -353,8 +386,10 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
// shareService call
// [ok]
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
note := &info.Note{}
db.Get(db.Notes, noteId, note)
note := info.Note{}
// db.Get(db.Notes, noteId, &note)
// LogJ(note)
db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"NotebookId"}, &note)
return note.NotebookId
}
@ -396,7 +431,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
for i, note := range notes {
noteIds[i] = note.NoteId
}
LogJ(noteIds)
noteContents := []info.NoteContent{}
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
if isBlog {
@ -419,9 +453,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
noteIds2[i] = content.NoteId
}
// Log(" content search ")
// Log(lenContent)
// 得到notes
notes2 := this.ListNotesByNoteIds(noteIds2)
@ -446,8 +477,6 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
// 总记录数
count, _ = q.Count()
Log(count)
q.Sort(sortFieldR).
Skip(skipNum).
Limit(pageSize).

View File

@ -3,7 +3,7 @@ package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
"sort"
@ -286,6 +286,28 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
return db.Insert(db.ShareNotes, shareNote), "", toUserId
}
// updatedUserId是否有查看userId noteId的权限?
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
if !db.Has(db.ShareNotes,
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
// noteId的notebookId是否被共享了?
notebookId := noteService.GetNotebookId(noteId)
if notebookId.Hex() == "" {
return false
}
// 判断notebook是否被共享
if !db.Has(db.ShareNotebooks,
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
return false
} else {
return true
}
} else {
return true
}
}
// updatedUserId是否有修改userId noteId的权限?
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
// 1. noteId是否被共享了?
@ -334,14 +356,14 @@ func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
}
// userId是否被共享了noteId
func (this *ShareService) hasSharedNote(noteId, myUserId string) bool {
func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
}
// noteId的notebook是否共享了给我
func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
note := noteService.GetNote(noteId, sharedUserId)
if note.NoteId != "" {
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": note.NotebookId,
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
notebookId := noteService.GetNotebookId(noteId)
if notebookId != "" {
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": notebookId,
"UserId": bson.ObjectIdHex(sharedUserId),
"ToUserId": bson.ObjectIdHex(myUserId),
})
@ -355,7 +377,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
noteContent = info.NoteContent{}
// 是否单独共享了该notebook
// 或者, 其notebook共享了我
if this.hasSharedNote(noteId, myUserId) || this.hasSharedNotebook(noteId, myUserId, sharedUserId) {
if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
db.Get(db.NoteContents, noteId, &noteContent)
} else {
}
@ -507,4 +529,51 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
db.DeleteAll(db.HasShareNotes, query);
return true
}
// 用户userId是否有修改noteId的权限
func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false;
}
note := noteService.GetNoteById(noteId)
LogJ(note);
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
// 是否是有权限协作的
if this.HasUpdatePerm(noteUserId, userId, noteId) {
return true
} else {
return false;
}
} else {
return true
}
} else {
return false;
}
}
// 用户userId是否有修改noteId的权限
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false;
}
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
// 是否是有权限协作的
if this.HasReadPerm(noteUserId, userId, noteId) {
return true
} else {
return false;
}
} else {
return true
}
} else {
return false;
}
}

View File

@ -53,7 +53,15 @@ func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
// 删除trash
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
return db.DeleteByIdAndUserId(db.Notes, noteId, userId)
// delete note's attachs
ok := attachService.DeleteAllAttachs(noteId, userId)
// delete note
ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
// delete content
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
return ok
}
// 列出note, 排序规则, 还有分页

View File

@ -17,6 +17,9 @@ var userService *UserService
var tagService *TagService
var blogService *BlogService
var tokenService *TokenService
var noteImageService *NoteImageService
var fileService *FileService
var attachService *AttachService
func init() {
notebookService = &NotebookService{}
@ -28,4 +31,7 @@ func init() {
tagService = &TagService{}
blogService = &BlogService{}
tokenService = &TokenService{}
fileService = &FileService{}
attachService = &AttachService{}
noteImageService = &NoteImageService{}
}

View File

@ -353,6 +353,7 @@ function log(o) {
</i>Sort <i class="fa fa-angle-down"></i>
-->
</a>
<!--
<ul class="dropdown-menu" role="menu"
aria-labelledby="dropdownMenu1"
style="right: 3px; ! important; left: -100px; min-width: 100px;">
@ -366,6 +367,7 @@ function log(o) {
<li role="presentation"><a role="menuitem" tabindex="-1"
href="#">Separated </a></li>
</ul>
-->
</div>
</div>
@ -466,6 +468,38 @@ function log(o) {
<ul class="pull-right" id="editorTool">
<li><a class="ios7-a " id="saveBtn" title="ctrl+s"
data-toggle="dropdown">{{msg . "save"}}</a></li>
<li class="dropdown" id="attachDropdown">
<a class="ios7-a dropdown-toggle" data-toggle="dropdown" id="showAttach">
<!--
<span class="fa fa-upload"></span>
-->
{{msg . "attachments"}}<span id="attachNum"></span>
</a>
<div class="dropdown-menu" id="attachMenu">
<ul id="attachList">
</ul>
<form id="uploadAttach" method="post" action="/attach/UploadAttach" enctype="multipart/form-data">
<div id="dropAttach">
<a class="btn btn-success btn-choose-file">
Choose File to Upload
</a>
<a class="btn btn-default" id="downloadAllBtn">
<i class="fa fa-download"></i>
Download All
</a>
<a class="btn btn-default" id="linkAllBtn">
<i class="fa fa-link"></i>
Link All
</a>
<input type="file" name="file" multiple/>
</div>
<div id="attachUploadMsg">
</div>
</form>
</div>
</li>
<li><a class="ios7-a " id="tipsBtn"
data-toggle="dropdown">{{msg . "editorTips"}}</a></li>
<li><a class="ios7-a " id="contentHistory"
@ -498,7 +532,7 @@ function log(o) {
</div>
</div>
<!-- leaui image -->
<!-- leaui image drop image to editor-->
<form id="upload" method="post" action="/file/uploadImageLeaui" enctype="multipart/form-data" style="margin-top: 5px;">
<div id="drop">
Drop images to here
@ -1001,7 +1035,7 @@ initSlimScroll();
<!-- context-menu -->
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
<!-- version 2.0 -->
<!-- js version 2.0 use require.js -->
<script src="/js/require.js"></script>
<script>
require.config({
@ -1009,14 +1043,18 @@ require.config({
paths: {
// 'jquery': 'js/jquery-1.9.0.min',
'leaui_image': 'tinymce/plugins/leaui_image/public/js/for_editor',
'attachment_upload': 'js/app/attachment_upload',
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload'
},
shim: {
'fileupload': {deps: ['jquery.ui.widget']}
}
});
require(['leaui_image'], function(leaui_image) {
});
require(['attachment_upload'], function(attachment_upload) {
});
</script>
</body>
</html>

View File

@ -353,6 +353,7 @@ function log(o) {
</i>Sort <i class="fa fa-angle-down"></i>
-->
</a>
<!--
<ul class="dropdown-menu" role="menu"
aria-labelledby="dropdownMenu1"
style="right: 3px; ! important; left: -100px; min-width: 100px;">
@ -366,6 +367,7 @@ function log(o) {
<li role="presentation"><a role="menuitem" tabindex="-1"
href="#">Separated </a></li>
</ul>
-->
</div>
</div>
@ -466,6 +468,38 @@ function log(o) {
<ul class="pull-right" id="editorTool">
<li><a class="ios7-a " id="saveBtn" title="ctrl+s"
data-toggle="dropdown">{{msg . "save"}}</a></li>
<li class="dropdown" id="attachDropdown">
<a class="ios7-a dropdown-toggle" data-toggle="dropdown" id="showAttach">
<!--
<span class="fa fa-upload"></span>
-->
{{msg . "attachments"}}<span id="attachNum"></span>
</a>
<div class="dropdown-menu" id="attachMenu">
<ul id="attachList">
</ul>
<form id="uploadAttach" method="post" action="/attach/UploadAttach" enctype="multipart/form-data">
<div id="dropAttach">
<a class="btn btn-success btn-choose-file">
Choose File to Upload
</a>
<a class="btn btn-default" id="downloadAllBtn">
<i class="fa fa-download"></i>
Download All
</a>
<a class="btn btn-default" id="linkAllBtn">
<i class="fa fa-link"></i>
Link All
</a>
<input type="file" name="file" multiple/>
</div>
<div id="attachUploadMsg">
</div>
</form>
</div>
</li>
<li><a class="ios7-a " id="tipsBtn"
data-toggle="dropdown">{{msg . "editorTips"}}</a></li>
<li><a class="ios7-a " id="contentHistory"
@ -498,7 +532,7 @@ function log(o) {
</div>
</div>
<!-- leaui image -->
<!-- leaui image drop image to editor-->
<form id="upload" method="post" action="/file/uploadImageLeaui" enctype="multipart/form-data" style="margin-top: 5px;">
<div id="drop">
Drop images to here
@ -982,7 +1016,7 @@ initSlimScroll();
<link href="/public/mdeditor/editor/editor.css" rel="stylesheet">
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter-min.js"></script>
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer-min.js"></script>
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor-min.js"></script>
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh-min.js"></script>
<script src="/public/mdeditor/editor/Markdown.Extra-min.js"></script>
<script src="/public/mdeditor/editor/underscore-min.js"></script>
@ -1001,7 +1035,7 @@ initSlimScroll();
<!-- context-menu -->
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
<!-- version 2.0 -->
<!-- js version 2.0 use require.js -->
<script src="/js/require.js"></script>
<script>
require.config({
@ -1009,14 +1043,18 @@ require.config({
paths: {
// 'jquery': 'js/jquery-1.9.0.min',
'leaui_image': 'tinymce/plugins/leaui_image/public/js/for_editor',
'attachment_upload': 'js/app/attachment_upload',
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload'
},
shim: {
'fileupload': {deps: ['jquery.ui.widget']}
}
});
require(['leaui_image'], function(leaui_image) {
});
require(['attachment_upload'], function(attachment_upload) {
});
</script>
</body>
</html>

View File

@ -132,5 +132,8 @@ discussion=Discussion
download=Download
howToInstallLeanote=How to install leanote
#
attachments = Attachments
# error
notFound=This page cann't found.

View File

@ -136,6 +136,9 @@ discussion=社区讨论
download=下载
howToInstallLeanote=leanote安装步骤
#
attachments = 附件
# 必须要加这个, 奇怪
[CN]

View File

@ -38,6 +38,13 @@
/*"HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue", Helvetica, "Microsoft Yahei", Verdana, Simsun, "Segoe UI", "Segoe UI Web Regular", "Segoe UI Symbol", "BBAlpha Sans", "S60 Sans", Arial, sans-serif;*/
.btn {
border-radius: 2px;
}
.alert {
margin-bottom: 10px;
}
#logo {
font-family: "leanoteregular";
font-size: 36px;
@ -319,4 +326,98 @@
}
.ztree {
padding: 0px;
}
}
// leaui image drop drag
#upload {
position: absolute;
z-index: 0;
bottom: 0;
right: 0;
left: 0px;
padding: 0;
background-color: #fff;
text-align: center;
display: none;
}
#upload #drop {
width: 100%;
height: 100%;
padding-top: 100px;
}
#drop.in {
border: 1px solid #000000;
}
#drop.hover {
border: 2px solid #000000;
}
#uploadMsg {
position: absolute;
top: 3px;
right: 3px;
bottom: 10px;
overflow: scroll;
list-style: none;
}
// upload attach
#uploadAttach {
position: relative;
margin-top: 5px;
}
#dropAttach {
text-align: center;
input {
display: none;
}
}
#dropAttach.in {
border: 1px solid #000000;
}
#dropAttach.hover {
border: 2px solid #000000;
}
#attachUploadMsg{
list-style-type: none;
margin: 0;
padding: 0;
max-height: 240px;
overflow: scroll;
z-index: 3;
.alert {
margin: 0;
padding: 0 3px;
margin-top: 10px;
}
}
#attachMenu {
width: 450px;
padding: 10px 5px;
}
#attachList {
margin: 0;
padding: 0;
max-height: 450px;
overflow-y: scroll;
li {
display: block;
margin: 0;
padding: 0 3px;
border-radius: 3px;
border-bottom: 1px dashed #eee;
height: 45px;
line-height: 45px;
div {
float: left;
}
.attach-title {
width: 300px;
white-space: nowrap;text-overflow:ellipsis; overflow:hidden;
}
.attach-process {
float: right;
}
}
}

View File

@ -31,6 +31,12 @@
font-style: normal;
}
/*"HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue", Helvetica, "Microsoft Yahei", Verdana, Simsun, "Segoe UI", "Segoe UI Web Regular", "Segoe UI Symbol", "BBAlpha Sans", "S60 Sans", Arial, sans-serif;*/
.btn {
border-radius: 2px;
}
.alert {
margin-bottom: 10px;
}
#logo {
font-family: "leanoteregular";
font-size: 36px;
@ -285,6 +291,96 @@
.ztree {
padding: 0px;
}
#upload {
position: absolute;
z-index: 0;
bottom: 0;
right: 0;
left: 0px;
padding: 0;
background-color: #fff;
text-align: center;
display: none;
}
#upload #drop {
width: 100%;
height: 100%;
padding-top: 100px;
}
#drop.in {
border: 1px solid #000000;
}
#drop.hover {
border: 2px solid #000000;
}
#uploadMsg {
position: absolute;
top: 3px;
right: 3px;
bottom: 10px;
overflow: scroll;
list-style: none;
}
#uploadAttach {
position: relative;
margin-top: 5px;
}
#dropAttach {
text-align: center;
}
#dropAttach input {
display: none;
}
#dropAttach.in {
border: 1px solid #000000;
}
#dropAttach.hover {
border: 2px solid #000000;
}
#attachUploadMsg {
list-style-type: none;
margin: 0;
padding: 0;
max-height: 240px;
overflow: scroll;
z-index: 3;
}
#attachUploadMsg .alert {
margin: 0;
padding: 0 3px;
margin-top: 10px;
}
#attachMenu {
width: 450px;
padding: 10px 5px;
}
#attachList {
margin: 0;
padding: 0;
max-height: 450px;
overflow-y: scroll;
}
#attachList li {
display: block;
margin: 0;
padding: 0 3px;
border-radius: 3px;
border-bottom: 1px dashed #eee;
height: 45px;
line-height: 45px;
}
#attachList li div {
float: left;
}
#attachList li .attach-title {
width: 300px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
#attachList li .attach-process {
float: right;
}
::selection {
background: #000000;
color: #ffffff;
@ -1265,12 +1361,6 @@ background-position:-1px -670px
.tab-pane {
padding: 5px 0 0 0;
}
.alert {
margin-bottom: 10px;
}
.btn {
border-radius: 0 !important;
}
#notebookNavForNewNote li,
#notebookNavForNewSharedNote > li {
padding-left: 0;
@ -1313,36 +1403,6 @@ background-position:-1px -670px
#toggleEditorMode {
margin: 0 10px !important;
}
#upload {
position: absolute;
z-index: 0;
bottom: 0;
right: 0;
left: 0px;
padding: 0;
background-color: #fff;
text-align: center;
display: none;
}
#upload #drop {
width: 100%;
height: 100%;
padding-top: 100px;
}
#drop.in {
border: 1px solid #000000;
}
#drop.hover {
border: 2px solid #000000;
}
#uploadMsg {
position: absolute;
top: 3px;
right: 3px;
bottom: 10px;
overflow: scroll;
list-style: none;
}
#searchNotebookForList {
color: #ccc;
border: 1px solid rgba(255, 255, 255, 0.1);

View File

@ -1075,13 +1075,6 @@ background-position:-1px -670px
.tab-pane {
padding: 5px 0 0 0;
}
.alert {
margin-bottom: 10px;
}
.btn {
border-radius: 0 !important;
}
.mce-container-body iframe {
//overflow-x: hidden; // firefox 不能要
@ -1137,38 +1130,6 @@ background-position:-1px -670px
margin: 0 10px !important;
}
// leaui image drop drag
#upload {
position: absolute;
z-index: 0;
bottom: 0;
right: 0;
left: 0px;
padding: 0;
background-color: #fff;
text-align: center;
display: none;
}
#upload #drop {
width: 100%;
height: 100%;
padding-top: 100px;
}
#drop.in {
border: 1px solid #000000;
}
#drop.hover {
border: 2px solid #000000;
}
#uploadMsg {
position: absolute;
top: 3px;
right: 3px;
bottom: 10px;
overflow: scroll;
list-style: none;
}
//----------------------
#searchNotebookForList {
color: #ccc;

File diff suppressed because one or more lines are too long

View File

@ -1024,13 +1024,7 @@ background-position:-1px -670px
.tab-pane {
padding: 5px 0 0 0;
}
.alert {
margin-bottom: 10px;
}
.btn {
border-radius: 0 !important;
}
.mce-container-body iframe {
//overflow-x: hidden;
@ -1087,37 +1081,6 @@ background-position:-1px -670px
}
// leaui image drop drag
#upload {
position: absolute;
z-index: 0;
bottom: 0;
right: 0;
left: 0px;
padding: 0;
background-color: #fff;
text-align: center;
display: none;
}
#upload #drop {
width: 100%;
height: 100%;
padding-top: 100px;
}
#drop.in {
border: 1px solid #000000;
}
#drop.hover {
border: 2px solid #000000;
}
#uploadMsg {
position: absolute;
top: 3px;
right: 3px;
bottom: 10px;
overflow: scroll;
list-style: none;
}
#notebookList {
border-top: 1px dashed #eee;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,134 @@
// upload attachment
// 依赖note
var urlPrefix = window.location.protocol + "//" + window.location.host;
define('attachment_upload', ['jquery.ui.widget', 'fileupload'], function(){
// var editor = tinymce.activeEditor;
// var dom = editor.dom;
var initUploader = function() {
var $msg = $('#attachUploadMsg');
$('#dropAttach .btn-choose-file').click(function() {
// trigger to show file select
$(this).parent().find('input').click();
});
// Initialize the jQuery File Upload plugin
$('#uploadAttach').fileupload({
dataType: 'json',
maxFileSize: 210000,
// 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 = $('<div class="alert alert-info"><img class="loader" src="/tinymce/plugins/leaui_image/public/images/ajax-loader.gif"> <a class="close" data-dismiss="alert">×</a></div>');
// Append the file name and file size
tpl.append(data.files[0].name + ' <small>[<i>' + formatFileSize(data.files[0].size) + '</i>]</small>');
// Add the HTML to the UL element
tpl.appendTo($msg);
data.context = $msg;
// Automatically upload the file once it is added to the queue
var jqXHR;
setTimeout(function() {
jqXHR = data.submit();
}, 0);
},
done: function(e, data) {
if (data.result.Ok == true) {
data.context.remove();
Attach.addAttach(data.result.Item);
} else {
var re = data.result;
data.context.empty();
var tpl = $('<div class="alert alert-danger"><a class="close" data-dismiss="alert">×</a></div>');
tpl.append('<b>Error:</b> ' + data.files[0].name + ' <small>[<i>' + formatFileSize(data.files[0].size) + '</i>]</small> ' + 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.empty();
var tpl = $('<div class="alert alert-danger"><a class="close" data-dismiss="alert">×</a></div>');
tpl.append('<b>Error:</b> ' + data.files[0].name + ' <small>[<i>' + formatFileSize(data.files[0].size) + '</i>]</small> ' + data.errorThrown);
data.context.html(tpl);
setTimeout((function(tpl) {
return function() {
tpl.remove();
}
})(tpl), 3000);
$("#uploadAttachMsg").scrollTop(1000);
}
});
// Prevent the default action when a file is dropped on the window
$(document).on('drop dragover', function(e) {
e.preventDefault();
});
// 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';
}
// drag css
$(document).bind('dragover', function (e) {
var dropZone = $('#dropAttach'),
timeout = window.dropZoneTimeout;
if (!timeout) {
dropZone.addClass('in');
showUpload();
} else {
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.dropZoneTimeout = setTimeout(function () {
window.dropZoneTimeout = null;
dropZone.removeClass('in hover');
hideUpload();
}, 100);
});
}
initUploader();
});

File diff suppressed because one or more lines are too long

View File

@ -71,6 +71,19 @@ Note.setNoteCache = function(content, clear) {
}
}
// 得到当前的笔记
Note.getCurNote = function() {
var self = this;
if(self.curNoteId == "") {
return null;
}
return self.cache[self.curNoteId];
}
Note.getNote = function(noteId) {
var self = this;
return self.cache[noteId];
}
// 每当有notebookId相应的note改变时都要重新清空之
// 并设置该notebookId有值
Note.clearCacheByNotebookId = function(notebookId) {
@ -432,6 +445,8 @@ Note.changeNote = function(selectNoteId, isShare, needSaveChanged) {
Note.renderNoteReadOnly(cacheNote);
}
Attach.renderNoteAttachNum(selectNoteId, true);
function setContent(ret) {
Note.setNoteCache(ret, false);
// 把其它信息也带上
@ -695,6 +710,9 @@ Note.newNote = function(notebookId, isShare, fromUserId, isMarkdown) {
// 添加到缓存中
Note.addNoteCache(note);
// 清空附件数
Attach.clearNoteAttachNum();
// 是否是为共享的notebook添加笔记, 如果是, 则还要记录fromUserId
var newItem = "";
@ -1278,8 +1296,209 @@ Note.initContextmenu = function() {
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("/attach/download?attachId=" + attachId);
// location.href = "/attach/download?attachId=" + attachId;
});
// 下载全部
self.downloadAllBtnO.click(function() {
window.open("/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 = "/attach/download?attachId=" + attachId;
if(LEA.isMarkdownEditor() && MarkdownEditor) {
MarkdownEditor.insertLink(src, attach.Title);
} else {
tinymce.activeEditor.insertContent('<a target="_blank" href="' + src + '">' + attach.Title + '</a>');
}
});
// make all link
self.linkAllBtnO.on("click",function(e) {
e.stopPropagation();
var note = Note.getCurNote();
if(!note) {
return;
}
var src = "/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('<a target="_blank" href="' + src + '">' + title + '</a>');
}
});
},
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 循环之
/*
<li class="clearfix">
<div class="attach-title">leanote官abcefedafadfadfadfadfad方文档.doc</div>
<div class="attach-process">
<button class="btn btn-sm btn-warning">Delete</button>
<button class="btn btn-sm btn-deafult">Download</button>
</div>
</li>
*/
var html = "";
var attachNum = attachs.length;
for(var i = 0; i < attachNum; ++i) {
var each = attachs[i];
html += '<li class="clearfix" data-id="' + each.AttachId + '">' +
'<div class="attach-title">' + each.Title + '</div>' +
'<div class="attach-process"> ' +
' <button class="btn btn-sm btn-warning delete-attach"><i class="fa fa-trash-o"></i></button> ' +
' <button type="button" class="btn btn-sm btn-primary download-attach"><i class="fa fa-download"></i></button> ' +
' <button type="button" class="btn btn-sm btn-default link-attach" title="Insert link into content"><i class="fa fa-link"></i></button> ' +
'</div>' +
'</li>';
self.attachsMap[each.AttachId] = each;
}
self.attachListO.html(html);
// 设置数量
var note = Note.getCurNote();
if(note) {
note.AttachNum = attachNum;
self.renderNoteAttachNum(note.NoteId, false);
}
},
// 渲染noteId的附件
// 当点击"附件"时加载,
// TODO 判断是否已loaded
renderAttachs: function(noteId) {
var self = this;
if(self.loadedNoteAttachs[noteId]) {
self._renderAttachs(self.loadedNoteAttachs[noteId]);
return;
}
// ajax获取noteAttachs
ajaxGet("/attach/getAttachs", {noteId: noteId}, function(ret) {
var list = [];
if(ret.Ok) {
list = ret.List;
if(!list) {
list = [];
}
}
// 添加到缓存中
self.loadedNoteAttachs[noteId] = list;
self._renderAttachs(list);
});
},
// 添加附件, attachment_upload上传调用
addAttach: function(attachInfo) {
var self = this;
if(!self.loadedNoteAttachs[attachInfo.NoteId]) {
self.loadedNoteAttachs[attachInfo.NoteId] = [];
}
self.loadedNoteAttachs[attachInfo.NoteId].push(attachInfo);
self.renderAttachs(attachInfo.NoteId);
},
// 删除
deleteAttach: function(attachId) {
var self = this;
var noteId = Note.curNoteId;
var attachs = self.loadedNoteAttachs[noteId];
for(var i = 0; i < attachs.length; ++i) {
if(attachs[i].AttachId == attachId) {
// 删除之, 并render之
attachs.splice(i, 1);
break;
}
}
// self.loadedNoteAttachs[noteId] = attachs;
self.renderAttachs(noteId);
},
// 下载
downloadAttach: function(fileId) {
var self = this;
},
downloadAll: function() {
}
}
//------------------- 事件
$(function() {
// 附件初始化
Attach.init();
//-----------------
// for list nav
$("#noteItemList").on("click", ".item", function(event) {

File diff suppressed because one or more lines are too long

View File

@ -93,8 +93,8 @@ Share.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) {
return;
}
if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) {
return;
if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) {
shareNotebooks = {};
}
var $shareNotebooks = $("#shareNotebooks");

File diff suppressed because one or more lines are too long

View File

@ -288,7 +288,12 @@ function editorIframeTabindex(index) {
}
}
//切换编辑器
LEA.isM = false;
LEA.isMarkdownEditor = function() {
return LEA.isM;
}
function switchEditor(isMarkdown) {
LEA.isM = isMarkdown;
// 富文本永远是2
if(!isMarkdown) {
$("#editor").show();

File diff suppressed because one or more lines are too long

View File

@ -1317,7 +1317,37 @@
}
});
}
// life 新添加函数
// life
function insertLinkLife(link, text) {
inputBox.focus();
if (undoManager) {
undoManager.setCommandMode();
}
var state = new TextareaState(panels);
if (!state) {
return;
}
var chunks = state.getChunks(); // 得到chunk
var fixupInputArea = function () {
inputBox.focus();
if (chunks) {
state.setChunks(chunks);
}
state.restore();
previewManager.refresh();
};
var a = commandProto.insertLink(chunks, fixupInputArea, link, text);
if(!a) fixupInputArea();
}
MarkdownEditor.insertLink = insertLinkLife;
// Perform the button's action.
function doClick(button) {
@ -1369,6 +1399,7 @@
var noCleanup = button.textOp(chunks, fixupInputArea);
// 这里生成
if (!noCleanup) {
fixupInputArea();
}
@ -1378,6 +1409,7 @@
if (button.execute) {
button.execute(undoManager);
}
};
function setupButton(button, isEnabled) {
@ -1707,6 +1739,68 @@
return title ? link + ' "' + title + '"' : link;
});
}
// life 添加
commandProto.insertLink = function (chunk, postProcessing, link, text) {
isImage = false;
chunk.trimWhitespace();
chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/);
var background;
if (chunk.endTag.length > 1 && chunk.startTag.length > 0) {
chunk.startTag = chunk.startTag.replace(/!?\[/, "");
chunk.endTag = "";
this.addLinkDef(chunk, null);
}
else {
// We're moving start and end tag back into the selection, since (as we're in the else block) we're not
// *removing* a link, but *adding* one, so whatever findTags() found is now back to being part of the
// link text. linkEnteredCallback takes care of escaping any brackets.
chunk.selection = chunk.startTag + chunk.selection + chunk.endTag;
chunk.startTag = chunk.endTag = "";
if (/\n\n/.test(chunk.selection)) {
this.addLinkDef(chunk, null);
return;
}
var that = this;
// The function to be executed when you enter a link and press OK or Cancel.
// Marks up the link and adds the ref.
var linkEnteredCallback = function (link) {
background.parentNode.removeChild(background);
if (link !== null) {
chunk.selection = (" " + chunk.selection).replace(/([^\\](?:\\\\)*)(?=[[\]])/g, "$1\\").substr(1);
var linkDef = " [999]: " + properlyEncoded(link);
var num = that.addLinkDef(chunk, linkDef);
chunk.startTag = isImage ? "![" : "[";
chunk.endTag = "][" + num + "]";
chunk.selection = text;
}
postProcessing();
};
background = ui.createBackground();
linkEnteredCallback(link);
/*
if (isImage) {
if (!this.hooks.insertImageDialog(linkEnteredCallback))
ui.prompt(this.getString("imagedialog"), imageDefaultText, linkEnteredCallback);
}
else {
if (!this.hooks.insertLinkDialog(linkEnteredCallback)) // jiawzhang
ui.prompt(this.getString("linkdialog"), linkDefaultText, linkEnteredCallback);
}
*/
return true;
}
};
commandProto.doLinkOrImage = function (chunk, postProcessing, isImage) {

View File

@ -88,7 +88,7 @@ tinymce.PluginManager.add('leaui_image', function(editor, url) {
d.height = img.getAttribute("data-height");
d.title = img.getAttribute("data-title");
datas.push(d);
datas.push(d);
}
};
@ -104,49 +104,63 @@ tinymce.PluginManager.add('leaui_image', function(editor, url) {
}
data.src = trueSrc;
/*
var width = "", height="", title="";
if(data.width) {
width = 'width="' + data.width +'" ';
}
if(data.height) {
height = 'height="' + data.height +'" ';
}
if(data.title) {
title = 'title="' + data.title +'" ';
}
var attrs = width + height + title;
editor.insertContent('<img ' + attrs + ' data-src="' + src + '" src="' + trueSrc + '" />');
*/
// 这里, 如果图片宽度过大, 这里设置成500px
var back = (function(data2, i) {
var d = {};
var imgElm;
// 先显示loading...
d.id = '__mcenew' + i;
d.src = "http://leanote.com/images/loading-24.gif";
imgElm = dom.createHTML('img', d);
editor.insertContent(imgElm);
imgElm = dom.get(d.id);
log(imgElm)
return function(wh) {
if(wh && wh.width) {
if(wh.width > 600) {
wh.width = 600;
}
data2.width = wh.width;
}
dom.setAttrib(imgElm, 'src', data2.src);
dom.setAttrib(imgElm, 'width', data2.width);
dom.setAttrib(imgElm, 'title', data2.title);
var renderImage = function(data) {
// 这里, 如果图片宽度过大, 这里设置成500px
var back = (function(data2, i) {
var d = {};
var imgElm;
// 先显示loading...
d.id = '__mcenew' + i;
d.src = "http://leanote.com/images/loading-24.gif";
imgElm = dom.createHTML('img', d);
editor.insertContent(imgElm);
imgElm = dom.get(d.id);
dom.setAttrib(imgElm, 'id', null);
return function(wh) {
if(wh && wh.width) {
if(wh.width > 600) {
wh.width = 600;
}
data2.width = wh.width;
}
dom.setAttrib(imgElm, 'src', data2.src);
dom.setAttrib(imgElm, 'width', data2.width);
dom.setAttrib(imgElm, 'title', data2.title);
dom.setAttrib(imgElm, 'id', null);
}
})(data, i);
getImageSize(data.src, back);
}
// outputImage?fileId=123232323
var fileId = "";
fileIds = trueSrc.split("fileId=")
if(fileIds.length == 2 && fileIds[1].length == "53aecf8a8a039a43c8036282".length) {
fileId = fileIds[1];
}
if(fileId) {
// 得到fileId, 如果这个笔记不是我的, 那么肯定是协作的笔记, 那么需要将图片copy给原note owner
var curNote = Note.getCurNote();
if(curNote && curNote.UserId != UserInfo.UserId) {
(function(data) {
ajaxPost("/file/copyImage", {userId: UserInfo.UserId, fileId: fileId, toUserId: curNote.UserId}, function(re) {
if(reIsOk(re) && re.Id) {
var urlPrefix = window.location.protocol + "//" + window.location.host;
data.src = urlPrefix + "/file/outputImage?fileId=" + re.Id;
}
renderImage(data);
});
})(data);
} else {
renderImage(data);
}
})(data, i);
getImageSize(data.src, back);
}
} else {
renderImage(data);
}
} // end for
this.parent().parent().close();
}
},

View File

@ -1 +1 @@
var LEAUI_DATAS=[];tinymce.PluginManager.add("leaui_image",function(t,e){function i(t,e){function i(t,i){n.parentNode.removeChild(n),e({width:t,height:i})}var n=document.createElement("img");n.onload=function(){i(n.clientWidth,n.clientHeight)},n.onerror=function(){i()},n.src=t;var r=n.style;r.visibility="hidden",r.position="fixed",r.bottom=r.left=0,r.width=r.height="auto",document.body.appendChild(n)}function n(){function n(){var t='<iframe id="leauiIfr" src="'+e+"/index.html?"+(new Date).getTime()+'" frameborder="0"></iframe>';return t}var r=t.dom,a=t.selection.getContent(),o=/<img.*?\/>/g,d=a.match(o),c=document.createElement("p"),g=[];for(var h in d){c.innerHTML=d[h];var l=c.firstChild;if(l&&"IMG"==l.nodeName){var s={};s.src=r.getAttrib(l,"data-src")||r.getAttrib(l,"src"),s.width=r.getAttrib(l,"width"),s.height=r.getAttrib(l,"height"),s.title=r.getAttrib(l,"title"),g.push(s)}}LEAUI_DATAS=g,win=t.windowManager.open({title:"Manage Image",width:885,height:475,html:n(),buttons:[{text:"Insert Image",subtype:"primary",onclick:function(n){for(var a=document.getElementById("leauiIfr").contentWindow,o=a.document.getElementById("preview"),d=o.childNodes,c=[],g=0;g<d.length;++g){var n=d[g];if(n.firstChild&&"IMG"==n.firstChild.nodeName){var h=n.firstChild,l={};l.src=h.getAttribute("src"),l.width=h.getAttribute("data-width"),l.height=h.getAttribute("data-height"),l.title=h.getAttribute("data-title"),c.push(l)}}for(var g in c){var s,m=c[g],u=m.src;s=-1!=u.indexOf("http://")||-1!=u.indexOf("https://")?u:e+"/"+u,m.src=s;var f=function(e,i){var n,a={};return a.id="__mcenew"+i,a.src="http://leanote.com/images/loading-24.gif",n=r.createHTML("img",a),t.insertContent(n),n=r.get(a.id),log(n),function(t){t&&t.width&&(t.width>600&&(t.width=600),e.width=t.width),r.setAttrib(n,"src",e.src),r.setAttrib(n,"width",e.width),r.setAttrib(n,"title",e.title),r.setAttrib(n,"id",null)}}(m,g);i(m.src,f)}this.parent().parent().close()}},{text:"Cancel",onclick:function(){this.parent().parent().close()}}]})}t.addButton("leaui_image",{icon:"image",tooltip:"Insert/edit image",onclick:n,stateSelector:"img:not([data-mce-object])"}),t.addMenuItem("leaui_image",{icon:"image",text:"Insert image",onclick:n,context:"insert",prependToContext:!0});var r=!1;t.on("dragstart",function(){r=!0}),t.on("dragend",function(){r=!1}),t.on("dragover",function(){r||$("body").trigger("dragover")})});
var LEAUI_DATAS=[];tinymce.PluginManager.add("leaui_image",function(t,e){function i(t,e){function i(t,i){n.parentNode.removeChild(n),e({width:t,height:i})}var n=document.createElement("img");n.onload=function(){i(n.clientWidth,n.clientHeight)},n.onerror=function(){i()},n.src=t;var r=n.style;r.visibility="hidden",r.position="fixed",r.bottom=r.left=0,r.width=r.height="auto",document.body.appendChild(n)}function n(){function n(){var t='<iframe id="leauiIfr" src="'+e+"/index.html?"+(new Date).getTime()+'" frameborder="0"></iframe>';return t}var r=t.dom,o=t.selection.getContent(),a=/<img.*?\/>/g,d=o.match(a),c=document.createElement("p"),l=[];for(var s in d){c.innerHTML=d[s];var g=c.firstChild;if(g&&"IMG"==g.nodeName){var h={};h.src=r.getAttrib(g,"data-src")||r.getAttrib(g,"src"),h.width=r.getAttrib(g,"width"),h.height=r.getAttrib(g,"height"),h.title=r.getAttrib(g,"title"),l.push(h)}}LEAUI_DATAS=l,win=t.windowManager.open({title:"Manage Image",width:885,height:475,html:n(),buttons:[{text:"Insert Image",subtype:"primary",onclick:function(n){for(var o=document.getElementById("leauiIfr").contentWindow,a=o.document.getElementById("preview"),d=a.childNodes,c=[],l=0;l<d.length;++l){var n=d[l];if(n.firstChild&&"IMG"==n.firstChild.nodeName){var s=n.firstChild,g={};g.src=s.getAttribute("src"),g.width=s.getAttribute("data-width"),g.height=s.getAttribute("data-height"),g.title=s.getAttribute("data-title"),c.push(g)}}for(var l in c){var h,f=c[l],u=f.src;h=-1!=u.indexOf("http://")||-1!=u.indexOf("https://")?u:e+"/"+u,f.src=h;var m=function(e){var n=function(e,i){var n,o={};return o.id="__mcenew"+i,o.src="http://leanote.com/images/loading-24.gif",n=r.createHTML("img",o),t.insertContent(n),n=r.get(o.id),function(t){t&&t.width&&(t.width>600&&(t.width=600),e.width=t.width),r.setAttrib(n,"src",e.src),r.setAttrib(n,"width",e.width),r.setAttrib(n,"title",e.title),r.setAttrib(n,"id",null)}}(e,l);i(e.src,n)},I="";if(fileIds=h.split("fileId="),2==fileIds.length&&fileIds[1].length=="53aecf8a8a039a43c8036282".length&&(I=fileIds[1]),I){var p=Note.getCurNote();p&&p.UserId!=UserInfo.UserId?!function(t){ajaxPost("/file/copyImage",{userId:UserInfo.UserId,fileId:I,toUserId:p.UserId},function(e){if(reIsOk(e)&&e.Id){var i=window.location.protocol+"//"+window.location.host;t.src=i+"/file/outputImage?fileId="+e.Id}m(t)})}(f):m(f)}else m(f)}this.parent().parent().close()}},{text:"Cancel",onclick:function(){this.parent().parent().close()}}]})}t.addButton("leaui_image",{icon:"image",tooltip:"Insert/edit image",onclick:n,stateSelector:"img:not([data-mce-object])"}),t.addMenuItem("leaui_image",{icon:"image",text:"Insert image",onclick:n,context:"insert",prependToContext:!0});var r=!1;t.on("dragstart",function(){r=!0}),t.on("dragend",function(){r=!1}),t.on("dragover",function(){r||$("body").trigger("dragover")})});

View File

@ -1,7 +1,7 @@
// for editor.
// drag image to editor
// Copyright leaui
var urlPrefix = window.location.protocol + "//" + window.location.host;
define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
var editor = tinymce.activeEditor;
var dom = editor.dom;
@ -35,33 +35,62 @@ define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
}
var i = 1;
function insertImage(data2) {
// 这里, 如果图片宽度过大, 这里设置成500px
var d = {};
var imgElm;
// 先显示loading...
d.id = '__mcenew' + (i++);
d.src = "http://leanote.com/images/loading-24.gif";
imgElm = dom.createHTML('img', d);
editor.insertContent(imgElm);
imgElm = dom.get(d.id);
function callback (wh) {
if(wh && wh.width) {
if(wh.width > 600) {
wh.width = 600;
}
data2.width = wh.width;
}
dom.setAttrib(imgElm, 'src', data2.src);
dom.setAttrib(imgElm, 'width', data2.width);
if(data2.title) {
dom.setAttrib(imgElm, 'title', data2.title);
}
function insertImage(data) {
var renderImage = function(data2) {
// 这里, 如果图片宽度过大, 这里设置成500px
var d = {};
var imgElm;
// 先显示loading...
d.id = '__mcenew' + (i++);
d.src = "http://leanote.com/images/loading-24.gif";
imgElm = dom.createHTML('img', d);
editor.insertContent(imgElm);
imgElm = dom.get(d.id);
dom.setAttrib(imgElm, 'id', null);
};
getImageSize(data2.src, callback);
function callback (wh) {
if(wh && wh.width) {
if(wh.width > 600) {
wh.width = 600;
}
data2.width = wh.width;
}
dom.setAttrib(imgElm, 'src', data2.src);
dom.setAttrib(imgElm, 'width', data2.width);
if(data2.title) {
dom.setAttrib(imgElm, 'title', data2.title);
}
dom.setAttrib(imgElm, 'id', null);
};
getImageSize(data.src, callback);
}
//-------------
// outputImage?fileId=123232323
var fileId = "";
fileIds = data.src.split("fileId=")
if(fileIds.length == 2 && fileIds[1].length == "53aecf8a8a039a43c8036282".length) {
fileId = fileIds[1];
}
if(fileId) {
// 得到fileId, 如果这个笔记不是我的, 那么肯定是协作的笔记, 那么需要将图片copy给原note owner
var curNote = Note.getCurNote();
if(curNote && curNote.UserId != UserInfo.UserId) {
(function(data) {
ajaxPost("/file/copyImage", {userId: UserInfo.UserId, fileId: fileId, toUserId: curNote.UserId}, function(re) {
if(reIsOk(re) && re.Id) {
var urlPrefix = window.location.protocol + "//" + window.location.host;
data.src = urlPrefix + "/file/outputImage?fileId=" + re.Id;
}
renderImage(data);
});
})(data);
} else {
renderImage(data);
}
} else {
renderImage(data);
}
}
var initUploader = function() {
@ -103,7 +132,8 @@ define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
done: function(e, data) {
if (data.result.Ok == true) {
data.context.remove();
var data2 = {src: data.result.Id}
// life
var data2 = {src: urlPrefix + "/file/outputImage?fileId=" + data.result.Id}
insertImage(data2);
} else {
data.context.empty();

View File

@ -260,13 +260,19 @@ var o = {
for(var i in datas){
var each = datas[i];
var classes = "";
var src = urlPrefix + each.Path;
// life edit
// 之前的
if(each.Path != "" && each.Path.substr(0, 7) == "/upload") {
var src = urlPrefix + each.Path;
} else {
var src = urlPrefix + "/file/outputImage?fileId=" + each.FileId;
}
// log(src);
if(selectedMap[src]) {
classes = 'class="selected"';
}
html += '<li ' + classes + '>';
html += '<a title="" href="javascript:;" class="a-img"><img alt="" data-original="' + src + '" ></a>';
html += '<a title="" href="javascript:;" class="a-img"><img alt="" data-original="' + src + '" ></a>';
// html += '<div class="tools"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div>';
html += '<div class="tools clearfix" data-id="' + each.FileId + '"><div class="file-title pull-left">' + each.Title + '</div><div class="pull-right"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div></div>';
html += "</li>";
@ -348,10 +354,11 @@ var o = {
return false;
}
// life 为了图片安全
if(typeof $li == "object") {
var src = $li.find("img").attr('src');
} else {
src = $li;
src = urlPrefix + "/file/outputImage?fileId=" + $li;
}
this.selectedImages.push(src);
this.reRenderSelectedImages(false, src);

File diff suppressed because one or more lines are too long

View File

@ -287,6 +287,7 @@ define("tinymce/pasteplugin/Clipboard", [
var c = new FormData;
c.append("from", "pasteImage");
c.append("file", blob);
c.append("noteId", Note.curNoteId); // life
// var d;
// d = $.ajaxSettings.xhr();
// d.withCredentials = i;var d = {};
@ -296,10 +297,10 @@ define("tinymce/pasteplugin/Clipboard", [
var dom = editor.dom;
var d = {};
d.id = '__mcenew';
d.src = "http://leanote.com/images/loading-24.gif";
d.src = "http://leanote.com/images/loading-24.gif"; // 写死了
editor.insertContent(dom.createHTML('img', d));
var imgElm = dom.get('__mcenew');
$.ajax({url: "/file/uploadImageJson", contentType:false, processData:false , data: c, type: "POST"}
$.ajax({url: "/file/pasteImage", contentType:false, processData:false , data: c, type: "POST"}
).done(function(re) {
if(!re || typeof re != "object" || !re.Ok) {
// 删除
@ -307,7 +308,9 @@ define("tinymce/pasteplugin/Clipboard", [
return;
}
// 这里, 如果图片宽度过大, 这里设置成500px
getImageSize(re.Id, function(wh) {
var urlPrefix = window.location.protocol + "//" + window.location.host;
var src = urlPrefix + "/file/outputImage?fileId=" + re.Id;
getImageSize(src, function(wh) {
// life 4/25
if(wh && wh.width) {
if(wh.width > 600) {
@ -316,7 +319,7 @@ define("tinymce/pasteplugin/Clipboard", [
d.width = wh.width;
dom.setAttrib(imgElm, 'width', d.width);
}
dom.setAttrib(imgElm, 'src', re.Id);
dom.setAttrib(imgElm, 'src', src);
});
dom.setAttrib(imgElm, 'id', null);
});

View File

@ -117,4 +117,4 @@
writeScripts();
})(this);
// $hash: cbcf61872b3ecc41bd22dcf691e2e4dd
// $hash: 3d47d6168ca064ff0c3f626e575ff2e8

View File

@ -472,6 +472,7 @@ define("tinymce/pasteplugin/Clipboard", [
var c = new FormData;
c.append("from", "pasteImage");
c.append("file", blob);
c.append("noteId", Note.curNoteId); // life
// var d;
// d = $.ajaxSettings.xhr();
// d.withCredentials = i;var d = {};
@ -481,10 +482,10 @@ define("tinymce/pasteplugin/Clipboard", [
var dom = editor.dom;
var d = {};
d.id = '__mcenew';
d.src = "http://leanote.com/images/loading-24.gif";
d.src = "http://leanote.com/images/loading-24.gif"; // 写死了
editor.insertContent(dom.createHTML('img', d));
var imgElm = dom.get('__mcenew');
$.ajax({url: "/file/uploadImageJson", contentType:false, processData:false , data: c, type: "POST"}
$.ajax({url: "/file/pasteImage", contentType:false, processData:false , data: c, type: "POST"}
).done(function(re) {
if(!re || typeof re != "object" || !re.Ok) {
// 删除
@ -492,7 +493,9 @@ define("tinymce/pasteplugin/Clipboard", [
return;
}
// 这里, 如果图片宽度过大, 这里设置成500px
getImageSize(re.Id, function(wh) {
var urlPrefix = window.location.protocol + "//" + window.location.host;
var src = urlPrefix + "/file/outputImage?fileId=" + re.Id;
getImageSize(src, function(wh) {
// life 4/25
if(wh && wh.width) {
if(wh.width > 600) {
@ -501,7 +504,7 @@ define("tinymce/pasteplugin/Clipboard", [
d.width = wh.width;
dom.setAttrib(imgElm, 'width', d.width);
}
dom.setAttrib(imgElm, 'src', re.Id);
dom.setAttrib(imgElm, 'src', src);
});
dom.setAttrib(imgElm, 'id', null);
});

File diff suppressed because one or more lines are too long