From 47687cc5b191201ad64fc944e0eca84f036d90bf Mon Sep 17 00:00:00 2001 From: Minho Date: Fri, 7 Jul 2017 16:20:55 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=AE=9E=E7=8E=B0=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=202=E3=80=81=E5=AE=9E=E7=8E=B0=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E7=94=A8=E6=88=B7=EF=BC=8C=E5=BD=93=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E7=94=A8=E6=88=B7=E6=97=B6=EF=BC=8C=E8=AF=A5?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=9A=84=E6=89=80=E6=9C=89=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=B0=86=E8=BD=AC=E4=B9=89=E5=88=B0=E8=B6=85=E7=BA=A7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E8=B4=A6=E6=88=B7=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commands/command.go | 1 + controllers/book.go | 2 +- controllers/document.go | 3 +- controllers/home.go | 7 + controllers/label.go | 60 + controllers/manager.go | 35 +- docs/.gitignore | 1 - models/book.go | 326 +-- models/document.go | 2 +- models/label.go | 92 + models/member.go | 65 + routers/filter.go | 13 +- routers/router.go | 3 + .../plugins/tagsinput/bootstrap-tagsinput.css | 55 + .../plugins/tagsinput/bootstrap-tagsinput.js | 646 ++++++ .../tagsinput/bootstrap-tagsinput.less | 50 + .../tagsinput/bootstrap-tagsinput.min.js | 7 + .../tagsinput/bootstrap-tagsinput.min.js.map | 1 + static/css/main.css | 46 +- .../github.com/PuerkitoBio/goquery/README.md | 23 +- .../russross/blackfriday/.gitignore | 8 + .../russross/blackfriday/.travis.yml | 30 + .../russross/blackfriday/LICENSE.txt | 29 + .../github.com/russross/blackfriday/README.md | 292 +++ .../github.com/russross/blackfriday/block.go | 1450 ++++++++++++++ .../russross/blackfriday/block_test.go | 1781 +++++++++++++++++ vendor/github.com/russross/blackfriday/doc.go | 32 + .../github.com/russross/blackfriday/html.go | 949 +++++++++ .../github.com/russross/blackfriday/inline.go | 1154 +++++++++++ .../russross/blackfriday/inline_test.go | 1242 ++++++++++++ .../github.com/russross/blackfriday/latex.go | 332 +++ .../russross/blackfriday/markdown.go | 931 +++++++++ .../russross/blackfriday/markdown_test.go | 75 + .../russross/blackfriday/ref_test.go | 128 ++ .../russross/blackfriday/smartypants.go | 400 ++++ .../testdata/Amps and angle encoding.html | 17 + .../testdata/Amps and angle encoding.text | 21 + .../blackfriday/testdata/Auto links.html | 18 + .../blackfriday/testdata/Auto links.text | 13 + .../testdata/Backslash escapes.html | 123 ++ .../testdata/Backslash escapes.text | 126 ++ .../Blockquotes with code blocks.html | 15 + .../Blockquotes with code blocks.text | 11 + .../blackfriday/testdata/Code Blocks.html | 18 + .../blackfriday/testdata/Code Blocks.text | 14 + .../blackfriday/testdata/Code Spans.html | 5 + .../blackfriday/testdata/Code Spans.text | 6 + ...like lines no empty line before block.html | 14 + ...like lines no empty line before block.text | 8 + ...apped paragraphs with list-like lines.html | 8 + ...apped paragraphs with list-like lines.text | 8 + .../testdata/Horizontal rules.html | 71 + .../testdata/Horizontal rules.text | 67 + .../testdata/Inline HTML (Advanced).html | 15 + .../testdata/Inline HTML (Advanced).text | 15 + .../testdata/Inline HTML (Simple).html | 72 + .../testdata/Inline HTML (Simple).text | 69 + .../testdata/Inline HTML comments.html | 13 + .../testdata/Inline HTML comments.text | 13 + .../testdata/Links, inline style.html | 11 + .../testdata/Links, inline style.text | 12 + .../testdata/Links, reference style.html | 52 + .../testdata/Links, reference style.text | 71 + .../testdata/Links, shortcut references.html | 9 + .../testdata/Links, shortcut references.text | 20 + .../testdata/Literal quotes in titles.html | 3 + .../testdata/Literal quotes in titles.text | 7 + .../Markdown Documentation - Basics.html | 314 +++ .../Markdown Documentation - Basics.text | 306 +++ .../Markdown Documentation - Syntax.html | 946 +++++++++ .../Markdown Documentation - Syntax.text | 888 ++++++++ .../testdata/Nested blockquotes.html | 9 + .../testdata/Nested blockquotes.text | 5 + .../testdata/Ordered and unordered lists.html | 166 ++ .../testdata/Ordered and unordered lists.text | 131 ++ .../testdata/Strong and em together.html | 7 + .../testdata/Strong and em together.text | 7 + .../russross/blackfriday/testdata/Tabs.html | 26 + .../russross/blackfriday/testdata/Tabs.text | 21 + .../blackfriday/testdata/Tidyness.html | 9 + .../blackfriday/testdata/Tidyness.text | 5 + views/book/setting.tpl | 23 +- views/home/index.tpl | 13 + views/label/index.tpl | 65 + views/manager/users.tpl | 26 + 85 files changed, 13999 insertions(+), 184 deletions(-) create mode 100644 controllers/label.go delete mode 100644 docs/.gitignore create mode 100644 models/label.go create mode 100644 static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.css create mode 100644 static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.js create mode 100644 static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.less create mode 100644 static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.min.js create mode 100644 static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.min.js.map create mode 100644 vendor/github.com/russross/blackfriday/.gitignore create mode 100644 vendor/github.com/russross/blackfriday/.travis.yml create mode 100644 vendor/github.com/russross/blackfriday/LICENSE.txt create mode 100644 vendor/github.com/russross/blackfriday/README.md create mode 100644 vendor/github.com/russross/blackfriday/block.go create mode 100644 vendor/github.com/russross/blackfriday/block_test.go create mode 100644 vendor/github.com/russross/blackfriday/doc.go create mode 100644 vendor/github.com/russross/blackfriday/html.go create mode 100644 vendor/github.com/russross/blackfriday/inline.go create mode 100644 vendor/github.com/russross/blackfriday/inline_test.go create mode 100644 vendor/github.com/russross/blackfriday/latex.go create mode 100644 vendor/github.com/russross/blackfriday/markdown.go create mode 100644 vendor/github.com/russross/blackfriday/markdown_test.go create mode 100644 vendor/github.com/russross/blackfriday/ref_test.go create mode 100644 vendor/github.com/russross/blackfriday/smartypants.go create mode 100644 vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Auto links.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Auto links.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Backslash escapes.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Backslash escapes.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Code Blocks.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Code Blocks.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Code Spans.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Code Spans.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Horizontal rules.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Horizontal rules.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, inline style.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, inline style.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, reference style.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, reference style.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Strong and em together.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Strong and em together.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Tabs.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Tabs.text create mode 100644 vendor/github.com/russross/blackfriday/testdata/Tidyness.html create mode 100644 vendor/github.com/russross/blackfriday/testdata/Tidyness.text create mode 100644 views/label/index.tpl diff --git a/commands/command.go b/commands/command.go index 0ab127ee..ee4c9bc6 100644 --- a/commands/command.go +++ b/commands/command.go @@ -78,6 +78,7 @@ func RegisterModel() { new(models.MemberToken), new(models.DocumentHistory), new(models.Migration), + new(models.Label), ) migrate.RegisterMigration() } diff --git a/controllers/book.go b/controllers/book.go index 01a591f6..62f4240a 100644 --- a/controllers/book.go +++ b/controllers/book.go @@ -137,7 +137,7 @@ func (c *BookController) SaveBook() { comment_status = "closed" } if tag != ""{ - tags := strings.Split(tag,";") + tags := strings.Split(tag,",") if len(tags) > 10 { c.JsonResult(6005,"最多允许添加10个标签") } diff --git a/controllers/document.go b/controllers/document.go index c4180511..2760bacd 100644 --- a/controllers/document.go +++ b/controllers/document.go @@ -26,6 +26,7 @@ import ( "github.com/lifei6671/mindoc/models" "github.com/lifei6671/mindoc/utils" "github.com/lifei6671/mindoc/utils/wkhtmltopdf" + "github.com/russross/blackfriday" ) //DocumentController struct. @@ -126,7 +127,7 @@ func (c *DocumentController) Index() { c.Data["Model"] = bookResult c.Data["Result"] = template.HTML(tree) c.Data["Title"] = "概要" - c.Data["Content"] = bookResult.Description + c.Data["Content"] = template.HTML( blackfriday.MarkdownBasic([]byte(bookResult.Description))) } //阅读文档. diff --git a/controllers/home.go b/controllers/home.go index dca97ee8..51f9a99f 100644 --- a/controllers/home.go +++ b/controllers/home.go @@ -43,4 +43,11 @@ func (c *HomeController) Index() { c.Data["Lists"] = books + labels ,totalCount,err := models.NewLabel().FindToPager(1,10) + + if err != nil { + c.Data["Labels"] = make([]*models.Label,0) + }else{ + c.Data["Labels"] = labels + } } diff --git a/controllers/label.go b/controllers/label.go new file mode 100644 index 00000000..c2fe653f --- /dev/null +++ b/controllers/label.go @@ -0,0 +1,60 @@ +package controllers + +import ( + "github.com/lifei6671/mindoc/models" + "github.com/astaxie/beego/orm" + "github.com/astaxie/beego" + "github.com/lifei6671/mindoc/conf" + "github.com/lifei6671/mindoc/utils" +) + +type LabelController struct { + BaseController +} + +func (c *LabelController) Index() { + c.Prepare() + c.TplName = "label/index.tpl" + + //如果没有开启你们访问则跳转到登录 + if !c.EnableAnonymous && c.Member == nil { + c.Redirect(beego.URLFor("AccountController.Login"),302) + return + } + + labelName := c.Ctx.Input.Param(":key") + pageIndex,_ := c.GetInt("page",1) + if labelName == "" { + c.Abort("404") + } + _,err := models.NewLabel().FindFirst("label_name",labelName) + + if err != nil { + if err == orm.ErrNoRows { + c.Abort("404") + }else{ + beego.Error(err) + c.Abort("500") + } + } + member_id := 0 + if c.Member != nil { + member_id = c.Member.MemberId + } + search_result,totalCount,err := models.NewBook().FindForLabelToPager(labelName,pageIndex,conf.PageSize,member_id) + + if err != nil { + beego.Error(err) + return + } + if totalCount > 0 { + html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount) + + c.Data["PageHtml"] = html + }else { + c.Data["PageHtml"] = "" + } + c.Data["Lists"] = search_result + + c.Data["LabelName"] = labelName +} diff --git a/controllers/manager.go b/controllers/manager.go index 63548c12..6809ba7c 100644 --- a/controllers/manager.go +++ b/controllers/manager.go @@ -186,6 +186,7 @@ func (c *ManagerController) ChangeMemberRole() { c.JsonResult(0, "ok", member) } +//编辑用户信息. func (c *ManagerController) EditMember() { c.Prepare() c.TplName = "manager/edit_users.tpl" @@ -238,6 +239,38 @@ func (c *ManagerController) EditMember() { c.Data["Model"] = member } +//删除一个用户,并将该用户的所有信息转移到超级管理员上. +func (c *ManagerController) DeleteMember() { + c.Prepare() + member_id,_ := c.GetInt("id",0) + + if member_id <= 0 { + c.JsonResult(404,"参数错误") + } + + _ ,err := models.NewMember().Find(member_id) + + if err != nil { + beego.Error(err) + c.JsonResult(500,"用户不存在") + } + superMember,err := models.NewMember().FindByFieldFirst("role",0) + + if err != nil { + beego.Error(err) + c.JsonResult(5001,"未能找到超级管理员") + } + + err = models.NewMember().Delete(member_id,superMember.MemberId) + + if err != nil { + beego.Error(err) + c.JsonResult(5002,"删除失败") + } + c.JsonResult(0,"ok") +} + +//项目列表. func (c *ManagerController) Books() { c.Prepare() c.TplName = "manager/books.tpl" @@ -261,7 +294,7 @@ func (c *ManagerController) Books() { c.Data["Lists"] = books } -//编辑项目 +//编辑项目. func (c *ManagerController) EditBook() { c.Prepare() diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index bfa6a22a..00000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# Created by .ignore support plugin (hsz.mobi) diff --git a/models/book.go b/models/book.go index 0e6b2bb5..59d9c3ef 100644 --- a/models/book.go +++ b/models/book.go @@ -3,53 +3,55 @@ package models import ( "time" + "strings" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" "github.com/lifei6671/mindoc/conf" - "github.com/astaxie/beego/logs" - "strings" - "github.com/astaxie/beego" + "fmt" ) // Book struct . type Book struct { - BookId int `orm:"pk;auto;unique;column(book_id)" json:"book_id"` + BookId int `orm:"pk;auto;unique;column(book_id)" json:"book_id"` // BookName 项目名称. - BookName string `orm:"column(book_name);size(500)" json:"book_name"` + BookName string `orm:"column(book_name);size(500)" json:"book_name"` // Identify 项目唯一标识. - Identify string `orm:"column(identify);size(100);unique" json:"identify"` - OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"` + Identify string `orm:"column(identify);size(100);unique" json:"identify"` + OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"` // Description 项目描述. - Description string `orm:"column(description);size(2000)" json:"description"` - Label string `orm:"column(label);size(500)" json:"label"` + Description string `orm:"column(description);size(2000)" json:"description"` + Label string `orm:"column(label);size(500)" json:"label"` // PrivatelyOwned 项目私有: 0 公开/ 1 私有 - PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"` + PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"` // 当项目是私有时的访问Token. - PrivateToken string `orm:"column(private_token);size(500);null" json:"private_token"` + PrivateToken string `orm:"column(private_token);size(500);null" json:"private_token"` //状态:0 正常/1 已删除 - Status int `orm:"column(status);type(int);default(0)" json:"status"` + Status int `orm:"column(status);type(int);default(0)" json:"status"` //默认的编辑器. - Editor string `orm:"column(editor);size(50)" json:"editor"` + Editor string `orm:"column(editor);size(50)" json:"editor"` // DocCount 包含文档数量. - DocCount int `orm:"column(doc_count);type(int)" json:"doc_count"` + DocCount int `orm:"column(doc_count);type(int)" json:"doc_count"` // CommentStatus 评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论. - CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"` - CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"` + CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"` + CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"` //封面地址 - Cover string `orm:"column(cover);size(1000)" json:"cover"` + Cover string `orm:"column(cover);size(1000)" json:"cover"` //主题风格 - Theme string `orm:"column(theme);size(255);default(default)" json:"theme"` + Theme string `orm:"column(theme);size(255);default(default)" json:"theme"` // CreateTime 创建时间 . - CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"` - MemberId int `orm:"column(member_id);size(100)" json:"member_id"` - ModifyTime time.Time `orm:"type(datetime);column(modify_time);null;auto_now" json:"modify_time"` - Version int64 `orm:"type(bigint);column(version)" json:"version"` + CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"` + MemberId int `orm:"column(member_id);size(100)" json:"member_id"` + ModifyTime time.Time `orm:"type(datetime);column(modify_time);null;auto_now" json:"modify_time"` + Version int64 `orm:"type(bigint);column(version)" json:"version"` } - // TableName 获取对应数据库表名. func (m *Book) TableName() string { return "books" } + // TableEngine 获取数据使用的引擎. func (m *Book) TableEngine() string { return "INNODB" @@ -64,18 +66,22 @@ func NewBook() *Book { func (m *Book) Insert() error { o := orm.NewOrm() -// o.Begin() + // o.Begin() - _,err := o.Insert(m) + _, err := o.Insert(m) if err == nil { + if m.Label != "" { + NewLabel().InsertOrUpdateMulti(m.Label) + } + relationship := NewRelationship() relationship.BookId = m.BookId relationship.RoleId = 0 relationship.MemberId = m.MemberId err = relationship.Insert() if err != nil { - logs.Error("插入项目与用户关联 => ",err) + logs.Error("插入项目与用户关联 => ", err) //o.Rollback() return err } @@ -84,7 +90,7 @@ func (m *Book) Insert() error { document.DocumentName = "空白文档" document.MemberId = m.MemberId err = document.InsertOrUpdate() - if err != nil{ + if err != nil { //o.Rollback() return err } @@ -95,113 +101,113 @@ func (m *Book) Insert() error { return err } -func (m *Book) Find(id int) (*Book,error) { +func (m *Book) Find(id int) (*Book, error) { if id <= 0 { - return m,ErrInvalidParameter + return m, ErrInvalidParameter } o := orm.NewOrm() + err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", id).One(m) - err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",id).One(m) - - return m,err + return m, err } -func (m *Book) Update(cols... string) error { +func (m *Book) Update(cols ...string) error { o := orm.NewOrm() - _,err := o.Update(m,cols...) + temp := NewBook() + temp.BookId = m.BookId + + if err := o.Read(temp);err != nil { + return err + } + + if (m.Label + temp.Label) != "" { + + go NewLabel().InsertOrUpdateMulti(m.Label + "," + temp.Label) + } + + _, err := o.Update(m, cols...) return err } //根据指定字段查询结果集. -func (m *Book) FindByField(field string,value interface{}) ([]*Book,error) { +func (m *Book) FindByField(field string, value interface{}) ([]*Book, error) { o := orm.NewOrm() var books []*Book - _,err := o.QueryTable(m.TableNameWithPrefix()).Filter(field,value).All(&books) + _, err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, value).All(&books) - return books,err + return books, err } //根据指定字段查询一个结果. -func (m *Book) FindByFieldFirst(field string,value interface{})(*Book,error) { +func (m *Book) FindByFieldFirst(field string, value interface{}) (*Book, error) { o := orm.NewOrm() - err := o.QueryTable(m.TableNameWithPrefix()).Filter(field,value).One(m) + err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, value).One(m) - return m,err + return m, err } -func (m *Book) FindByIdentify(identify string) (*Book,error) { +func (m *Book) FindByIdentify(identify string) (*Book, error) { o := orm.NewOrm() - err := o.QueryTable(m.TableNameWithPrefix()).Filter("identify",identify).One(m) + err := o.QueryTable(m.TableNameWithPrefix()).Filter("identify", identify).One(m) - return m,err + return m, err } //分页查询指定用户的项目 -func (m *Book) FindToPager(pageIndex, pageSize ,memberId int) (books []*BookResult,totalCount int,err error){ +func (m *Book) FindToPager(pageIndex, pageSize, memberId int) (books []*BookResult, totalCount int, err error) { relationship := NewRelationship() o := orm.NewOrm() - qb, _ := orm.NewQueryBuilder("mysql") + sql1 := "SELECT COUNT(book.book_id) AS total_count FROM " + m.TableNameWithPrefix() + " AS book LEFT JOIN " + + relationship.TableNameWithPrefix() + " AS rel ON book.book_id=rel.book_id AND rel.member_id = ? WHERE rel.relationship_id > 0 " - qb.Select("COUNT(book.book_id) AS total_count"). - From(m.TableNameWithPrefix() + " AS book"). - LeftJoin(relationship.TableNameWithPrefix() + " AS rel"). - On("book.book_id=rel.book_id AND rel.member_id = ?"). - Where("rel.relationship_id > 0") - - err = o.Raw(qb.String(),memberId).QueryRow(&totalCount) + err = o.Raw(sql1, memberId).QueryRow(&totalCount) if err != nil { return } offset := (pageIndex - 1) * pageSize - qb2,_ := orm.NewQueryBuilder("mysql") - qb2.Select("book.*,rel.member_id","rel.role_id","m.account as create_name"). - From(m.TableNameWithPrefix() + " AS book"). - LeftJoin(relationship.TableNameWithPrefix() + " AS rel").On("book.book_id=rel.book_id AND rel.member_id = ?"). - LeftJoin(relationship.TableNameWithPrefix() + " AS rel1").On("book.book_id=rel1.book_id AND rel1.role_id=0"). - LeftJoin(NewMember().TableNameWithPrefix() + " AS m").On("rel1.member_id=m.member_id"). - Where("rel.relationship_id > 0"). - OrderBy("book.order_index DESC ","book.book_id").Desc(). - Limit(pageSize). - Offset(offset) + sql2 := "SELECT book.*,rel.member_id,rel.role_id,m.account as create_name FROM " + m.TableNameWithPrefix() + " AS book" + + " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel ON book.book_id=rel.book_id AND rel.member_id = ?" + + " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel1 ON book.book_id=rel1.book_id AND rel1.role_id=0" + + " LEFT JOIN " + NewMember().TableNameWithPrefix() + " AS m ON rel1.member_id=m.member_id " + + " WHERE rel.relationship_id > 0 ORDER BY book.order_index DESC,book.book_id DESC LIMIT " + fmt.Sprintf("%d,%d",offset,pageSize) - _,err = o.Raw(qb2.String(),memberId).QueryRows(&books) + _, err = o.Raw(sql2, memberId).QueryRows(&books) if err != nil { - logs.Error("分页查询项目列表 => ",err) + logs.Error("分页查询项目列表 => ", err) return } sql := "SELECT m.account,doc.modify_time FROM md_documents AS doc LEFT JOIN md_members AS m ON doc.modify_at=m.member_id WHERE book_id = ? LIMIT 1 ORDER BY doc.modify_time DESC" - if err == nil && len(books) > 0{ - for index,book := range books { - var text struct{ - Account string + if err == nil && len(books) > 0 { + for index, book := range books { + var text struct { + Account string ModifyTime time.Time } - - err1 := o.Raw(sql,book.BookId).QueryRow(&text) + err1 := o.Raw(sql, book.BookId).QueryRow(&text) if err1 == nil { books[index].LastModifyText = text.Account + " 于 " + text.ModifyTime.Format("2006-01-02 15:04:05") } - if book.RoleId == 0{ + if book.RoleId == 0 { book.RoleName = "创始人" - }else if book.RoleId == 1 { + } else if book.RoleId == 1 { book.RoleName = "管理员" - }else if book.RoleId == 2 { + } else if book.RoleId == 2 { book.RoleName = "编辑者" - }else if book.RoleId == 3 { + } else if book.RoleId == 3 { book.RoleName = "观察者" } } @@ -211,7 +217,7 @@ func (m *Book) FindToPager(pageIndex, pageSize ,memberId int) (books []*BookResu // 彻底删除项目. func (m *Book) ThoroughDeleteBook(id int) error { - if id <= 0{ + if id <= 0 { return ErrInvalidParameter } o := orm.NewOrm() @@ -221,17 +227,10 @@ func (m *Book) ThoroughDeleteBook(id int) error { return err } o.Begin() - //sql1 := "DELETE FROM " + NewComment().TableNameWithPrefix() + " WHERE book_id = ?" - // - //_,err := o.Raw(sql1,m.BookId).Exec() - // - //if err != nil { - // o.Rollback() - // return err - //} + sql2 := "DELETE FROM " + NewDocument().TableNameWithPrefix() + " WHERE book_id = ?" - _,err := o.Raw(sql2,m.BookId).Exec() + _, err := o.Raw(sql2, m.BookId).Exec() if err != nil { o.Rollback() @@ -239,7 +238,7 @@ func (m *Book) ThoroughDeleteBook(id int) error { } sql3 := "DELETE FROM " + m.TableNameWithPrefix() + " WHERE book_id = ?" - _,err = o.Raw(sql3,m.BookId).Exec() + _, err = o.Raw(sql3, m.BookId).Exec() if err != nil { o.Rollback() @@ -247,19 +246,23 @@ func (m *Book) ThoroughDeleteBook(id int) error { } sql4 := "DELETE FROM " + NewRelationship().TableNameWithPrefix() + " WHERE book_id = ?" - _,err = o.Raw(sql4,m.BookId).Exec() + _, err = o.Raw(sql4, m.BookId).Exec() if err != nil { o.Rollback() return err } + if m.Label != "" { + NewLabel().InsertOrUpdateMulti(m.Label) + } + return o.Commit() } //分页查找系统首页数据. -func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []*BookResult,totalCount int,err error) { +func (m *Book) FindForHomeToPager(pageIndex, pageSize, member_id int) (books []*BookResult, totalCount int, err error) { o := orm.NewOrm() offset := (pageIndex - 1) * pageSize @@ -267,7 +270,7 @@ func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []* if member_id > 0 { sql1 := "SELECT COUNT(*) FROM md_books AS book LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.member_id = ? WHERE relationship_id > 0 OR book.privately_owned = 0" - err = o.Raw(sql1,member_id).QueryRow(&totalCount) + err = o.Raw(sql1, member_id).QueryRow(&totalCount) if err != nil { return } @@ -277,12 +280,12 @@ func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []* LEFT JOIN md_members AS member ON rel1.member_id = member.member_id WHERE rel.relationship_id > 0 OR book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?` - _,err = o.Raw(sql2,member_id,offset,pageSize).QueryRows(&books) + _, err = o.Raw(sql2, member_id, offset, pageSize).QueryRows(&books) return - }else{ - count,err1 := o.QueryTable(m.TableNameWithPrefix()).Filter("privately_owned",0).Count() + } else { + count, err1 := o.QueryTable(m.TableNameWithPrefix()).Filter("privately_owned", 0).Count() if err1 != nil { err = err1 @@ -295,7 +298,7 @@ func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []* LEFT JOIN md_members AS member ON rel.member_id = member.member_id WHERE book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?` - _,err = o.Raw(sql,offset,pageSize).QueryRows(&books) + _, err = o.Raw(sql, offset, pageSize).QueryRows(&books) return @@ -303,30 +306,75 @@ func (m *Book) FindForHomeToPager(pageIndex, pageSize ,member_id int) (books []* } +//分页全局搜索. +func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_id int) (books []*BookResult, totalCount int, err error) { + o := orm.NewOrm() + + keyword = "%" + keyword + "%" + offset := (pageIndex - 1) * pageSize + //如果是登录用户 + if member_id > 0 { + sql1 := "SELECT COUNT(*) FROM md_books AS book LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.member_id = ? WHERE (relationship_id > 0 OR book.privately_owned = 0) AND book.label LIKE ?" + + err = o.Raw(sql1, member_id,keyword).QueryRow(&totalCount) + if err != nil { + return + } + sql2 := `SELECT book.*,rel1.*,member.account AS create_name FROM md_books AS book + LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.member_id = ? + LEFT JOIN md_relationship AS rel1 ON rel1.book_id = book.book_id AND rel1.role_id = 0 + LEFT JOIN md_members AS member ON rel1.member_id = member.member_id + WHERE (rel.relationship_id > 0 OR book.privately_owned = 0) AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?` + + _, err = o.Raw(sql2, member_id,keyword, offset, pageSize).QueryRows(&books) + + return + + } else { + count, err1 := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("privately_owned", 0).Filter("label__icontains",keyword).Count() + + if err1 != nil { + err = err1 + return + } + totalCount = int(count) + + sql := `SELECT book.*,rel.*,member.account AS create_name FROM md_books AS book + LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0 + LEFT JOIN md_members AS member ON rel.member_id = member.member_id + WHERE book.privately_owned = 0 AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?` + + _, err = o.Raw(sql,keyword, offset, pageSize).QueryRows(&books) + + return + + } +} + + func (book *Book) ToBookResult() *BookResult { m := NewBookResult() - m.BookId = book.BookId - m.BookName = book.BookName - m.Identify = book.Identify - m.OrderIndex = book.OrderIndex - m.Description = strings.Replace(book.Description, "\r\n", "
", -1) - m.PrivatelyOwned = book.PrivatelyOwned - m.PrivateToken = book.PrivateToken - m.DocCount = book.DocCount - m.CommentStatus = book.CommentStatus - m.CommentCount = book.CommentCount - m.CreateTime = book.CreateTime - m.ModifyTime = book.ModifyTime - m.Cover = book.Cover - m.Label = book.Label - m.Status = book.Status - m.Editor = book.Editor - m.Theme = book.Theme + m.BookId = book.BookId + m.BookName = book.BookName + m.Identify = book.Identify + m.OrderIndex = book.OrderIndex + m.Description = strings.Replace(book.Description, "\r\n", "
", -1) + m.PrivatelyOwned = book.PrivatelyOwned + m.PrivateToken = book.PrivateToken + m.DocCount = book.DocCount + m.CommentStatus = book.CommentStatus + m.CommentCount = book.CommentCount + m.CreateTime = book.CreateTime + m.ModifyTime = book.ModifyTime + m.Cover = book.Cover + m.Label = book.Label + m.Status = book.Status + m.Editor = book.Editor + m.Theme = book.Theme - - if book.Theme == ""{ + if book.Theme == "" { m.Theme = "default" } if book.Editor == "" { @@ -336,61 +384,13 @@ func (book *Book) ToBookResult() *BookResult { } //重置文档数量 -func (m *Book) ResetDocumentNumber(book_id int) { +func (m *Book) ResetDocumentNumber(book_id int) { o := orm.NewOrm() - totalCount,err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("book_id",book_id).Count() + totalCount, err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("book_id", book_id).Count() if err == nil { - o.Raw("UPDATE md_books SET doc_count = ? WHERE book_id = ?",int(totalCount),book_id).Exec() - }else{ + o.Raw("UPDATE md_books SET doc_count = ? WHERE book_id = ?", int(totalCount), book_id).Exec() + } else { beego.Error(err) } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/models/document.go b/models/document.go index e4a149e3..f20767a3 100644 --- a/models/document.go +++ b/models/document.go @@ -155,7 +155,7 @@ func (m *Document) ReleaseContent(book_id int) { func (m *Document) FindListByBookId(book_id int) (docs []*Document, err error) { o := orm.NewOrm() - _, err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).All(&docs) + _, err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).OrderBy("order_sort").All(&docs) return } diff --git a/models/label.go b/models/label.go new file mode 100644 index 00000000..7f1aa8ae --- /dev/null +++ b/models/label.go @@ -0,0 +1,92 @@ +package models + +import ( + "github.com/lifei6671/mindoc/conf" + "github.com/astaxie/beego/orm" + "strings" +) + +type Label struct { + LabelId int `orm:"column(label_id);pk;auto;unique;" json:"label_id"` + LabelName string `orm:"column(label_name);size(50);unique" json:"label_name"` + BookNumber int `orm:"column(book_number)" json:"book_number"` +} + +// TableName 获取对应数据库表名. +func (m *Label) TableName() string { + return "label" +} +// TableEngine 获取数据使用的引擎. +func (m *Label) TableEngine() string { + return "INNODB" +} + +func (m *Label)TableNameWithPrefix() string { + return conf.GetDatabasePrefix() + m.TableName() +} + +func NewLabel() *Label { + return &Label{} +} + +func (m *Label) FindFirst(field string, value interface{}) (*Label,error){ + o := orm.NewOrm() + + err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, value).One(m) + + return m, err +} + +//插入或更新标签. +func (m *Label) InsertOrUpdate(labelName string) error { + o := orm.NewOrm() + + err := o.QueryTable(m.TableNameWithPrefix()).Filter("label_name",labelName).One(m) + if err != nil && err != orm.ErrNoRows { + return err + } + count,_ := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("label__icontains",labelName).Count() + m.BookNumber = int(count) + m.LabelName = labelName + + if err == orm.ErrNoRows { + err = nil + m.LabelName = labelName + _,err = o.Insert(m) + }else{ + _,err = o.Update(m) + } + return err +} + +//批量插入或更新标签. +func (m *Label) InsertOrUpdateMulti(labels string) { + if labels != "" { + labelArray := strings.Split(labels, ",") + + for _, label := range labelArray { + if label != "" { + NewLabel().InsertOrUpdate(label) + } + } + } +} + +//分页查找标签. +func (m *Label) FindToPager(pageIndex, pageSize int) (labels []*Label,totalCount int,err error) { + o := orm.NewOrm() + + count,err := o.QueryTable(m.TableNameWithPrefix()).Count() + + if err != nil { + return + } + totalCount = int(count) + + offset := (pageIndex - 1) * pageSize + + _,err = o.QueryTable(m.TableNameWithPrefix()).OrderBy("-book_number").Offset(offset).Limit(pageSize).All(&labels) + + return +} + diff --git a/models/member.go b/models/member.go index e9f79f5d..6bffe8f2 100644 --- a/models/member.go +++ b/models/member.go @@ -217,6 +217,7 @@ func (m *Member) ResolveRoleName() { } } +//根据账号查找用户. func (m *Member) FindByAccount(account string) (*Member, error) { o := orm.NewOrm() @@ -228,6 +229,7 @@ func (m *Member) FindByAccount(account string) (*Member, error) { return m, err } +//分页查找用户. func (m *Member) FindToPager(pageIndex, pageSize int) ([]*Member, int64, error) { o := orm.NewOrm() @@ -260,6 +262,7 @@ func (c *Member) IsAdministrator() bool { return c.Role == 0 || c.Role == 1 } +//根据指定字段查找用户. func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, error) { o := orm.NewOrm() @@ -268,6 +271,7 @@ func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, err return m, err } +//校验用户. func (m *Member) Valid(is_hash_password bool) error { //邮箱不能为空 @@ -324,6 +328,67 @@ func (m *Member) Valid(is_hash_password bool) error { return nil } +//删除一个用户. + +func (m *Member) Delete(oldId int,newId int) error { + o := orm.NewOrm() + + err := o.Begin() + + if err != nil { + return err + } + + _,err = o.Raw("DELETE FROM md_members WHERE member_id = ?",oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_attachment SET `create_at` = ? WHERE `create_at` = ?",newId,oldId).Exec() + + if err != nil { + o.Rollback() + return err + } + + _,err = o.Raw("UPDATE md_books SET member_id = ? WHERE member_id = ?",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_document_history SET member_id=? WHERE member_id = ?",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_document_history SET modify_at=? WHERE modify_at = ?",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_documents SET member_id = ? WHERE member_id = ?;",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_documents SET modify_at = ? WHERE modify_at = ?",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + _,err = o.Raw("UPDATE md_relationship SET member_id = ? WHERE member_id = ?",newId,oldId).Exec() + if err != nil { + o.Rollback() + return err + } + if err = o.Commit();err != nil { + o.Rollback() + return err + } + return nil +} + + diff --git a/routers/filter.go b/routers/filter.go index da34de98..b9811682 100644 --- a/routers/filter.go +++ b/routers/filter.go @@ -5,6 +5,7 @@ import ( "github.com/astaxie/beego/context" "github.com/lifei6671/mindoc/conf" "github.com/lifei6671/mindoc/models" + "encoding/json" ) func init() { @@ -12,7 +13,17 @@ func init() { _, ok := ctx.Input.Session(conf.LoginSessionName).(models.Member) if !ok { - ctx.Redirect(302, beego.URLFor("AccountController.Login")) + if ctx.Input.IsAjax() { + jsonData := make(map[string]interface{},3) + + jsonData["errcode"] = 403 + jsonData["message"] = "请登录后再操作" + returnJSON, _ := json.Marshal(jsonData) + + ctx.ResponseWriter.Write(returnJSON) + }else{ + ctx.Redirect(302, beego.URLFor("AccountController.Login")) + } } } beego.InsertFilter("/manager",beego.BeforeRouter,FilterUser) diff --git a/routers/router.go b/routers/router.go index a951dadb..880ec872 100644 --- a/routers/router.go +++ b/routers/router.go @@ -19,6 +19,7 @@ func init() { beego.Router("/manager/users", &controllers.ManagerController{},"*:Users") beego.Router("/manager/users/edit/:id", &controllers.ManagerController{},"*:EditMember") beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember") + beego.Router("/manager/member/delete", &controllers.ManagerController{},"post:DeleteMember") beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus") beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole") beego.Router("/manager/books", &controllers.ManagerController{},"*:Books") @@ -82,5 +83,7 @@ func init() { beego.Router("/comment/index", &controllers.CommentController{},"*:Index") beego.Router("/search",&controllers.SearchController{},"get:Index") + + beego.Router("/tag/:key", &controllers.LabelController{},"get:Index") } diff --git a/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.css b/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.css new file mode 100644 index 00000000..b31f01c7 --- /dev/null +++ b/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.css @@ -0,0 +1,55 @@ +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; + cursor: text; +} +.bootstrap-tagsinput input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0 6px; + margin: 0; + width: auto; + max-width: inherit; +} +.bootstrap-tagsinput.form-control input::-moz-placeholder { + color: #777; + opacity: 1; +} +.bootstrap-tagsinput.form-control input:-ms-input-placeholder { + color: #777; +} +.bootstrap-tagsinput.form-control input::-webkit-input-placeholder { + color: #777; +} +.bootstrap-tagsinput input:focus { + border: none; + box-shadow: none; +} +.bootstrap-tagsinput .tag { + margin-right: 2px; + color: white; +} +.bootstrap-tagsinput .tag [data-role="remove"] { + margin-left: 8px; + cursor: pointer; +} +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; + padding: 0px 2px; +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} diff --git a/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.js b/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.js new file mode 100644 index 00000000..2b403f77 --- /dev/null +++ b/static/bootstrap/plugins/tagsinput/bootstrap-tagsinput.js @@ -0,0 +1,646 @@ +(function ($) { + "use strict"; + + var defaultOptions = { + tagClass: function(item) { + return 'label label-info'; + }, + itemValue: function(item) { + return item ? item.toString() : item; + }, + itemText: function(item) { + return this.itemValue(item); + }, + itemTitle: function(item) { + return null; + }, + freeInput: true, + addOnBlur: true, + maxTags: undefined, + maxChars: undefined, + confirmKeys: [13, 44], + delimiter: ',', + delimiterRegex: null, + cancelConfirmKeysOnEmpty: true, + onTagExists: function(item, $tag) { + $tag.hide().fadeIn(); + }, + trimValue: false, + allowDuplicates: false + }; + + /** + * Constructor function + */ + function TagsInput(element, options) { + this.itemsArray = []; + + this.$element = $(element); + this.$element.hide(); + + this.isSelect = (element.tagName === 'SELECT'); + this.multiple = (this.isSelect && element.hasAttribute('multiple')); + this.objectItems = options && options.itemValue; + this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; + this.inputSize = Math.max(1, this.placeholderText.length); + + this.$container = $('
'); + this.$input = $('').appendTo(this.$container); + + this.$element.before(this.$container); + + this.build(options); + } + + TagsInput.prototype = { + constructor: TagsInput, + + /** + * Adds the given item as a new tag. Pass true to dontPushVal to prevent + * updating the elements val() + */ + add: function(item, dontPushVal, options) { + var self = this; + + if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) + return; + + // Ignore falsey values, except false + if (item !== false && !item) + return; + + // Trim value + if (typeof item === "string" && self.options.trimValue) { + item = $.trim(item); + } + + // Throw an error when trying to add an object while the itemValue option was not set + if (typeof item === "object" && !self.objectItems) + throw("Can't add objects when itemValue option is not set"); + + // Ignore strings only containg whitespace + if (item.toString().match(/^\s*$/)) + return; + + // If SELECT but not multiple, remove current tag + if (self.isSelect && !self.multiple && self.itemsArray.length > 0) + self.remove(self.itemsArray[0]); + + if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { + var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter; + var items = item.split(delimiter); + if (items.length > 1) { + for (var i = 0; i < items.length; i++) { + this.add(items[i], true); + } + + if (!dontPushVal) + self.pushVal(); + return; + } + } + + var itemValue = self.options.itemValue(item), + itemText = self.options.itemText(item), + tagClass = self.options.tagClass(item), + itemTitle = self.options.itemTitle(item); + + // Ignore items allready added + var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; + if (existing && !self.options.allowDuplicates) { + // Invoke onTagExists + if (self.options.onTagExists) { + var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); + self.options.onTagExists(item, $existingTag); + } + return; + } + + // if length greater than limit + if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) + return; + + // raise beforeItemAdd arg + var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options}); + self.$element.trigger(beforeItemAddEvent); + if (beforeItemAddEvent.cancel) + return; + + // register item in internal array and map + self.itemsArray.push(item); + + // add a tag element + + var $tag = $('' + htmlEncode(itemText) + ''); + $tag.data('item', item); + self.findInputWrapper().before($tag); + $tag.after(' '); + + // add