From 3dde41ffee671d4563a900bb031c5b1faf3675f8 Mon Sep 17 00:00:00 2001
From: chao <285449594@qq.com>
Date: Fri, 14 Jun 2019 14:23:34 +0800
Subject: [PATCH] add bootstrap-tagsinput to fastadmin
---
.gitignore | 2 +-
public/assets/js/require-backend.min.js | 1262 +++++++++--------
public/assets/js/require-form.js | 18 +
.../bootstrap-tagsinput.css | 55 +
.../bootstrap-tagsinput.js | 646 +++++++++
.../bootstrap-tagsinput.min.js | 7 +
6 files changed, 1369 insertions(+), 621 deletions(-)
create mode 100644 public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.css
create mode 100644 public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.js
create mode 100644 public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.min.js
diff --git a/.gitignore b/.gitignore
index 3f2ebf8ce..2c96fdb37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@
/runtime/*
/addons/*
/application/admin/command/Install/*.lock
-/public/assets/libs/
+#/public/assets/libs/
/public/assets/addons/*
/public/uploads/*
.idea
diff --git a/public/assets/js/require-backend.min.js b/public/assets/js/require-backend.min.js
index 52bf0aaa1..4e02dc016 100644
--- a/public/assets/js/require-backend.min.js
+++ b/public/assets/js/require-backend.min.js
@@ -20,7 +20,7 @@ require.config({
}
],
//在打包压缩时将会把include中的模块合并到主文件中
- include: ['css', 'layer', 'toastr', 'fast', 'backend', 'backend-init', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs', 'selectpage'],
+ include: ['css', 'layer', 'toastr', 'fast', 'backend', 'backend-init', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs', 'selectpage', 'tags'],
paths: {
'lang': "empty:",
'form': 'require-form',
@@ -64,6 +64,7 @@ require.config({
'selectpage': '../libs/fastadmin-selectpage/selectpage',
'citypicker': '../libs/fastadmin-citypicker/dist/js/city-picker.min',
'citypicker-data': '../libs/fastadmin-citypicker/dist/js/city-picker.data',
+ 'tags': '../libs/bootstrap-tagsinput/bootstrap-tagsinput',
},
// shim依赖配置
shim: {
@@ -128,6 +129,7 @@ require.config({
// 'validator-core': ['css!../libs/nice-validator/dist/jquery.validator.css'],
'validator-lang': ['validator-core'],
// 'selectpage': ['css!../libs/fastadmin-selectpage/selectpage.css'],
+ 'tags': ['css!../libs/bootstrap-tagsinput/bootstrap-tagsinput.css'],
'citypicker': ['citypicker-data', 'css!../libs/fastadmin-citypicker/dist/css/city-picker.css']
},
baseUrl: requirejs.s.contexts._.config.config.site.cdnurl + '/assets/js/', //资源基础路径
@@ -9273,6 +9275,24 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
});
});
}
+ },
+ tags: function(form){
+ if ($(".fastadmin-tags", form).size() > 0) {
+ require(['tags'], function () {
+ $(".fastadmin-tags", form).each(function(){
+ let options = {
+ confirmKeys: [13],
+ cancelConfirmKeysOnEmpty: false
+ }
+ let num = $(this).data('num');
+ if (num > 0){
+ options.maxTags = num
+ }
+
+ $(this).tagsinput(options);
+ });
+ });
+ }
}
},
api: {
@@ -9375,6 +9395,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
events.slider(form);
events.switcher(form);
+
+ events.tags(form);
},
custom: {}
},
@@ -10590,387 +10612,387 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
return Table;
});
-// jQuery List DragSort v0.5.2
-// Website: http://dragsort.codeplex.com/
-// License: http://dragsort.codeplex.com/license
-
-(function($) {
-
- $.fn.dragsort = function(options) {
- if (options == "destroy") {
- $(this.selector).trigger("dragsort-uninit");
- return;
- }
-
- var opts = $.extend({}, $.fn.dragsort.defaults, options);
- var lists = [];
- var list = null, lastPos = null;
-
- this.each(function(i, cont) {
-
- //if list container is table, the browser automatically wraps rows in tbody if not specified so change list container to tbody so that children returns rows as user expected
- if ($(cont).is("table") && $(cont).children().size() == 1 && $(cont).children().is("tbody"))
- cont = $(cont).children().get(0);
-
- var newList = {
- draggedItem: null,
- placeHolderItem: null,
- pos: null,
- offset: null,
- offsetLimit: null,
- scroll: null,
- container: cont,
-
- init: function() {
- //set options to default values if not set
- opts.tagName = opts.tagName == "" ? ($(this.container).children().size() == 0 ? "li" : $(this.container).children().get(0).tagName.toLowerCase()) : opts.tagName;
- if (opts.itemSelector == "")
- opts.itemSelector = opts.tagName;
- if (opts.dragSelector == "")
- opts.dragSelector = opts.tagName;
- if (opts.placeHolderTemplate == "")
- opts.placeHolderTemplate = "<" + opts.tagName + "> " + opts.tagName + ">";
-
- //listidx allows reference back to correct list variable instance
- $(this.container).attr("data-listidx", i).mousedown(this.grabItem).bind("dragsort-uninit", this.uninit);
- this.styleDragHandlers(true);
- },
-
- uninit: function() {
- var list = lists[$(this).attr("data-listidx")];
- $(list.container).unbind("mousedown", list.grabItem).unbind("dragsort-uninit");
- list.styleDragHandlers(false);
- },
-
- getItems: function() {
- return $(this.container).children(opts.itemSelector);
- },
-
- styleDragHandlers: function(cursor) {
- this.getItems().map(function() { return $(this).is(opts.dragSelector) ? this : $(this).find(opts.dragSelector).get(); }).css("cursor", cursor ? "pointer" : "");
- },
-
- grabItem: function(e) {
- var list = lists[$(this).attr("data-listidx")];
- var item = $(e.target).closest("[data-listidx] > " + opts.tagName).get(0);
- var insideMoveableItem = list.getItems().filter(function() { return this == item; }).size() > 0;
-
- //if not left click or if clicked on excluded element (e.g. text box) or not a moveable list item return
- if (e.which != 1 || $(e.target).is(opts.dragSelectorExclude) || $(e.target).closest(opts.dragSelectorExclude).size() > 0 || !insideMoveableItem)
- return;
-
- //prevents selection, stops issue on Fx where dragging hyperlink doesn't work and on IE where it triggers mousemove even though mouse hasn't moved,
- //does also stop being able to click text boxes hence dragging on text boxes by default is disabled in dragSelectorExclude
- //e.preventDefault();
-
- //change cursor to move while dragging
- var dragHandle = e.target;
- while (!$(dragHandle).is(opts.dragSelector)) {
- if (dragHandle == this) return;
- dragHandle = dragHandle.parentNode;
- }
- $(dragHandle).attr("data-cursor", $(dragHandle).css("cursor"));
- $(dragHandle).css("cursor", "move");
-
- //on mousedown wait for movement of mouse before triggering dragsort script (dragStart) to allow clicking of hyperlinks to work
- var listElem = this;
- var trigger = function() {
- list.dragStart.call(listElem, e);
- $(list.container).unbind("mousemove", trigger);
- };
- $(list.container).mousemove(trigger).mouseup(function() { $(list.container).unbind("mousemove", trigger); $(dragHandle).css("cursor", $(dragHandle).attr("data-cursor")); });
- },
-
- dragStart: function(e) {
- if (list != null && list.draggedItem != null)
- list.dropItem();
-
- list = lists[$(this).attr("data-listidx")];
- list.draggedItem = $(e.target).closest("[data-listidx] > " + opts.tagName)
-
- //record current position so on dragend we know if the dragged item changed position or not, not using getItems to allow dragsort to restore dragged item to original location in relation to fixed items
- list.draggedItem.attr("data-origpos", $(this).attr("data-listidx") + "-" + $(list.container).children().index(list.draggedItem));
-
- //calculate mouse offset relative to draggedItem
- var mt = parseInt(list.draggedItem.css("marginTop"));
- var ml = parseInt(list.draggedItem.css("marginLeft"));
- list.offset = list.draggedItem.offset();
- list.offset.top = e.pageY - list.offset.top + (isNaN(mt) ? 0 : mt) - 1;
- list.offset.left = e.pageX - list.offset.left + (isNaN(ml) ? 0 : ml) - 1;
-
- //calculate box the dragged item can't be dragged outside of
- if (!opts.dragBetween) {
- var containerHeight = $(list.container).outerHeight() == 0 ? Math.max(1, Math.round(0.5 + list.getItems().size() * list.draggedItem.outerWidth() / $(list.container).outerWidth())) * list.draggedItem.outerHeight() : $(list.container).outerHeight();
- list.offsetLimit = $(list.container).offset();
- list.offsetLimit.right = list.offsetLimit.left + $(list.container).outerWidth() - list.draggedItem.outerWidth();
- list.offsetLimit.bottom = list.offsetLimit.top + containerHeight - list.draggedItem.outerHeight();
- }
-
- //create placeholder item
- var h = list.draggedItem.height();
- var w = list.draggedItem.width();
- if (opts.tagName == "tr") {
- list.draggedItem.children().each(function() { $(this).width($(this).width()); });
- list.placeHolderItem = list.draggedItem.clone().attr("data-placeholder", true);
- list.draggedItem.after(list.placeHolderItem);
- //list.placeHolderItem.children().each(function() { $(this).css({ borderWidth:0, width: $(this).width() + 1, height: $(this).height() + 1 }).html(" "); });
- list.placeHolderItem.children().each(function() { $(this).html(" "); });
- } else {
- list.draggedItem.after(opts.placeHolderTemplate);
- list.placeHolderItem = list.draggedItem.next().css({ height: h, width: w }).attr("data-placeholder", true);
- }
-
- if (opts.tagName == "td") {
- var listTable = list.draggedItem.closest("table").get(0);
- $("
").appendTo("body").children().append(list.draggedItem);
- }
-
- //style draggedItem while dragging
- var orig = list.draggedItem.attr("style");
- list.draggedItem.attr("data-origstyle", orig ? orig : "");
- list.draggedItem.css({ position: "absolute", opacity: 0.8, "z-index": 999, height: h, width: w });
-
- //auto-scroll setup
- list.scroll = { moveX: 0, moveY: 0, maxX: $(document).width() - $(window).width(), maxY: $(document).height() - $(window).height() };
- list.scroll.scrollY = window.setInterval(function() {
- if (opts.scrollContainer != window) {
- $(opts.scrollContainer).scrollTop($(opts.scrollContainer).scrollTop() + list.scroll.moveY);
- return;
- }
- var t = $(opts.scrollContainer).scrollTop();
- if (list.scroll.moveY > 0 && t < list.scroll.maxY || list.scroll.moveY < 0 && t > 0) {
- $(opts.scrollContainer).scrollTop(t + list.scroll.moveY);
- list.draggedItem.css("top", list.draggedItem.offset().top + list.scroll.moveY + 1);
- }
- }, 10);
- list.scroll.scrollX = window.setInterval(function() {
- if (opts.scrollContainer != window) {
- $(opts.scrollContainer).scrollLeft($(opts.scrollContainer).scrollLeft() + list.scroll.moveX);
- return;
- }
- var l = $(opts.scrollContainer).scrollLeft();
- if (list.scroll.moveX > 0 && l < list.scroll.maxX || list.scroll.moveX < 0 && l > 0) {
- $(opts.scrollContainer).scrollLeft(l + list.scroll.moveX);
- list.draggedItem.css("left", list.draggedItem.offset().left + list.scroll.moveX + 1);
- }
- }, 10);
-
- //misc
- $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
- list.setPos(e.pageX, e.pageY);
- $(document).bind("mousemove", list.swapItems);
- $(document).bind("mouseup", list.dropItem);
- if (opts.scrollContainer != window)
- $(window).bind("wheel", list.wheel);
- },
-
- //set position of draggedItem
- setPos: function(x, y) {
- //remove mouse offset so mouse cursor remains in same place on draggedItem instead of top left corner
- var top = y - this.offset.top;
- var left = x - this.offset.left;
-
- //limit top, left to within box draggedItem can't be dragged outside of
- if (!opts.dragBetween) {
- top = Math.min(this.offsetLimit.bottom, Math.max(top, this.offsetLimit.top));
- left = Math.min(this.offsetLimit.right, Math.max(left, this.offsetLimit.left));
- }
-
- //adjust top & left calculations to parent offset
- var parent = this.draggedItem.offsetParent().not("body").offset(); //offsetParent returns body even when it's static, if not static offset is only factoring margin
- if (parent != null) {
- top -= parent.top;
- left -= parent.left;
- }
-
- //set x or y auto-scroll amount
- if (opts.scrollContainer == window) {
- y -= $(window).scrollTop();
- x -= $(window).scrollLeft();
- y = Math.max(0, y - $(window).height() + 5) + Math.min(0, y - 5);
- x = Math.max(0, x - $(window).width() + 5) + Math.min(0, x - 5);
- } else {
- var cont = $(opts.scrollContainer);
- var offset = cont.offset();
- y = Math.max(0, y - cont.height() - offset.top) + Math.min(0, y - offset.top);
- x = Math.max(0, x - cont.width() - offset.left) + Math.min(0, x - offset.left);
- }
-
- list.scroll.moveX = x == 0 ? 0 : x * opts.scrollSpeed / Math.abs(x);
- list.scroll.moveY = y == 0 ? 0 : y * opts.scrollSpeed / Math.abs(y);
-
- //move draggedItem to new mouse cursor location
- this.draggedItem.css({ top: top, left: left });
- },
-
- //if scroll container is a div allow mouse wheel to scroll div instead of window when mouse is hovering over
- wheel: function(e) {
- if (list && opts.scrollContainer != window) {
- var cont = $(opts.scrollContainer);
- var offset = cont.offset();
- e = e.originalEvent;
- if (e.clientX > offset.left && e.clientX < offset.left + cont.width() && e.clientY > offset.top && e.clientY < offset.top + cont.height()) {
- var deltaY = (e.deltaMode == 0 ? 1 : 10) * e.deltaY;
- cont.scrollTop(cont.scrollTop() + deltaY);
- e.preventDefault();
- }
- }
- },
-
- //build a table recording all the positions of the moveable list items
- buildPositionTable: function() {
- var pos = [];
- this.getItems().not([list.draggedItem[0], list.placeHolderItem[0]]).each(function(i) {
- var loc = $(this).offset();
- loc.right = loc.left + $(this).outerWidth();
- loc.bottom = loc.top + $(this).outerHeight();
- loc.elm = this;
- pos[i] = loc;
- });
- this.pos = pos;
- },
-
- dropItem: function() {
- if (list.draggedItem == null)
- return;
-
- //list.draggedItem.attr("style", "") doesn't work on IE8 and jQuery 1.5 or lower
- //list.draggedItem.removeAttr("style") doesn't work on chrome and jQuery 1.6 (works jQuery 1.5 or lower)
- var orig = list.draggedItem.attr("data-origstyle");
- list.draggedItem.attr("style", orig);
- if (orig == "")
- list.draggedItem.removeAttr("style");
- list.draggedItem.removeAttr("data-origstyle");
-
- list.styleDragHandlers(true);
-
- list.placeHolderItem.before(list.draggedItem);
- list.placeHolderItem.remove();
-
- $("[data-droptarget], .dragSortItem").remove();
-
- window.clearInterval(list.scroll.scrollY);
- window.clearInterval(list.scroll.scrollX);
-
- //if position changed call dragEnd
- if (list.draggedItem.attr("data-origpos") != $(lists).index(list) + "-" + $(list.container).children().index(list.draggedItem))
- if (opts.dragEnd.apply(list.draggedItem) == false) { //if dragEnd returns false revert order
- var pos = list.draggedItem.attr("data-origpos").split('-');
- var nextItem = $(lists[pos[0]].container).children().not(list.draggedItem).eq(pos[1]);
- if (nextItem.size() > 0)
- nextItem.before(list.draggedItem);
- else if (pos[1] == 0) //was the only item in list
- $(lists[pos[0]].container).prepend(list.draggedItem);
- else //was the last item in list
- $(lists[pos[0]].container).append(list.draggedItem);
- }
- list.draggedItem.removeAttr("data-origpos");
-
- list.draggedItem = null;
- $(document).unbind("mousemove", list.swapItems);
- $(document).unbind("mouseup", list.dropItem);
- if (opts.scrollContainer != window)
- $(window).unbind("wheel", list.wheel);
- return false;
- },
-
- //swap the draggedItem (represented visually by placeholder) with the list item the it has been dragged on top of
- swapItems: function(e) {
- if (list.draggedItem == null)
- return false;
-
- //move draggedItem to mouse location
- list.setPos(e.pageX, e.pageY);
-
- //retrieve list and item position mouse cursor is over
- var ei = list.findPos(e.pageX, e.pageY);
- var nlist = list;
- for (var i = 0; ei == -1 && opts.dragBetween && i < lists.length; i++) {
- ei = lists[i].findPos(e.pageX, e.pageY);
- nlist = lists[i];
- }
-
- //if not over another moveable list item return
- if (ei == -1)
- return false;
-
- //save fixed items locations
- var children = function() { return $(nlist.container).children().not(nlist.draggedItem); };
- var fixed = children().not(opts.itemSelector).each(function(i) { this.idx = children().index(this); });
-
- //if moving draggedItem up or left place placeHolder before list item the dragged item is hovering over otherwise place it after
- if (lastPos == null || lastPos.top > list.draggedItem.offset().top || lastPos.left > list.draggedItem.offset().left)
- $(nlist.pos[ei].elm).before(list.placeHolderItem);
- else
- $(nlist.pos[ei].elm).after(list.placeHolderItem);
-
- //restore fixed items location
- fixed.each(function() {
- var elm = children().eq(this.idx).get(0);
- if (this != elm && children().index(this) < this.idx)
- $(this).insertAfter(elm);
- else if (this != elm)
- $(this).insertBefore(elm);
- });
-
- //misc
- $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
- lastPos = list.draggedItem.offset();
- return false;
- },
-
- //returns the index of the list item the mouse is over
- findPos: function(x, y) {
- for (var i = 0; i < this.pos.length; i++) {
- if (this.pos[i].left < x && this.pos[i].right > x && this.pos[i].top < y && this.pos[i].bottom > y)
- return i;
- }
- return -1;
- },
-
- //create drop targets which are placeholders at the end of other lists to allow dragging straight to the last position
- createDropTargets: function() {
- if (!opts.dragBetween)
- return;
-
- $(lists).each(function() {
- var ph = $(this.container).find("[data-placeholder]");
- var dt = $(this.container).find("[data-droptarget]");
- if (ph.size() > 0 && dt.size() > 0)
- dt.remove();
- else if (ph.size() == 0 && dt.size() == 0) {
- if (opts.tagName == "td")
- $(opts.placeHolderTemplate).attr("data-droptarget", true).appendTo(this.container);
- else
- //list.placeHolderItem.clone().removeAttr("data-placeholder") crashes in IE7 and jquery 1.5.1 (doesn't in jquery 1.4.2 or IE8)
- $(this.container).append(list.placeHolderItem.removeAttr("data-placeholder").clone().attr("data-droptarget", true));
-
- list.placeHolderItem.attr("data-placeholder", true);
- }
- });
- }
- };
-
- newList.init();
- lists.push(newList);
- });
-
- return this;
- };
-
- $.fn.dragsort.defaults = {
- tagName:"",
- itemSelector: "",
- dragSelector: "",
- dragSelectorExclude: "input, textarea",
- dragEnd: function() { },
- dragBetween: false,
- placeHolderTemplate: "",
- scrollContainer: window,
- scrollSpeed: 5
- };
-
-})(jQuery);
+// jQuery List DragSort v0.5.2
+// Website: http://dragsort.codeplex.com/
+// License: http://dragsort.codeplex.com/license
+
+(function($) {
+
+ $.fn.dragsort = function(options) {
+ if (options == "destroy") {
+ $(this.selector).trigger("dragsort-uninit");
+ return;
+ }
+
+ var opts = $.extend({}, $.fn.dragsort.defaults, options);
+ var lists = [];
+ var list = null, lastPos = null;
+
+ this.each(function(i, cont) {
+
+ //if list container is table, the browser automatically wraps rows in tbody if not specified so change list container to tbody so that children returns rows as user expected
+ if ($(cont).is("table") && $(cont).children().size() == 1 && $(cont).children().is("tbody"))
+ cont = $(cont).children().get(0);
+
+ var newList = {
+ draggedItem: null,
+ placeHolderItem: null,
+ pos: null,
+ offset: null,
+ offsetLimit: null,
+ scroll: null,
+ container: cont,
+
+ init: function() {
+ //set options to default values if not set
+ opts.tagName = opts.tagName == "" ? ($(this.container).children().size() == 0 ? "li" : $(this.container).children().get(0).tagName.toLowerCase()) : opts.tagName;
+ if (opts.itemSelector == "")
+ opts.itemSelector = opts.tagName;
+ if (opts.dragSelector == "")
+ opts.dragSelector = opts.tagName;
+ if (opts.placeHolderTemplate == "")
+ opts.placeHolderTemplate = "<" + opts.tagName + "> " + opts.tagName + ">";
+
+ //listidx allows reference back to correct list variable instance
+ $(this.container).attr("data-listidx", i).mousedown(this.grabItem).bind("dragsort-uninit", this.uninit);
+ this.styleDragHandlers(true);
+ },
+
+ uninit: function() {
+ var list = lists[$(this).attr("data-listidx")];
+ $(list.container).unbind("mousedown", list.grabItem).unbind("dragsort-uninit");
+ list.styleDragHandlers(false);
+ },
+
+ getItems: function() {
+ return $(this.container).children(opts.itemSelector);
+ },
+
+ styleDragHandlers: function(cursor) {
+ this.getItems().map(function() { return $(this).is(opts.dragSelector) ? this : $(this).find(opts.dragSelector).get(); }).css("cursor", cursor ? "pointer" : "");
+ },
+
+ grabItem: function(e) {
+ var list = lists[$(this).attr("data-listidx")];
+ var item = $(e.target).closest("[data-listidx] > " + opts.tagName).get(0);
+ var insideMoveableItem = list.getItems().filter(function() { return this == item; }).size() > 0;
+
+ //if not left click or if clicked on excluded element (e.g. text box) or not a moveable list item return
+ if (e.which != 1 || $(e.target).is(opts.dragSelectorExclude) || $(e.target).closest(opts.dragSelectorExclude).size() > 0 || !insideMoveableItem)
+ return;
+
+ //prevents selection, stops issue on Fx where dragging hyperlink doesn't work and on IE where it triggers mousemove even though mouse hasn't moved,
+ //does also stop being able to click text boxes hence dragging on text boxes by default is disabled in dragSelectorExclude
+ //e.preventDefault();
+
+ //change cursor to move while dragging
+ var dragHandle = e.target;
+ while (!$(dragHandle).is(opts.dragSelector)) {
+ if (dragHandle == this) return;
+ dragHandle = dragHandle.parentNode;
+ }
+ $(dragHandle).attr("data-cursor", $(dragHandle).css("cursor"));
+ $(dragHandle).css("cursor", "move");
+
+ //on mousedown wait for movement of mouse before triggering dragsort script (dragStart) to allow clicking of hyperlinks to work
+ var listElem = this;
+ var trigger = function() {
+ list.dragStart.call(listElem, e);
+ $(list.container).unbind("mousemove", trigger);
+ };
+ $(list.container).mousemove(trigger).mouseup(function() { $(list.container).unbind("mousemove", trigger); $(dragHandle).css("cursor", $(dragHandle).attr("data-cursor")); });
+ },
+
+ dragStart: function(e) {
+ if (list != null && list.draggedItem != null)
+ list.dropItem();
+
+ list = lists[$(this).attr("data-listidx")];
+ list.draggedItem = $(e.target).closest("[data-listidx] > " + opts.tagName)
+
+ //record current position so on dragend we know if the dragged item changed position or not, not using getItems to allow dragsort to restore dragged item to original location in relation to fixed items
+ list.draggedItem.attr("data-origpos", $(this).attr("data-listidx") + "-" + $(list.container).children().index(list.draggedItem));
+
+ //calculate mouse offset relative to draggedItem
+ var mt = parseInt(list.draggedItem.css("marginTop"));
+ var ml = parseInt(list.draggedItem.css("marginLeft"));
+ list.offset = list.draggedItem.offset();
+ list.offset.top = e.pageY - list.offset.top + (isNaN(mt) ? 0 : mt) - 1;
+ list.offset.left = e.pageX - list.offset.left + (isNaN(ml) ? 0 : ml) - 1;
+
+ //calculate box the dragged item can't be dragged outside of
+ if (!opts.dragBetween) {
+ var containerHeight = $(list.container).outerHeight() == 0 ? Math.max(1, Math.round(0.5 + list.getItems().size() * list.draggedItem.outerWidth() / $(list.container).outerWidth())) * list.draggedItem.outerHeight() : $(list.container).outerHeight();
+ list.offsetLimit = $(list.container).offset();
+ list.offsetLimit.right = list.offsetLimit.left + $(list.container).outerWidth() - list.draggedItem.outerWidth();
+ list.offsetLimit.bottom = list.offsetLimit.top + containerHeight - list.draggedItem.outerHeight();
+ }
+
+ //create placeholder item
+ var h = list.draggedItem.height();
+ var w = list.draggedItem.width();
+ if (opts.tagName == "tr") {
+ list.draggedItem.children().each(function() { $(this).width($(this).width()); });
+ list.placeHolderItem = list.draggedItem.clone().attr("data-placeholder", true);
+ list.draggedItem.after(list.placeHolderItem);
+ //list.placeHolderItem.children().each(function() { $(this).css({ borderWidth:0, width: $(this).width() + 1, height: $(this).height() + 1 }).html(" "); });
+ list.placeHolderItem.children().each(function() { $(this).html(" "); });
+ } else {
+ list.draggedItem.after(opts.placeHolderTemplate);
+ list.placeHolderItem = list.draggedItem.next().css({ height: h, width: w }).attr("data-placeholder", true);
+ }
+
+ if (opts.tagName == "td") {
+ var listTable = list.draggedItem.closest("table").get(0);
+ $("").appendTo("body").children().append(list.draggedItem);
+ }
+
+ //style draggedItem while dragging
+ var orig = list.draggedItem.attr("style");
+ list.draggedItem.attr("data-origstyle", orig ? orig : "");
+ list.draggedItem.css({ position: "absolute", opacity: 0.8, "z-index": 999, height: h, width: w });
+
+ //auto-scroll setup
+ list.scroll = { moveX: 0, moveY: 0, maxX: $(document).width() - $(window).width(), maxY: $(document).height() - $(window).height() };
+ list.scroll.scrollY = window.setInterval(function() {
+ if (opts.scrollContainer != window) {
+ $(opts.scrollContainer).scrollTop($(opts.scrollContainer).scrollTop() + list.scroll.moveY);
+ return;
+ }
+ var t = $(opts.scrollContainer).scrollTop();
+ if (list.scroll.moveY > 0 && t < list.scroll.maxY || list.scroll.moveY < 0 && t > 0) {
+ $(opts.scrollContainer).scrollTop(t + list.scroll.moveY);
+ list.draggedItem.css("top", list.draggedItem.offset().top + list.scroll.moveY + 1);
+ }
+ }, 10);
+ list.scroll.scrollX = window.setInterval(function() {
+ if (opts.scrollContainer != window) {
+ $(opts.scrollContainer).scrollLeft($(opts.scrollContainer).scrollLeft() + list.scroll.moveX);
+ return;
+ }
+ var l = $(opts.scrollContainer).scrollLeft();
+ if (list.scroll.moveX > 0 && l < list.scroll.maxX || list.scroll.moveX < 0 && l > 0) {
+ $(opts.scrollContainer).scrollLeft(l + list.scroll.moveX);
+ list.draggedItem.css("left", list.draggedItem.offset().left + list.scroll.moveX + 1);
+ }
+ }, 10);
+
+ //misc
+ $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
+ list.setPos(e.pageX, e.pageY);
+ $(document).bind("mousemove", list.swapItems);
+ $(document).bind("mouseup", list.dropItem);
+ if (opts.scrollContainer != window)
+ $(window).bind("wheel", list.wheel);
+ },
+
+ //set position of draggedItem
+ setPos: function(x, y) {
+ //remove mouse offset so mouse cursor remains in same place on draggedItem instead of top left corner
+ var top = y - this.offset.top;
+ var left = x - this.offset.left;
+
+ //limit top, left to within box draggedItem can't be dragged outside of
+ if (!opts.dragBetween) {
+ top = Math.min(this.offsetLimit.bottom, Math.max(top, this.offsetLimit.top));
+ left = Math.min(this.offsetLimit.right, Math.max(left, this.offsetLimit.left));
+ }
+
+ //adjust top & left calculations to parent offset
+ var parent = this.draggedItem.offsetParent().not("body").offset(); //offsetParent returns body even when it's static, if not static offset is only factoring margin
+ if (parent != null) {
+ top -= parent.top;
+ left -= parent.left;
+ }
+
+ //set x or y auto-scroll amount
+ if (opts.scrollContainer == window) {
+ y -= $(window).scrollTop();
+ x -= $(window).scrollLeft();
+ y = Math.max(0, y - $(window).height() + 5) + Math.min(0, y - 5);
+ x = Math.max(0, x - $(window).width() + 5) + Math.min(0, x - 5);
+ } else {
+ var cont = $(opts.scrollContainer);
+ var offset = cont.offset();
+ y = Math.max(0, y - cont.height() - offset.top) + Math.min(0, y - offset.top);
+ x = Math.max(0, x - cont.width() - offset.left) + Math.min(0, x - offset.left);
+ }
+
+ list.scroll.moveX = x == 0 ? 0 : x * opts.scrollSpeed / Math.abs(x);
+ list.scroll.moveY = y == 0 ? 0 : y * opts.scrollSpeed / Math.abs(y);
+
+ //move draggedItem to new mouse cursor location
+ this.draggedItem.css({ top: top, left: left });
+ },
+
+ //if scroll container is a div allow mouse wheel to scroll div instead of window when mouse is hovering over
+ wheel: function(e) {
+ if (list && opts.scrollContainer != window) {
+ var cont = $(opts.scrollContainer);
+ var offset = cont.offset();
+ e = e.originalEvent;
+ if (e.clientX > offset.left && e.clientX < offset.left + cont.width() && e.clientY > offset.top && e.clientY < offset.top + cont.height()) {
+ var deltaY = (e.deltaMode == 0 ? 1 : 10) * e.deltaY;
+ cont.scrollTop(cont.scrollTop() + deltaY);
+ e.preventDefault();
+ }
+ }
+ },
+
+ //build a table recording all the positions of the moveable list items
+ buildPositionTable: function() {
+ var pos = [];
+ this.getItems().not([list.draggedItem[0], list.placeHolderItem[0]]).each(function(i) {
+ var loc = $(this).offset();
+ loc.right = loc.left + $(this).outerWidth();
+ loc.bottom = loc.top + $(this).outerHeight();
+ loc.elm = this;
+ pos[i] = loc;
+ });
+ this.pos = pos;
+ },
+
+ dropItem: function() {
+ if (list.draggedItem == null)
+ return;
+
+ //list.draggedItem.attr("style", "") doesn't work on IE8 and jQuery 1.5 or lower
+ //list.draggedItem.removeAttr("style") doesn't work on chrome and jQuery 1.6 (works jQuery 1.5 or lower)
+ var orig = list.draggedItem.attr("data-origstyle");
+ list.draggedItem.attr("style", orig);
+ if (orig == "")
+ list.draggedItem.removeAttr("style");
+ list.draggedItem.removeAttr("data-origstyle");
+
+ list.styleDragHandlers(true);
+
+ list.placeHolderItem.before(list.draggedItem);
+ list.placeHolderItem.remove();
+
+ $("[data-droptarget], .dragSortItem").remove();
+
+ window.clearInterval(list.scroll.scrollY);
+ window.clearInterval(list.scroll.scrollX);
+
+ //if position changed call dragEnd
+ if (list.draggedItem.attr("data-origpos") != $(lists).index(list) + "-" + $(list.container).children().index(list.draggedItem))
+ if (opts.dragEnd.apply(list.draggedItem) == false) { //if dragEnd returns false revert order
+ var pos = list.draggedItem.attr("data-origpos").split('-');
+ var nextItem = $(lists[pos[0]].container).children().not(list.draggedItem).eq(pos[1]);
+ if (nextItem.size() > 0)
+ nextItem.before(list.draggedItem);
+ else if (pos[1] == 0) //was the only item in list
+ $(lists[pos[0]].container).prepend(list.draggedItem);
+ else //was the last item in list
+ $(lists[pos[0]].container).append(list.draggedItem);
+ }
+ list.draggedItem.removeAttr("data-origpos");
+
+ list.draggedItem = null;
+ $(document).unbind("mousemove", list.swapItems);
+ $(document).unbind("mouseup", list.dropItem);
+ if (opts.scrollContainer != window)
+ $(window).unbind("wheel", list.wheel);
+ return false;
+ },
+
+ //swap the draggedItem (represented visually by placeholder) with the list item the it has been dragged on top of
+ swapItems: function(e) {
+ if (list.draggedItem == null)
+ return false;
+
+ //move draggedItem to mouse location
+ list.setPos(e.pageX, e.pageY);
+
+ //retrieve list and item position mouse cursor is over
+ var ei = list.findPos(e.pageX, e.pageY);
+ var nlist = list;
+ for (var i = 0; ei == -1 && opts.dragBetween && i < lists.length; i++) {
+ ei = lists[i].findPos(e.pageX, e.pageY);
+ nlist = lists[i];
+ }
+
+ //if not over another moveable list item return
+ if (ei == -1)
+ return false;
+
+ //save fixed items locations
+ var children = function() { return $(nlist.container).children().not(nlist.draggedItem); };
+ var fixed = children().not(opts.itemSelector).each(function(i) { this.idx = children().index(this); });
+
+ //if moving draggedItem up or left place placeHolder before list item the dragged item is hovering over otherwise place it after
+ if (lastPos == null || lastPos.top > list.draggedItem.offset().top || lastPos.left > list.draggedItem.offset().left)
+ $(nlist.pos[ei].elm).before(list.placeHolderItem);
+ else
+ $(nlist.pos[ei].elm).after(list.placeHolderItem);
+
+ //restore fixed items location
+ fixed.each(function() {
+ var elm = children().eq(this.idx).get(0);
+ if (this != elm && children().index(this) < this.idx)
+ $(this).insertAfter(elm);
+ else if (this != elm)
+ $(this).insertBefore(elm);
+ });
+
+ //misc
+ $(lists).each(function(i, l) { l.createDropTargets(); l.buildPositionTable(); });
+ lastPos = list.draggedItem.offset();
+ return false;
+ },
+
+ //returns the index of the list item the mouse is over
+ findPos: function(x, y) {
+ for (var i = 0; i < this.pos.length; i++) {
+ if (this.pos[i].left < x && this.pos[i].right > x && this.pos[i].top < y && this.pos[i].bottom > y)
+ return i;
+ }
+ return -1;
+ },
+
+ //create drop targets which are placeholders at the end of other lists to allow dragging straight to the last position
+ createDropTargets: function() {
+ if (!opts.dragBetween)
+ return;
+
+ $(lists).each(function() {
+ var ph = $(this.container).find("[data-placeholder]");
+ var dt = $(this.container).find("[data-droptarget]");
+ if (ph.size() > 0 && dt.size() > 0)
+ dt.remove();
+ else if (ph.size() == 0 && dt.size() == 0) {
+ if (opts.tagName == "td")
+ $(opts.placeHolderTemplate).attr("data-droptarget", true).appendTo(this.container);
+ else
+ //list.placeHolderItem.clone().removeAttr("data-placeholder") crashes in IE7 and jquery 1.5.1 (doesn't in jquery 1.4.2 or IE8)
+ $(this.container).append(list.placeHolderItem.removeAttr("data-placeholder").clone().attr("data-droptarget", true));
+
+ list.placeHolderItem.attr("data-placeholder", true);
+ }
+ });
+ }
+ };
+
+ newList.init();
+ lists.push(newList);
+ });
+
+ return this;
+ };
+
+ $.fn.dragsort.defaults = {
+ tagName:"",
+ itemSelector: "",
+ dragSelector: "",
+ dragSelectorExclude: "input, textarea",
+ dragEnd: function() { },
+ dragBetween: false,
+ placeHolderTemplate: "",
+ scrollContainer: window,
+ scrollSpeed: 5
+ };
+
+})(jQuery);
define("dragsort", function(){});
@@ -10990,244 +11012,244 @@ define("drag", function(){});
;(function(d){d.fn.drop=function(i,e,h){var g=typeof i=="string"?i:"",f=d.isFunction(i)?i:d.isFunction(e)?e:null;if(g.indexOf("drop")!==0){g="drop"+g}h=(i==f?e:h)||{};return f?this.bind(g,h,f):this.trigger(g)};d.drop=function(e){e=e||{};b.multi=e.multi===true?Infinity:e.multi===false?1:!isNaN(e.multi)?e.multi:b.multi;b.delay=e.delay||b.delay;b.tolerance=d.isFunction(e.tolerance)?e.tolerance:e.tolerance===null?null:b.tolerance;b.mode=e.mode||b.mode||"intersect"};var c=d.event,a=c.special,b=d.event.special.drop={multi:1,delay:20,mode:"overlap",targets:[],datakey:"dropdata",noBubble:true,add:function(f){var e=d.data(this,b.datakey);e.related+=1},remove:function(){d.data(this,b.datakey).related-=1},setup:function(){if(d.data(this,b.datakey)){return}var e={related:0,active:[],anyactive:0,winner:0,location:{}};d.data(this,b.datakey,e);b.targets.push(this);return false},teardown:function(){var f=d.data(this,b.datakey)||{};if(f.related){return}d.removeData(this,b.datakey);var e=this;b.targets=d.grep(b.targets,function(g){return(g!==e)})},handler:function(g,e){var f,h;if(!e){return}switch(g.type){case"mousedown":case"touchstart":h=d(b.targets);if(typeof e.drop=="string"){h=h.filter(e.drop)}h.each(function(){var i=d.data(this,b.datakey);i.active=[];i.anyactive=0;i.winner=0});e.droppable=h;a.drag.hijack(g,"dropinit",e);break;case"mousemove":case"touchmove":b.event=g;if(!b.timer){b.tolerate(e)}break;case"mouseup":case"touchend":b.timer=clearTimeout(b.timer);if(e.propagates){a.drag.hijack(g,"drop",e);a.drag.hijack(g,"dropend",e)}break}},locate:function(k,h){var l=d.data(k,b.datakey),g=d(k),i=g.offset()||{},e=g.outerHeight(),j=g.outerWidth(),f={elem:k,width:j,height:e,top:i.top,left:i.left,right:i.left+j,bottom:i.top+e};if(l){l.location=f;l.index=h;l.elem=k}return f},contains:function(e,f){return((f[0]||f.left)>=e.left&&(f[0]||f.right)<=e.right&&(f[1]||f.top)>=e.top&&(f[1]||f.bottom)<=e.bottom)},modes:{intersect:function(f,e,g){return this.contains(g,[f.pageX,f.pageY])?1000000000:this.modes.overlap.apply(this,arguments)},overlap:function(f,e,g){return Math.max(0,Math.min(g.bottom,e.bottom)-Math.max(g.top,e.top))*Math.max(0,Math.min(g.right,e.right)-Math.max(g.left,e.left))},fit:function(f,e,g){return this.contains(g,e)?1:0},middle:function(f,e,g){return this.contains(g,[e.left+e.width*0.5,e.top+e.height*0.5])?1:0}},sort:function(f,e){return(e.winner-f.winner)||(f.index-e.index)},tolerate:function(q){var k,e,n,j,l,m,g,p=0,f,h=q.interactions.length,r=[b.event.pageX,b.event.pageY],o=b.tolerance||b.modes[b.mode];do{if(f=q.interactions[p]){if(!f){return}f.drop=[];l=[];m=f.droppable.length;if(o){n=b.locate(f.proxy)}k=0;do{if(g=f.droppable[k]){j=d.data(g,b.datakey);e=j.location;if(!e){continue}j.winner=o?o.call(b,b.event,n,e):b.contains(e,r)?1:0;l.push(j)}}while(++k -1 ? "&" : "?") + "ref=addtabs") : url;
- try {
- window.history.pushState(state, title, pushurl);
- } catch (e) {
-
- }
- }
- $(this).data("pushstate", null);
- _add.call(this, {
- id: id,
- title: $(this).attr('title') ? $(this).attr('title') : $(this).html(),
- content: content,
- url: url,
- ajax: ajax
- });
- }
- });
-
- navobj.on('click', '.close-tab', function () {
- var id = $(this).prev("a").attr("aria-controls");
- _close(id);
- return false;
- });
- navobj.on('dblclick', 'li[role=presentation]', function () {
- $(this).find(".close-tab").trigger("click");
- });
- navobj.on('click', 'li[role=presentation]', function () {
- $("a[addtabs=" + $("a", this).attr("node-id") + "]").trigger("click");
- });
-
- $(window).resize(function () {
- if (typeof options.nav === 'object') {
- var siblingsWidth = 0;
- navobj.siblings().each(function () {
- siblingsWidth += $(this).outerWidth();
- });
- navobj.width(navobj.parent().width() - siblingsWidth);
- } else {
- $("#nav").width($("#header").find("> .navbar").width() - $(".sidebar-toggle").outerWidth() - $(".navbar-custom-menu").outerWidth() - 20);
- }
- _drop();
- });
-
- var _add = function (opts) {
- var id, tabid, conid, url;
- id = opts.id;
- tabid = 'tab_' + opts.id;
- conid = 'con_' + opts.id;
- url = opts.url;
- url += (opts.url.indexOf("?") > -1 ? "&addtabs=1" : "?addtabs=1");
-
- var tabitem = $('#' + tabid, navobj);
- var conitem = $('#' + conid, tabobj);
-
- navobj.find("[role='presentation']").removeClass('active');
- tabobj.find("[role='tabpanel']").removeClass('active');
-
- //如果TAB不存在,创建一个新的TAB
- if (tabitem.size() === 0) {
- //创建新TAB的title
- tabitem = $('' + opts.title + '');
- //是否允许关闭
- if (options.close && $("li", navobj).size() > 0) {
- tabitem.append(' ');
- }
- if (conitem.size() === 0) {
- //创建新TAB的内容
- conitem = $('');
- //是否指定TAB内容
- if (opts.content) {
- conitem.append(opts.content);
- } else if (options.iframeUse && !opts.ajax) {//没有内容,使用IFRAME打开链接
- var height = options.iframeHeight;
- conitem.append('');
- } else {
- $.get(url, function (data) {
- conitem.append(data);
- });
- }
- tabobj.append(conitem);
- }
- //加入TABS
- if ($('.tabdrop li', navobj).size() > 0) {
- $('.tabdrop ul', navobj).append(tabitem);
- } else {
- navobj.append(tabitem);
- }
- } else {
- //强制刷新iframe
- if (options.iframeForceRefresh) {
- $("#" + conid + " iframe").attr('src', function (i, val) {
- return val;
- });
- } else if (options.iframeForceRefreshTable) {
- try {
- //检测iframe中是否存在刷新按钮
- if ($("#" + conid + " iframe").contents().find(".btn-refresh").size() > 0) {
- $("#" + conid + " iframe")[0].contentWindow.$(".btn-refresh").trigger("click");
- }
- } catch (e) {
-
- }
- }
- }
- localStorage.setItem("addtabs", $(this).prop('outerHTML'));
- //激活TAB
- tabitem.addClass('active');
- conitem.addClass("active");
- _drop();
- };
-
- var _close = function (id) {
- var tabid = 'tab_' + id;
- var conid = 'con_' + id;
- var tabitem = $('#' + tabid, navobj);
- var conitem = $('#' + conid, tabobj);
- //如果关闭的是当前激活的TAB,激活他的前一个TAB
- if (obj.find("li.active").not('.tabdrop').attr('id') === tabid) {
- var prev = tabitem.prev().not(".tabdrop");
- var next = tabitem.next().not(".tabdrop");
- if (prev.size() > 0) {
- prev.find('a').trigger("click");
- } else if (next.size() > 0) {
- next.find('a').trigger("click");
- } else {
- $(">li:not(.tabdrop):last > a", navobj).trigger('click');
- }
- }
- //关闭TAB
- tabitem.remove();
- conitem.remove();
- _drop();
- options.callback();
- };
-
- var _drop = function () {
- navobj.refreshAddtabs();
- };
- };
- //刷新Addtabs
- $.fn.refreshAddtabs = function () {
- var navobj = $(this);
- var dropdown = $(".tabdrop", navobj);
- if (dropdown.size() === 0) {
- dropdown = $('' +
- '' +
- ' ');
- dropdown.prependTo(navobj);
- }
-
- //检测是否有下拉样式
- if (navobj.parent().is('.tabs-below')) {
- dropdown.addClass('dropup');
- }
-
- var collection = 0;
- var maxwidth = navobj.width() - 65;
-
- var liwidth = 0;
- //检查超过一行的标签页
- var litabs = navobj.append(dropdown.find('li')).find('>li').not('.tabdrop');
- var totalwidth = 0;
- litabs.each(function () {
- totalwidth += $(this).outerWidth(true);
- });
- if (navobj.width() < totalwidth) {
- litabs.each(function () {
- liwidth += $(this).outerWidth(true);
- if (liwidth > maxwidth) {
- dropdown.find('ul').append($(this));
- collection++;
- }
- });
- if (collection > 0) {
- dropdown.removeClass('hide');
- if (dropdown.find('.active').length === 1) {
- dropdown.addClass('active');
- } else {
- dropdown.removeClass('active');
- }
- }
- } else {
- dropdown.addClass('hide');
- }
-
- };
-})(jQuery);
+/**
+ * http://git.oschina.net/hbbcs/bootStrap-addTabs
+ * Created by joe on 2015-12-19.
+ * Modified by Karson
+ */
+
+(function ($) {
+
+ $.fn.addtabs = function (options) {
+ var obj = $(this);
+ options = $.extend({
+ content: '', //直接指定所有页面TABS内容
+ close: true, //是否可以关闭
+ monitor: 'body', //监视的区域
+ nav: '.nav-addtabs',
+ tab: '.tab-addtabs',
+ iframeUse: true, //使用iframe还是ajax
+ iframeHeight: $(window).height() - 50, //固定TAB中IFRAME高度,根据需要自己修改
+ iframeForceRefresh: false, //点击后强制加载对应的iframe
+ iframeForceRefreshTable: false, //点击后强制刷新对应的iframe中的table
+ callback: function () {
+ //关闭后回调函数
+ }
+ }, options || {});
+ var navobj = $(options.nav);
+ var tabobj = $(options.tab);
+ if (history.pushState) {
+ //浏览器前进后退事件
+ $(window).on("popstate", function (e) {
+ var state = e.originalEvent.state;
+ if (state) {
+ $("a[addtabs=" + state.id + "]", options.monitor).data("pushstate", true).trigger("click");
+ }
+ });
+ }
+ $(options.monitor).on('click', '[addtabs]', function (e) {
+ if ($(this).attr('url').indexOf("javascript:") !== 0) {
+ if ($(this).is("a")) {
+ e.preventDefault();
+ }
+ var id = $(this).attr('addtabs');
+ var title = $(this).attr('title') ? $(this).attr('title') : $.trim($(this).text());
+ var url = $(this).attr('url');
+ var content = options.content ? options.content : $(this).attr('content');
+ var ajax = $(this).attr('ajax') === '1' || $(this).attr('ajax') === 'true';
+ var state = ({
+ url: url, title: title, id: id, content: content, ajax: ajax
+ });
+
+ document.title = title;
+ if (history.pushState && !$(this).data("pushstate")) {
+ var pushurl = url.indexOf("ref=addtabs") === -1 ? (url + (url.indexOf("?") > -1 ? "&" : "?") + "ref=addtabs") : url;
+ try {
+ window.history.pushState(state, title, pushurl);
+ } catch (e) {
+
+ }
+ }
+ $(this).data("pushstate", null);
+ _add.call(this, {
+ id: id,
+ title: $(this).attr('title') ? $(this).attr('title') : $(this).html(),
+ content: content,
+ url: url,
+ ajax: ajax
+ });
+ }
+ });
+
+ navobj.on('click', '.close-tab', function () {
+ var id = $(this).prev("a").attr("aria-controls");
+ _close(id);
+ return false;
+ });
+ navobj.on('dblclick', 'li[role=presentation]', function () {
+ $(this).find(".close-tab").trigger("click");
+ });
+ navobj.on('click', 'li[role=presentation]', function () {
+ $("a[addtabs=" + $("a", this).attr("node-id") + "]").trigger("click");
+ });
+
+ $(window).resize(function () {
+ if (typeof options.nav === 'object') {
+ var siblingsWidth = 0;
+ navobj.siblings().each(function () {
+ siblingsWidth += $(this).outerWidth();
+ });
+ navobj.width(navobj.parent().width() - siblingsWidth);
+ } else {
+ $("#nav").width($("#header").find("> .navbar").width() - $(".sidebar-toggle").outerWidth() - $(".navbar-custom-menu").outerWidth() - 20);
+ }
+ _drop();
+ });
+
+ var _add = function (opts) {
+ var id, tabid, conid, url;
+ id = opts.id;
+ tabid = 'tab_' + opts.id;
+ conid = 'con_' + opts.id;
+ url = opts.url;
+ url += (opts.url.indexOf("?") > -1 ? "&addtabs=1" : "?addtabs=1");
+
+ var tabitem = $('#' + tabid, navobj);
+ var conitem = $('#' + conid, tabobj);
+
+ navobj.find("[role='presentation']").removeClass('active');
+ tabobj.find("[role='tabpanel']").removeClass('active');
+
+ //如果TAB不存在,创建一个新的TAB
+ if (tabitem.size() === 0) {
+ //创建新TAB的title
+ tabitem = $('' + opts.title + '');
+ //是否允许关闭
+ if (options.close && $("li", navobj).size() > 0) {
+ tabitem.append(' ');
+ }
+ if (conitem.size() === 0) {
+ //创建新TAB的内容
+ conitem = $('');
+ //是否指定TAB内容
+ if (opts.content) {
+ conitem.append(opts.content);
+ } else if (options.iframeUse && !opts.ajax) {//没有内容,使用IFRAME打开链接
+ var height = options.iframeHeight;
+ conitem.append('');
+ } else {
+ $.get(url, function (data) {
+ conitem.append(data);
+ });
+ }
+ tabobj.append(conitem);
+ }
+ //加入TABS
+ if ($('.tabdrop li', navobj).size() > 0) {
+ $('.tabdrop ul', navobj).append(tabitem);
+ } else {
+ navobj.append(tabitem);
+ }
+ } else {
+ //强制刷新iframe
+ if (options.iframeForceRefresh) {
+ $("#" + conid + " iframe").attr('src', function (i, val) {
+ return val;
+ });
+ } else if (options.iframeForceRefreshTable) {
+ try {
+ //检测iframe中是否存在刷新按钮
+ if ($("#" + conid + " iframe").contents().find(".btn-refresh").size() > 0) {
+ $("#" + conid + " iframe")[0].contentWindow.$(".btn-refresh").trigger("click");
+ }
+ } catch (e) {
+
+ }
+ }
+ }
+ localStorage.setItem("addtabs", $(this).prop('outerHTML'));
+ //激活TAB
+ tabitem.addClass('active');
+ conitem.addClass("active");
+ _drop();
+ };
+
+ var _close = function (id) {
+ var tabid = 'tab_' + id;
+ var conid = 'con_' + id;
+ var tabitem = $('#' + tabid, navobj);
+ var conitem = $('#' + conid, tabobj);
+ //如果关闭的是当前激活的TAB,激活他的前一个TAB
+ if (obj.find("li.active").not('.tabdrop').attr('id') === tabid) {
+ var prev = tabitem.prev().not(".tabdrop");
+ var next = tabitem.next().not(".tabdrop");
+ if (prev.size() > 0) {
+ prev.find('a').trigger("click");
+ } else if (next.size() > 0) {
+ next.find('a').trigger("click");
+ } else {
+ $(">li:not(.tabdrop):last > a", navobj).trigger('click');
+ }
+ }
+ //关闭TAB
+ tabitem.remove();
+ conitem.remove();
+ _drop();
+ options.callback();
+ };
+
+ var _drop = function () {
+ navobj.refreshAddtabs();
+ };
+ };
+ //刷新Addtabs
+ $.fn.refreshAddtabs = function () {
+ var navobj = $(this);
+ var dropdown = $(".tabdrop", navobj);
+ if (dropdown.size() === 0) {
+ dropdown = $('' +
+ '' +
+ ' ');
+ dropdown.prependTo(navobj);
+ }
+
+ //检测是否有下拉样式
+ if (navobj.parent().is('.tabs-below')) {
+ dropdown.addClass('dropup');
+ }
+
+ var collection = 0;
+ var maxwidth = navobj.width() - 65;
+
+ var liwidth = 0;
+ //检查超过一行的标签页
+ var litabs = navobj.append(dropdown.find('li')).find('>li').not('.tabdrop');
+ var totalwidth = 0;
+ litabs.each(function () {
+ totalwidth += $(this).outerWidth(true);
+ });
+ if (navobj.width() < totalwidth) {
+ litabs.each(function () {
+ liwidth += $(this).outerWidth(true);
+ if (liwidth > maxwidth) {
+ dropdown.find('ul').append($(this));
+ collection++;
+ }
+ });
+ if (collection > 0) {
+ dropdown.removeClass('hide');
+ if (dropdown.find('.active').length === 1) {
+ dropdown.addClass('active');
+ } else {
+ dropdown.removeClass('active');
+ }
+ }
+ } else {
+ dropdown.addClass('hide');
+ }
+
+ };
+})(jQuery);
define("addtabs", function(){});
diff --git a/public/assets/js/require-form.js b/public/assets/js/require-form.js
index 1ef68bf13..b4d71208d 100755
--- a/public/assets/js/require-form.js
+++ b/public/assets/js/require-form.js
@@ -392,6 +392,24 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
});
});
}
+ },
+ tags: function(form){
+ if ($(".fastadmin-tags", form).size() > 0) {
+ require(['tags'], function () {
+ $(".fastadmin-tags", form).each(function(){
+ let options = {
+ confirmKeys: [13],
+ cancelConfirmKeysOnEmpty: false
+ }
+ let num = $(this).data('num');
+ if (num > 0){
+ options.maxTags = num
+ }
+
+ $(this).tagsinput(options);
+ });
+ });
+ }
}
},
api: {
diff --git a/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.css b/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.css
new file mode 100644
index 000000000..b31f01c77
--- /dev/null
+++ b/public/assets/libs/bootstrap-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/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.js b/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.js
new file mode 100644
index 000000000..2b403f779
--- /dev/null
+++ b/public/assets/libs/bootstrap-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 if item represents a value not present in one of the 's options
+ if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]',self.$element)[0]) {
+ var $option = $('');
+ $option.data('item', item);
+ $option.attr('value', itemValue);
+ self.$element.append($option);
+ }
+
+ if (!dontPushVal)
+ self.pushVal();
+
+ // Add class when reached maxTags
+ if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
+ self.$container.addClass('bootstrap-tagsinput-max');
+
+ self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
+ },
+
+ /**
+ * Removes the given item. Pass true to dontPushVal to prevent updating the
+ * elements val()
+ */
+ remove: function(item, dontPushVal, options) {
+ var self = this;
+
+ if (self.objectItems) {
+ if (typeof item === "object")
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
+ else
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
+
+ item = item[item.length-1];
+ }
+
+ if (item) {
+ var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
+ self.$element.trigger(beforeItemRemoveEvent);
+ if (beforeItemRemoveEvent.cancel)
+ return;
+
+ $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
+ $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
+ if($.inArray(item, self.itemsArray) !== -1)
+ self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
+ }
+
+ if (!dontPushVal)
+ self.pushVal();
+
+ // Remove class when reached maxTags
+ if (self.options.maxTags > self.itemsArray.length)
+ self.$container.removeClass('bootstrap-tagsinput-max');
+
+ self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
+ },
+
+ /**
+ * Removes all items
+ */
+ removeAll: function() {
+ var self = this;
+
+ $('.tag', self.$container).remove();
+ $('option', self.$element).remove();
+
+ while(self.itemsArray.length > 0)
+ self.itemsArray.pop();
+
+ self.pushVal();
+ },
+
+ /**
+ * Refreshes the tags so they match the text/value of their corresponding
+ * item.
+ */
+ refresh: function() {
+ var self = this;
+ $('.tag', self.$container).each(function() {
+ var $tag = $(this),
+ item = $tag.data('item'),
+ itemValue = self.options.itemValue(item),
+ itemText = self.options.itemText(item),
+ tagClass = self.options.tagClass(item);
+
+ // Update tag's class and inner text
+ $tag.attr('class', null);
+ $tag.addClass('tag ' + htmlEncode(tagClass));
+ $tag.contents().filter(function() {
+ return this.nodeType == 3;
+ })[0].nodeValue = htmlEncode(itemText);
+
+ if (self.isSelect) {
+ var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
+ option.attr('value', itemValue);
+ }
+ });
+ },
+
+ /**
+ * Returns the items added as tags
+ */
+ items: function() {
+ return this.itemsArray;
+ },
+
+ /**
+ * Assembly value by retrieving the value of each item, and set it on the
+ * element.
+ */
+ pushVal: function() {
+ var self = this,
+ val = $.map(self.items(), function(item) {
+ return self.options.itemValue(item).toString();
+ });
+
+ self.$element.val(val, true).trigger('change');
+ },
+
+ /**
+ * Initializes the tags input behaviour on the element
+ */
+ build: function(options) {
+ var self = this;
+
+ self.options = $.extend({}, defaultOptions, options);
+ // When itemValue is set, freeInput should always be false
+ if (self.objectItems)
+ self.options.freeInput = false;
+
+ makeOptionItemFunction(self.options, 'itemValue');
+ makeOptionItemFunction(self.options, 'itemText');
+ makeOptionFunction(self.options, 'tagClass');
+
+ // Typeahead Bootstrap version 2.3.2
+ if (self.options.typeahead) {
+ var typeahead = self.options.typeahead || {};
+
+ makeOptionFunction(typeahead, 'source');
+
+ self.$input.typeahead($.extend({}, typeahead, {
+ source: function (query, process) {
+ function processItems(items) {
+ var texts = [];
+
+ for (var i = 0; i < items.length; i++) {
+ var text = self.options.itemText(items[i]);
+ map[text] = items[i];
+ texts.push(text);
+ }
+ process(texts);
+ }
+
+ this.map = {};
+ var map = this.map,
+ data = typeahead.source(query);
+
+ if ($.isFunction(data.success)) {
+ // support for Angular callbacks
+ data.success(processItems);
+ } else if ($.isFunction(data.then)) {
+ // support for Angular promises
+ data.then(processItems);
+ } else {
+ // support for functions and jquery promises
+ $.when(data)
+ .then(processItems);
+ }
+ },
+ updater: function (text) {
+ self.add(this.map[text]);
+ return this.map[text];
+ },
+ matcher: function (text) {
+ return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
+ },
+ sorter: function (texts) {
+ return texts.sort();
+ },
+ highlighter: function (text) {
+ var regex = new RegExp( '(' + this.query + ')', 'gi' );
+ return text.replace( regex, "$1" );
+ }
+ }));
+ }
+
+ // typeahead.js
+ if (self.options.typeaheadjs) {
+ var typeaheadConfig = null;
+ var typeaheadDatasets = {};
+
+ // Determine if main configurations were passed or simply a dataset
+ var typeaheadjs = self.options.typeaheadjs;
+ if ($.isArray(typeaheadjs)) {
+ typeaheadConfig = typeaheadjs[0];
+ typeaheadDatasets = typeaheadjs[1];
+ } else {
+ typeaheadDatasets = typeaheadjs;
+ }
+
+ self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
+ if (typeaheadDatasets.valueKey)
+ self.add(datum[typeaheadDatasets.valueKey]);
+ else
+ self.add(datum);
+ self.$input.typeahead('val', '');
+ }, self));
+ }
+
+ self.$container.on('click', $.proxy(function(event) {
+ if (! self.$element.attr('disabled')) {
+ self.$input.removeAttr('disabled');
+ }
+ self.$input.focus();
+ }, self));
+
+ if (self.options.addOnBlur && self.options.freeInput) {
+ self.$input.on('focusout', $.proxy(function(event) {
+ // HACK: only process on focusout when no typeahead opened, to
+ // avoid adding the typeahead text as tag
+ if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
+ self.add(self.$input.val());
+ self.$input.val('');
+ }
+ }, self));
+ }
+
+
+ self.$container.on('keydown', 'input', $.proxy(function(event) {
+ var $input = $(event.target),
+ $inputWrapper = self.findInputWrapper();
+
+ if (self.$element.attr('disabled')) {
+ self.$input.attr('disabled', 'disabled');
+ return;
+ }
+
+ switch (event.which) {
+ // BACKSPACE
+ case 8:
+ if (doGetCaretPosition($input[0]) === 0) {
+ var prev = $inputWrapper.prev();
+ if (prev.length) {
+ self.remove(prev.data('item'));
+ }
+ }
+ break;
+
+ // DELETE
+ case 46:
+ if (doGetCaretPosition($input[0]) === 0) {
+ var next = $inputWrapper.next();
+ if (next.length) {
+ self.remove(next.data('item'));
+ }
+ }
+ break;
+
+ // LEFT ARROW
+ case 37:
+ // Try to move the input before the previous tag
+ var $prevTag = $inputWrapper.prev();
+ if ($input.val().length === 0 && $prevTag[0]) {
+ $prevTag.before($inputWrapper);
+ $input.focus();
+ }
+ break;
+ // RIGHT ARROW
+ case 39:
+ // Try to move the input after the next tag
+ var $nextTag = $inputWrapper.next();
+ if ($input.val().length === 0 && $nextTag[0]) {
+ $nextTag.after($inputWrapper);
+ $input.focus();
+ }
+ break;
+ default:
+ // ignore
+ }
+
+ // Reset internal input's size
+ var textLength = $input.val().length,
+ wordSpace = Math.ceil(textLength / 5),
+ size = textLength + wordSpace + 1;
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
+ }, self));
+
+ self.$container.on('keypress', 'input', $.proxy(function(event) {
+ var $input = $(event.target);
+
+ if (self.$element.attr('disabled')) {
+ self.$input.attr('disabled', 'disabled');
+ return;
+ }
+
+ var text = $input.val(),
+ maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
+ if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
+ // Only attempt to add a tag if there is data in the field
+ if (text.length !== 0) {
+ self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
+ $input.val('');
+ }
+
+ // If the field is empty, let the event triggered fire as usual
+ if (self.options.cancelConfirmKeysOnEmpty === false) {
+ event.preventDefault();
+ }
+ }
+
+ // Reset internal input's size
+ var textLength = $input.val().length,
+ wordSpace = Math.ceil(textLength / 5),
+ size = textLength + wordSpace + 1;
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
+ }, self));
+
+ // Remove icon clicked
+ self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
+ if (self.$element.attr('disabled')) {
+ return;
+ }
+ self.remove($(event.target).closest('.tag').data('item'));
+ }, self));
+
+ // Only add existing value as tags when using strings as tags
+ if (self.options.itemValue === defaultOptions.itemValue) {
+ if (self.$element[0].tagName === 'INPUT') {
+ self.add(self.$element.val());
+ } else {
+ $('option', self.$element).each(function() {
+ self.add($(this).attr('value'), true);
+ });
+ }
+ }
+ },
+
+ /**
+ * Removes all tagsinput behaviour and unregsiter all event handlers
+ */
+ destroy: function() {
+ var self = this;
+
+ // Unbind events
+ self.$container.off('keypress', 'input');
+ self.$container.off('click', '[role=remove]');
+
+ self.$container.remove();
+ self.$element.removeData('tagsinput');
+ self.$element.show();
+ },
+
+ /**
+ * Sets focus on the tagsinput
+ */
+ focus: function() {
+ this.$input.focus();
+ },
+
+ /**
+ * Returns the internal input element
+ */
+ input: function() {
+ return this.$input;
+ },
+
+ /**
+ * Returns the element which is wrapped around the internal input. This
+ * is normally the $container, but typeahead.js moves the $input element.
+ */
+ findInputWrapper: function() {
+ var elt = this.$input[0],
+ container = this.$container[0];
+ while(elt && elt.parentNode !== container)
+ elt = elt.parentNode;
+
+ return $(elt);
+ }
+ };
+
+ /**
+ * Register JQuery plugin
+ */
+ $.fn.tagsinput = function(arg1, arg2, arg3) {
+ var results = [];
+
+ this.each(function() {
+ var tagsinput = $(this).data('tagsinput');
+ // Initialize a new tags input
+ if (!tagsinput) {
+ tagsinput = new TagsInput(this, arg1);
+ $(this).data('tagsinput', tagsinput);
+ results.push(tagsinput);
+
+ if (this.tagName === 'SELECT') {
+ $('option', $(this)).attr('selected', 'selected');
+ }
+
+ // Init tags from $(this).val()
+ $(this).val($(this).val());
+ } else if (!arg1 && !arg2) {
+ // tagsinput already exists
+ // no function, trying to init
+ results.push(tagsinput);
+ } else if(tagsinput[arg1] !== undefined) {
+ // Invoke function on existing tags input
+ if(tagsinput[arg1].length === 3 && arg3 !== undefined){
+ var retVal = tagsinput[arg1](arg2, null, arg3);
+ }else{
+ var retVal = tagsinput[arg1](arg2);
+ }
+ if (retVal !== undefined)
+ results.push(retVal);
+ }
+ });
+
+ if ( typeof arg1 == 'string') {
+ // Return the results from the invoked function calls
+ return results.length > 1 ? results : results[0];
+ } else {
+ return results;
+ }
+ };
+
+ $.fn.tagsinput.Constructor = TagsInput;
+
+ /**
+ * Most options support both a string or number as well as a function as
+ * option value. This function makes sure that the option with the given
+ * key in the given options is wrapped in a function
+ */
+ function makeOptionItemFunction(options, key) {
+ if (typeof options[key] !== 'function') {
+ var propertyName = options[key];
+ options[key] = function(item) { return item[propertyName]; };
+ }
+ }
+ function makeOptionFunction(options, key) {
+ if (typeof options[key] !== 'function') {
+ var value = options[key];
+ options[key] = function() { return value; };
+ }
+ }
+ /**
+ * HtmlEncodes the given value
+ */
+ var htmlEncodeContainer = $('');
+ function htmlEncode(value) {
+ if (value) {
+ return htmlEncodeContainer.text(value).html();
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Returns the position of the caret in the given input field
+ * http://flightschool.acylt.com/devnotes/caret-position-woes/
+ */
+ function doGetCaretPosition(oField) {
+ var iCaretPos = 0;
+ if (document.selection) {
+ oField.focus ();
+ var oSel = document.selection.createRange();
+ oSel.moveStart ('character', -oField.value.length);
+ iCaretPos = oSel.text.length;
+ } else if (oField.selectionStart || oField.selectionStart == '0') {
+ iCaretPos = oField.selectionStart;
+ }
+ return (iCaretPos);
+ }
+
+ /**
+ * Returns boolean indicates whether user has pressed an expected key combination.
+ * @param object keyPressEvent: JavaScript event object, refer
+ * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+ * @param object lookupList: expected key combinations, as in:
+ * [13, {which: 188, shiftKey: true}]
+ */
+ function keyCombinationInList(keyPressEvent, lookupList) {
+ var found = false;
+ $.each(lookupList, function (index, keyCombination) {
+ if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
+ found = true;
+ return false;
+ }
+
+ if (keyPressEvent.which === keyCombination.which) {
+ var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
+ shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
+ ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
+ if (alt && shift && ctrl) {
+ found = true;
+ return false;
+ }
+ }
+ });
+
+ return found;
+ }
+
+ /**
+ * Initialize tagsinput behaviour on inputs and selects which have
+ * data-role=tagsinput
+ */
+ $(function() {
+ $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
+ });
+})(window.jQuery);
diff --git a/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.min.js b/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.min.js
new file mode 100644
index 000000000..3adbfd913
--- /dev/null
+++ b/public/assets/libs/bootstrap-tagsinput/bootstrap-tagsinput.min.js
@@ -0,0 +1,7 @@
+/*
+ * bootstrap-tagsinput v0.6.1 by Tim Schlechter
+ *
+ */
+
+!function(a){"use strict";function b(b,c){this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a(''),this.$input=a('').appendTo(this.$container),this.$element.before(this.$container),this.build(c)}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!0,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;if.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a(''+e(k)+'');if(p.data("item",b),f.findInputWrapper().before(p),p.after(" "),f.isSelect&&!a('option[value="'+encodeURIComponent(j)+'"]',f.$element)[0]){var q=a("");q.data("item",b),q.attr("value",j),f.$element.append(q)}c||f.pushVal(),(f.options.maxTags===f.itemsArray.length||f.items().toString().length===f.options.maxInputLength)&&f.$container.addClass("bootstrap-tagsinput-max"),f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var r=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,r)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),-1!==a.inArray(b,e.itemsArray)&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d$1")}}))}if(e.options.typeaheadjs){var j=null,k={},l=e.options.typeaheadjs;a.isArray(l)?(j=l[0],k=l[1]):k=l,e.$input.typeahead(j,k).on("typeahead:selected",a.proxy(function(a,b){k.valueKey?e.add(b[k.valueKey]):e.add(b),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
+//# sourceMappingURL=bootstrap-tagsinput.min.js.map
\ No newline at end of file
--
Gitee