diff --git a/Bootstrap.Admin/Bootstrap.Admin.csproj b/Bootstrap.Admin/Bootstrap.Admin.csproj index 58c9a689..2775bba0 100644 --- a/Bootstrap.Admin/Bootstrap.Admin.csproj +++ b/Bootstrap.Admin/Bootstrap.Admin.csproj @@ -142,6 +142,8 @@ + + diff --git a/Bootstrap.Admin/Content/css/admin-responsive.css b/Bootstrap.Admin/Content/css/admin-responsive.css index f8854da0..f7e7a150 100644 --- a/Bootstrap.Admin/Content/css/admin-responsive.css +++ b/Bootstrap.Admin/Content/css/admin-responsive.css @@ -86,6 +86,12 @@ } } +@media (max-width: 374px) { + .hidden-400 { + display: none; + } +} + @media (min-height: 672px) { #sidebar { padding-top: 94px; diff --git a/Bootstrap.Admin/Content/js/bootstrap3-typeahead.js b/Bootstrap.Admin/Content/js/bootstrap3-typeahead.js new file mode 100644 index 00000000..0c97b8c7 --- /dev/null +++ b/Bootstrap.Admin/Content/js/bootstrap3-typeahead.js @@ -0,0 +1,584 @@ +/* ============================================================= + * bootstrap3-typeahead.js v4.0.2 + * https://github.com/bassjobsen/Bootstrap-3-Typeahead + * ============================================================= + * Original written by @mdo and @fat + * ============================================================= + * Copyright 2014 Bass Jobsen @bassjobsen + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +(function (root, factory) { + + 'use strict'; + + // CommonJS module is defined + if (typeof module !== 'undefined' && module.exports) { + module.exports = factory(require('jquery')); + } + // AMD module is defined + else if (typeof define === 'function' && define.amd) { + define(['jquery'], function ($) { + return factory ($); + }); + } else { + factory(root.jQuery); + } + +}(this, function ($) { + + 'use strict'; + // jshint laxcomma: true + + + /* TYPEAHEAD PUBLIC CLASS DEFINITION + * ================================= */ + + var Typeahead = function (element, options) { + this.$element = $(element); + this.options = $.extend({}, Typeahead.defaults, options); + this.matcher = this.options.matcher || this.matcher; + this.sorter = this.options.sorter || this.sorter; + this.select = this.options.select || this.select; + this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true; + this.highlighter = this.options.highlighter || this.highlighter; + this.render = this.options.render || this.render; + this.updater = this.options.updater || this.updater; + this.displayText = this.options.displayText || this.displayText; + this.source = this.options.source; + this.delay = this.options.delay; + this.$menu = $(this.options.menu); + this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null; + this.fitToElement = typeof this.options.fitToElement == 'boolean' ? this.options.fitToElement : false; + this.shown = false; + this.listen(); + this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' || this.options.showHintOnFocus === "all" ? this.options.showHintOnFocus : false; + this.afterSelect = this.options.afterSelect; + this.addItem = false; + this.value = this.$element.val() || this.$element.text(); + }; + + Typeahead.prototype = { + + constructor: Typeahead, + + select: function () { + var val = this.$menu.find('.active').data('value'); + this.$element.data('active', val); + if (this.autoSelect || val) { + var newVal = this.updater(val); + // Updater can be set to any random functions via "options" parameter in constructor above. + // Add null check for cases when updater returns void or undefined. + if (!newVal) { + newVal = ''; + } + this.$element + .val(this.displayText(newVal) || newVal) + .text(this.displayText(newVal) || newVal) + .change(); + this.afterSelect(newVal); + } + return this.hide(); + }, + + updater: function (item) { + return item; + }, + + setSource: function (source) { + this.source = source; + }, + + show: function () { + var pos = $.extend({}, this.$element.position(), { + height: this.$element[0].offsetHeight + }); + + var scrollHeight = typeof this.options.scrollHeight == 'function' ? + this.options.scrollHeight.call() : + this.options.scrollHeight; + + var element; + if (this.shown) { + element = this.$menu; + } else if (this.$appendTo) { + element = this.$menu.appendTo(this.$appendTo); + this.hasSameParent = this.$appendTo.is(this.$element.parent()); + } else { + element = this.$menu.insertAfter(this.$element); + this.hasSameParent = true; + } + + if (!this.hasSameParent) { + // We cannot rely on the element position, need to position relative to the window + element.css("position", "fixed"); + var offset = this.$element.offset(); + pos.top = offset.top; + pos.left = offset.left; + } + // The rules for bootstrap are: 'dropup' in the parent and 'dropdown-menu-right' in the element. + // Note that to get right alignment, you'll need to specify `menu` in the options to be: + // '' + var dropup = $(element).parent().hasClass('dropup'); + var newTop = dropup ? 'auto' : (pos.top + pos.height + scrollHeight); + var right = $(element).hasClass('dropdown-menu-right'); + var newLeft = right ? 'auto' : pos.left; + // it seems like setting the css is a bad idea (just let Bootstrap do it), but I'll keep the old + // logic in place except for the dropup/right-align cases. + element.css({ top: newTop, left: newLeft }).show(); + + if (this.options.fitToElement === true) { + element.css("width", this.$element.outerWidth() + "px"); + } + + this.shown = true; + return this; + }, + + hide: function () { + this.$menu.hide(); + this.shown = false; + return this; + }, + + lookup: function (query) { + var items; + if (typeof(query) != 'undefined' && query !== null) { + this.query = query; + } else { + this.query = this.$element.val() || this.$element.text() || ''; + } + + if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) { + return this.shown ? this.hide() : this; + } + + var worker = $.proxy(function () { + + if ($.isFunction(this.source)) { + this.source(this.query, $.proxy(this.process, this)); + } else if (this.source) { + this.process(this.source); + } + }, this); + + clearTimeout(this.lookupWorker); + this.lookupWorker = setTimeout(worker, this.delay); + }, + + process: function (items) { + var that = this; + + items = $.grep(items, function (item) { + return that.matcher(item); + }); + + items = this.sorter(items); + + if (!items.length && !this.options.addItem) { + return this.shown ? this.hide() : this; + } + + if (items.length > 0) { + this.$element.data('active', items[0]); + } else { + this.$element.data('active', null); + } + + // Add item + if (this.options.addItem){ + items.push(this.options.addItem); + } + + if (this.options.items == 'all') { + return this.render(items).show(); + } else { + return this.render(items.slice(0, this.options.items)).show(); + } + }, + + matcher: function (item) { + var it = this.displayText(item); + return ~it.toLowerCase().indexOf(this.query.toLowerCase()); + }, + + sorter: function (items) { + var beginswith = []; + var caseSensitive = []; + var caseInsensitive = []; + var item; + + while ((item = items.shift())) { + var it = this.displayText(item); + if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item); + else if (~it.indexOf(this.query)) caseSensitive.push(item); + else caseInsensitive.push(item); + } + + return beginswith.concat(caseSensitive, caseInsensitive); + }, + + highlighter: function (item) { + var html = $('
'); + var query = this.query; + var i = item.toLowerCase().indexOf(query.toLowerCase()); + var len = query.length; + var leftPart; + var middlePart; + var rightPart; + var strong; + if (len === 0) { + return html.text(item).html(); + } + while (i > -1) { + leftPart = item.substr(0, i); + middlePart = item.substr(i, len); + rightPart = item.substr(i + len); + strong = $('').text(middlePart); + html + .append(document.createTextNode(leftPart)) + .append(strong); + item = rightPart; + i = item.toLowerCase().indexOf(query.toLowerCase()); + } + return html.append(document.createTextNode(item)).html(); + }, + + render: function (items) { + var that = this; + var self = this; + var activeFound = false; + var data = []; + var _category = that.options.separator; + + $.each(items, function (key,value) { + // inject separator + if (key > 0 && value[_category] !== items[key - 1][_category]){ + data.push({ + __type: 'divider' + }); + } + + // inject category header + if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])){ + data.push({ + __type: 'category', + name: value[_category] + }); + } + data.push(value); + }); + + items = $(data).map(function (i, item) { + if ((item.__type || false) == 'category'){ + return $(that.options.headerHtml).text(item.name)[0]; + } + + if ((item.__type || false) == 'divider'){ + return $(that.options.headerDivider)[0]; + } + + var text = self.displayText(item); + i = $(that.options.item).data('value', item); + i.find('a').html(that.highlighter(text, item)); + if (text == self.$element.val()) { + i.addClass('active'); + self.$element.data('active', item); + activeFound = true; + } + return i[0]; + }); + + if (this.autoSelect && !activeFound) { + items.filter(':not(.dropdown-header)').first().addClass('active'); + this.$element.data('active', items.first().data('value')); + } + this.$menu.html(items); + return this; + }, + + displayText: function (item) { + return typeof item !== 'undefined' && typeof item.name != 'undefined' ? item.name : item; + }, + + next: function (event) { + var active = this.$menu.find('.active').removeClass('active'); + var next = active.next(); + + if (!next.length) { + next = $(this.$menu.find('li')[0]); + } + + next.addClass('active'); + }, + + prev: function (event) { + var active = this.$menu.find('.active').removeClass('active'); + var prev = active.prev(); + + if (!prev.length) { + prev = this.$menu.find('li').last(); + } + + prev.addClass('active'); + }, + + listen: function () { + this.$element + .on('focus', $.proxy(this.focus, this)) + .on('blur', $.proxy(this.blur, this)) + .on('keypress', $.proxy(this.keypress, this)) + .on('input', $.proxy(this.input, this)) + .on('keyup', $.proxy(this.keyup, this)); + + if (this.eventSupported('keydown')) { + this.$element.on('keydown', $.proxy(this.keydown, this)); + } + + this.$menu + .on('click', $.proxy(this.click, this)) + .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) + .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) + .on('mousedown', $.proxy(this.mousedown,this)); + }, + + destroy : function () { + this.$element.data('typeahead',null); + this.$element.data('active',null); + this.$element + .off('focus') + .off('blur') + .off('keypress') + .off('input') + .off('keyup'); + + if (this.eventSupported('keydown')) { + this.$element.off('keydown'); + } + + this.$menu.remove(); + this.destroyed = true; + }, + + eventSupported: function (eventName) { + var isSupported = eventName in this.$element; + if (!isSupported) { + this.$element.setAttribute(eventName, 'return;'); + isSupported = typeof this.$element[eventName] === 'function'; + } + return isSupported; + }, + + move: function (e) { + if (!this.shown) return; + + switch (e.keyCode) { + case 9: // tab + case 13: // enter + case 27: // escape + e.preventDefault(); + break; + + case 38: // up arrow + // with the shiftKey (this is actually the left parenthesis) + if (e.shiftKey) return; + e.preventDefault(); + this.prev(); + break; + + case 40: // down arrow + // with the shiftKey (this is actually the right parenthesis) + if (e.shiftKey) return; + e.preventDefault(); + this.next(); + break; + } + }, + + keydown: function (e) { + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); + if (!this.shown && e.keyCode == 40) { + this.lookup(); + } else { + this.move(e); + } + }, + + keypress: function (e) { + if (this.suppressKeyPressRepeat) return; + this.move(e); + }, + + input: function (e) { + // This is a fixed for IE10/11 that fires the input event when a placehoder is changed + // (https://connect.microsoft.com/IE/feedback/details/810538/ie-11-fires-input-event-on-focus) + var currentValue = this.$element.val() || this.$element.text(); + if (this.value !== currentValue) { + this.value = currentValue; + this.lookup(); + } + }, + + keyup: function (e) { + if (this.destroyed) { + return; + } + switch (e.keyCode) { + case 40: // down arrow + case 38: // up arrow + case 16: // shift + case 17: // ctrl + case 18: // alt + break; + + case 9: // tab + case 13: // enter + if (!this.shown) return; + this.select(); + break; + + case 27: // escape + if (!this.shown) return; + this.hide(); + break; + } + + + }, + + focus: function (e) { + if (!this.focused) { + this.focused = true; + if (this.options.showHintOnFocus && this.skipShowHintOnFocus !== true) { + if(this.options.showHintOnFocus === "all") { + this.lookup(""); + } else { + this.lookup(); + } + } + } + if (this.skipShowHintOnFocus) { + this.skipShowHintOnFocus = false; + } + }, + + blur: function (e) { + if (!this.mousedover && !this.mouseddown && this.shown) { + this.hide(); + this.focused = false; + } else if (this.mouseddown) { + // This is for IE that blurs the input when user clicks on scroll. + // We set the focus back on the input and prevent the lookup to occur again + this.skipShowHintOnFocus = true; + this.$element.focus(); + this.mouseddown = false; + } + }, + + click: function (e) { + e.preventDefault(); + this.skipShowHintOnFocus = true; + this.select(); + this.$element.focus(); + this.hide(); + }, + + mouseenter: function (e) { + this.mousedover = true; + this.$menu.find('.active').removeClass('active'); + $(e.currentTarget).addClass('active'); + }, + + mouseleave: function (e) { + this.mousedover = false; + if (!this.focused && this.shown) this.hide(); + }, + + /** + * We track the mousedown for IE. When clicking on the menu scrollbar, IE makes the input blur thus hiding the menu. + */ + mousedown: function (e) { + this.mouseddown = true; + this.$menu.one("mouseup", function(e){ + // IE won't fire this, but FF and Chrome will so we reset our flag for them here + this.mouseddown = false; + }.bind(this)); + }, + + }; + + + /* TYPEAHEAD PLUGIN DEFINITION + * =========================== */ + + var old = $.fn.typeahead; + + $.fn.typeahead = function (option) { + var arg = arguments; + if (typeof option == 'string' && option == 'getActive') { + return this.data('active'); + } + return this.each(function () { + var $this = $(this); + var data = $this.data('typeahead'); + var options = typeof option == 'object' && option; + if (!data) $this.data('typeahead', (data = new Typeahead(this, options))); + if (typeof option == 'string' && data[option]) { + if (arg.length > 1) { + data[option].apply(data, Array.prototype.slice.call(arg, 1)); + } else { + data[option](); + } + } + }); + }; + + Typeahead.defaults = { + source: [], + items: 8, + menu: '', + item: '
  • ', + minLength: 1, + scrollHeight: 0, + autoSelect: true, + afterSelect: $.noop, + addItem: false, + delay: 0, + separator: 'category', + headerHtml: '', + headerDivider: '' + }; + + $.fn.typeahead.Constructor = Typeahead; + + /* TYPEAHEAD NO CONFLICT + * =================== */ + + $.fn.typeahead.noConflict = function () { + $.fn.typeahead = old; + return this; + }; + + + /* TYPEAHEAD DATA-API + * ================== */ + + $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { + var $this = $(this); + if ($this.data('typeahead')) return; + $this.typeahead($this.data()); + }); + +})); diff --git a/Bootstrap.Admin/Content/js/bootstrap3-typeahead.min.js b/Bootstrap.Admin/Content/js/bootstrap3-typeahead.min.js new file mode 100644 index 00000000..93d4c925 --- /dev/null +++ b/Bootstrap.Admin/Content/js/bootstrap3-typeahead.min.js @@ -0,0 +1 @@ +(function(root,factory){"use strict";if(typeof module!=="undefined"&&module.exports){module.exports=factory(require("jquery"))}else if(typeof define==="function"&&define.amd){define(["jquery"],function($){return factory($)})}else{factory(root.jQuery)}})(this,function($){"use strict";var Typeahead=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.typeahead.defaults,options);this.matcher=this.options.matcher||this.matcher;this.sorter=this.options.sorter||this.sorter;this.select=this.options.select||this.select;this.autoSelect=typeof this.options.autoSelect=="boolean"?this.options.autoSelect:true;this.highlighter=this.options.highlighter||this.highlighter;this.render=this.options.render||this.render;this.updater=this.options.updater||this.updater;this.displayText=this.options.displayText||this.displayText;this.source=this.options.source;this.delay=this.options.delay;this.$menu=$(this.options.menu);this.$appendTo=this.options.appendTo?$(this.options.appendTo):null;this.fitToElement=typeof this.options.fitToElement=="boolean"?this.options.fitToElement:false;this.shown=false;this.listen();this.showHintOnFocus=typeof this.options.showHintOnFocus=="boolean"||this.options.showHintOnFocus==="all"?this.options.showHintOnFocus:false;this.afterSelect=this.options.afterSelect;this.addItem=false;this.value=this.$element.val()||this.$element.text()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").data("value");this.$element.data("active",val);if(this.autoSelect||val){var newVal=this.updater(val);if(!newVal){newVal=""}this.$element.val(this.displayText(newVal)||newVal).text(this.displayText(newVal)||newVal).change();this.afterSelect(newVal)}return this.hide()},updater:function(item){return item},setSource:function(source){this.source=source},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});var scrollHeight=typeof this.options.scrollHeight=="function"?this.options.scrollHeight.call():this.options.scrollHeight;var element;if(this.shown){element=this.$menu}else if(this.$appendTo){element=this.$menu.appendTo(this.$appendTo);this.hasSameParent=this.$appendTo.is(this.$element.parent())}else{element=this.$menu.insertAfter(this.$element);this.hasSameParent=true}if(!this.hasSameParent){element.css("position","fixed");var offset=this.$element.offset();pos.top=offset.top;pos.left=offset.left}var dropup=$(element).parent().hasClass("dropup");var newTop=dropup?"auto":pos.top+pos.height+scrollHeight;var right=$(element).hasClass("dropdown-menu-right");var newLeft=right?"auto":pos.left;element.css({top:newTop,left:newLeft}).show();if(this.options.fitToElement===true){element.css("width",this.$element.outerWidth()+"px")}this.shown=true;return this},hide:function(){this.$menu.hide();this.shown=false;return this},lookup:function(query){var items;if(typeof query!="undefined"&&query!==null){this.query=query}else{this.query=this.$element.val()||this.$element.text()||""}if(this.query.length0){this.$element.data("active",items[0])}else{this.$element.data("active",null)}if(this.options.addItem){items.push(this.options.addItem)}if(this.options.items=="all"){return this.render(items).show()}else{return this.render(items.slice(0,this.options.items)).show()}},matcher:function(item){var it=this.displayText(item);return~it.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(items){var beginswith=[];var caseSensitive=[];var caseInsensitive=[];var item;while(item=items.shift()){var it=this.displayText(item);if(!it.toLowerCase().indexOf(this.query.toLowerCase()))beginswith.push(item);else if(~it.indexOf(this.query))caseSensitive.push(item);else caseInsensitive.push(item)}return beginswith.concat(caseSensitive,caseInsensitive)},highlighter:function(item){var html=$("
    ");var query=this.query;var i=item.toLowerCase().indexOf(query.toLowerCase());var len=query.length;var leftPart;var middlePart;var rightPart;var strong;if(len===0){return html.text(item).html()}while(i>-1){leftPart=item.substr(0,i);middlePart=item.substr(i,len);rightPart=item.substr(i+len);strong=$("").text(middlePart);html.append(document.createTextNode(leftPart)).append(strong);item=rightPart;i=item.toLowerCase().indexOf(query.toLowerCase())}return html.append(document.createTextNode(item)).html()},render:function(items){var that=this;var self=this;var activeFound=false;var data=[];var _category=that.options.separator;$.each(items,function(key,value){if(key>0&&value[_category]!==items[key-1][_category]){data.push({__type:"divider"})}if(value[_category]&&(key===0||value[_category]!==items[key-1][_category])){data.push({__type:"category",name:value[_category]})}data.push(value)});items=$(data).map(function(i,item){if((item.__type||false)=="category"){return $(that.options.headerHtml).text(item.name)[0]}if((item.__type||false)=="divider"){return $(that.options.headerDivider)[0]}var text=self.displayText(item);i=$(that.options.item).data("value",item);i.find("a").html(that.highlighter(text,item));if(text==self.$element.val()){i.addClass("active");self.$element.data("active",item);activeFound=true}return i[0]});if(this.autoSelect&&!activeFound){items.filter(":not(.dropdown-header)").first().addClass("active");this.$element.data("active",items.first().data("value"))}this.$menu.html(items);return this},displayText:function(item){return typeof item!=="undefined"&&typeof item.name!="undefined"&&item.name||item},next:function(event){var active=this.$menu.find(".active").removeClass("active");var next=active.next();if(!next.length){next=$(this.$menu.find("li")[0])}next.addClass("active")},prev:function(event){var active=this.$menu.find(".active").removeClass("active");var prev=active.prev();if(!prev.length){prev=this.$menu.find("li").last()}prev.addClass("active")},listen:function(){this.$element.on("focus",$.proxy(this.focus,this)).on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("input",$.proxy(this.input,this)).on("keyup",$.proxy(this.keyup,this));if(this.eventSupported("keydown")){this.$element.on("keydown",$.proxy(this.keydown,this))}this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this)).on("mouseleave","li",$.proxy(this.mouseleave,this)).on("mousedown",$.proxy(this.mousedown,this))},destroy:function(){this.$element.data("typeahead",null);this.$element.data("active",null);this.$element.off("focus").off("blur").off("keypress").off("input").off("keyup");if(this.eventSupported("keydown")){this.$element.off("keydown")}this.$menu.remove();this.destroyed=true},eventSupported:function(eventName){var isSupported=eventName in this.$element;if(!isSupported){this.$element.setAttribute(eventName,"return;");isSupported=typeof this.$element[eventName]==="function"}return isSupported},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:if(e.shiftKey)return;e.preventDefault();this.prev();break;case 40:if(e.shiftKey)return;e.preventDefault();this.next();break}},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]);if(!this.shown&&e.keyCode==40){this.lookup()}else{this.move(e)}},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},input:function(e){var currentValue=this.$element.val()||this.$element.text();if(this.value!==currentValue){this.value=currentValue;this.lookup()}},keyup:function(e){if(this.destroyed){return}switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break}},focus:function(e){if(!this.focused){this.focused=true;if(this.options.showHintOnFocus&&this.skipShowHintOnFocus!==true){if(this.options.showHintOnFocus==="all"){this.lookup("")}else{this.lookup()}}}if(this.skipShowHintOnFocus){this.skipShowHintOnFocus=false}},blur:function(e){if(!this.mousedover&&!this.mouseddown&&this.shown){this.hide();this.focused=false}else if(this.mouseddown){this.skipShowHintOnFocus=true;this.$element.focus();this.mouseddown=false}},click:function(e){e.preventDefault();this.skipShowHintOnFocus=true;this.select();this.$element.focus();this.hide()},mouseenter:function(e){this.mousedover=true;this.$menu.find(".active").removeClass("active");$(e.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=false;if(!this.focused&&this.shown)this.hide()},mousedown:function(e){this.mouseddown=true;this.$menu.one("mouseup",function(e){this.mouseddown=false}.bind(this))}};var old=$.fn.typeahead;$.fn.typeahead=function(option){var arg=arguments;if(typeof option=="string"&&option=="getActive"){return this.data("active")}return this.each(function(){var $this=$(this);var data=$this.data("typeahead");var options=typeof option=="object"&&option;if(!data)$this.data("typeahead",data=new Typeahead(this,options));if(typeof option=="string"&&data[option]){if(arg.length>1){data[option].apply(data,Array.prototype.slice.call(arg,1))}else{data[option]()}}})};$.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1,scrollHeight:0,autoSelect:true,afterSelect:$.noop,addItem:false,delay:0,separator:"category",headerHtml:'',headerDivider:''};$.fn.typeahead.Constructor=Typeahead;$.fn.typeahead.noConflict=function(){$.fn.typeahead=old;return this};$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);if($this.data("typeahead"))return;$this.typeahead($this.data())})}); diff --git a/Bootstrap.Admin/Content/js/framework.js b/Bootstrap.Admin/Content/js/framework.js index 993ae4c0..a142a46d 100644 --- a/Bootstrap.Admin/Content/js/framework.js +++ b/Bootstrap.Admin/Content/js/framework.js @@ -160,7 +160,16 @@ data: { "": iDs }, type: 'DELETE', success: function (result) { - if (result) { swal("成功!", "删除数据", "success"); $(options.bootstrapTable).bootstrapTable('refresh'); } + if (result) { + if ($.isPlainObject(result)) { + var info = result.result ? "success" : "error"; + var msg = result.msg + swal(msg, "删除数据", info); + result = result.result; + } + else swal("成功", "删除数据", "success"); + if (result) $(options.bootstrapTable).bootstrapTable('refresh'); + } else swal("失败", "删除数据", "error"); handlerCallback.call(that, callback, e, { oper: 'del', success: !!result, data: iDs }); }, @@ -421,4 +430,12 @@ Exceptions.getFileByName = function (fileName, callback) { processData.call(this, { Id: "", callback: callback, method: "PUT", swal: false, data: { "": fileName } }); } + + // Dicts + Dicts = { + url: '../api/Dicts/' + } + Dicts.retrieveCategories = function (callback) { + processData.call(this, { Id: 1, callback: callback, swal: false, data: { type: 'category' } }); + } })(jQuery); \ No newline at end of file diff --git a/Bootstrap.Admin/Controllers/DictsController.cs b/Bootstrap.Admin/Controllers/DictsController.cs index 4fbc36bb..eb62cd8d 100644 --- a/Bootstrap.Admin/Controllers/DictsController.cs +++ b/Bootstrap.Admin/Controllers/DictsController.cs @@ -1,49 +1,73 @@ -using Bootstrap.Admin.Models; -using Bootstrap.DataAccess; -using System.Linq; -using System.Web.Http; - -namespace Bootstrap.Admin.Controllers -{ - public class DictsController : ApiController - { - /// - /// - /// - /// - /// - [HttpGet] - public QueryData Get([FromUri]QueryDictOption value) - { - return value.RetrieveData(); - } - /// - /// - /// - /// - /// - [HttpGet] - public Dict Get(int id) - { - return DictHelper.RetrieveDicts().FirstOrDefault(t => t.ID == id); - } - /// - /// - /// - /// - [HttpPost] - public bool Post([FromBody]Dict value) - { - return DictHelper.SaveDict(value); - } - /// - /// - /// - /// - [HttpDelete] - public bool Delete([FromBody]string value) - { - return DictHelper.DeleteDict(value); - } - } -} +using Bootstrap.Admin.Models; +using Bootstrap.DataAccess; +using Longbow.Security.Principal; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; + +namespace Bootstrap.Admin.Controllers +{ + public class DictsController : ApiController + { + /// + /// + /// + /// + /// + [HttpGet] + public QueryData Get([FromUri]QueryDictOption value) + { + return value.RetrieveData(); + } + /// + /// + /// + /// + /// + [HttpGet] + public Dict Get(int id) + { + return DictHelper.RetrieveDicts().FirstOrDefault(t => t.ID == id); + } + /// + /// + /// + /// + [HttpPost] + public bool Post([FromBody]Dict value) + { + return DictHelper.SaveDict(value); + } + /// + /// + /// + /// + [HttpPost] + public IEnumerable Post(int id, [FromBody]JObject value) + { + var ret = new List(); + dynamic json = value; + switch ((string)json.type) + { + case "category": + ret = DictHelper.RetrieveCategories().ToList(); + break; + default: + break; + } + return ret; + } + /// + /// + /// + /// + [HttpDelete] + public dynamic Delete([FromBody]string value) + { + if (!LgbPrincipal.IsAdmin(User.Identity.Name) && !User.IsInRole("Administrators")) return new { result = false, msg = "当前用户权限不够" }; + var result = DictHelper.DeleteDict(value); + return new { result = result, msg = result ? "成功!" : "失败" }; + } + } +} \ No newline at end of file diff --git a/Bootstrap.Admin/Scripts/Dicts.js b/Bootstrap.Admin/Scripts/Dicts.js index cbeb7b3d..56c17795 100644 --- a/Bootstrap.Admin/Scripts/Dicts.js +++ b/Bootstrap.Admin/Scripts/Dicts.js @@ -1,4 +1,5 @@ $(function () { + $('#panelResultHeader').html('查询结果(仅 Administrators 角色成员可删除数据)'); var bsa = new BootstrapAdmin({ url: '../api/Dicts', dataEntity: new DataEntity({ @@ -13,13 +14,13 @@ }); $('table').smartTable({ - url: '../api/Dicts', //请求后台的URL(*) + url: '../api/Dicts', sortName: 'Category', queryParams: function (params) { return $.extend(params, { category: $('#txt_dict_cate').val(), name: $("#txt_dict_name").val(), define: $("#txt_dict_define").val() }); }, columns: [{ checkbox: true }, { title: "Id", field: "ID", events: bsa.idEvents(), formatter: BootstrapAdmin.idFormatter }, { title: "字典分项", field: "Category", sortable: true }, - { title: "字典名称", field: "Name", sortable: true }, + { title: "字典名称", field: "Name", sortable: false }, { title: "字典代码", field: "Code", sortable: false }, { title: "字典类别", field: "DefineName", sortable: true } ] @@ -46,4 +47,12 @@ }); // select $('select').selectpicker(); + + // autocomplete + Dicts.retrieveCategories(function (result) { + $('#txt_dict_cate').typeahead({ + source: result, + autoSelect: true + }); + }); }); \ No newline at end of file diff --git a/Bootstrap.Admin/Scripts/_references.js b/Bootstrap.Admin/Scripts/_references.js index 10236e9d..0a1c01ed 100644 Binary files a/Bootstrap.Admin/Scripts/_references.js and b/Bootstrap.Admin/Scripts/_references.js differ diff --git a/Bootstrap.Admin/Views/Admin/Dicts.cshtml b/Bootstrap.Admin/Views/Admin/Dicts.cshtml index d17dfe02..7c9a691f 100644 --- a/Bootstrap.Admin/Views/Admin/Dicts.cshtml +++ b/Bootstrap.Admin/Views/Admin/Dicts.cshtml @@ -4,6 +4,7 @@ Layout = "~/Views/Shared/_Default.cshtml"; } @section Javascript { + } @section header { @@ -17,7 +18,7 @@
    - +
    diff --git a/Bootstrap.Admin/Views/Shared/_Default.cshtml b/Bootstrap.Admin/Views/Shared/_Default.cshtml index 1c509dc9..ef3444c2 100644 --- a/Bootstrap.Admin/Views/Shared/_Default.cshtml +++ b/Bootstrap.Admin/Views/Shared/_Default.cshtml @@ -60,8 +60,8 @@ @RenderSection("toolbar", false)
    -
    -
    +
    +
    查询结果
    diff --git a/Bootstrap.Admin/Web.config b/Bootstrap.Admin/Web.config index 827502a9..487ac019 100644 --- a/Bootstrap.Admin/Web.config +++ b/Bootstrap.Admin/Web.config @@ -43,6 +43,7 @@ + diff --git a/Bootstrap.DataAccess/DictHelper.cs b/Bootstrap.DataAccess/DictHelper.cs index 068c800a..6f076f9f 100644 --- a/Bootstrap.DataAccess/DictHelper.cs +++ b/Bootstrap.DataAccess/DictHelper.cs @@ -15,6 +15,7 @@ namespace Bootstrap.DataAccess internal const string RetrieveDictsDataKey = "DictHelper-RetrieveDicts"; internal const string RetrieveWebSettingsDataKey = "DictHelper-RetrieveDictsWebSettings"; internal const string RetrieveIconPathSettingsDataKey = "DictHelper-RetrieveDictsIconPathSettings"; + internal const string RetrieveCategoryDataKey = "DictHelper-RetrieveDictsCategory"; /// /// 查询所有字典信息 /// @@ -218,5 +219,30 @@ namespace Bootstrap.DataAccess return dict; }, CacheSection.RetrieveDescByKey(RetrieveIconPathSettingsDataKey)); } + /// + /// 获取字典分类名称 + /// + /// + public static IEnumerable RetrieveCategories() + { + return CacheManager.GetOrAdd(RetrieveCategoryDataKey, CacheSection.RetrieveIntervalByKey(RetrieveCategoryDataKey), key => + { + var ret = new List(); + string sql = "select distinct Category from Dicts"; + DbCommand cmd = DBAccessManager.SqlDBAccess.CreateCommand(CommandType.Text, sql); + try + { + using (DbDataReader reader = DBAccessManager.SqlDBAccess.ExecuteReader(cmd)) + { + while (reader.Read()) + { + ret.Add((string)reader[0]); + } + } + } + catch (Exception ex) { ExceptionManager.Publish(ex); } + return ret; + }, CacheSection.RetrieveDescByKey(RetrieveCategoryDataKey)); + } } }