diff --git a/.vs/config/applicationhost.config b/.vs/config/applicationhost.config index 34cdb1b..0700253 100644 --- a/.vs/config/applicationhost.config +++ b/.vs/config/applicationhost.config @@ -162,7 +162,7 @@ - + diff --git a/StockManMVC.sln b/StockManMVC.sln index 36a9400..b0515d2 100644 --- a/StockManMVC.sln +++ b/StockManMVC.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StockManMVC", "StockManMVC\StockManMVC.csproj", "{65E2BF91-5208-4820-8AED-1200E91CF93B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VersGen", "..\..\..\VisualStudioProjects\StockMan\VersGen\VersGen.csproj", "{3645071E-9114-4D3C-A419-990FC25D5CD7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VersGen", "VersGen\VersGen.csproj", "{3645071E-9114-4D3C-A419-990FC25D5CD7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/StockManMVC/Content/Gridmvc.css b/StockManMVC/Content/Gridmvc.css new file mode 100644 index 0000000..d48c4d3 --- /dev/null +++ b/StockManMVC/Content/Gridmvc.css @@ -0,0 +1,39 @@ +/*** +* Grid.Mvc stylesheet http://gridmvc.codeplex.com/ +* This file contains default styles for Grid.Mvc. +*/ +/* Grid */ +table.grid-table { margin: 0; } + table.grid-table .grid-wrap { padding: 0; position: relative; } + table.grid-table .grid-empty-text { color: #666; } + + /* Grid headers */ + table.grid-table .grid-header { position: relative; } + table.grid-table .grid-header .sorted-asc .grid-sort-arrow:after { content: " \2193"; } + table.grid-table .grid-header .sorted-desc .grid-sort-arrow:after { content: " \2191"; } + table.grid-table .grid-header > .grid-header-title { width: 100%; margin-right: 15px; white-space: nowrap; } + + /* Grid body */ + table.grid-table tr.grid-row-selected td { background: #4888C2 !important; color: white; } + table.grid-table tr.grid-row-selected a { color: white; } + +/* Grid filtering */ +input.grid-filter-input { padding: 4px; font-size: 13px; } +table.grid-table .grid-filter { position: relative; margin-top: 2px; float: right; width: 10px; height: 12px; } +table.grid-table .grid-filter-btn { cursor: pointer; display: block; width: 10px; height: 12px; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAMCAYAAABbayygAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAJFJREFUKFNjkJSU/E8MZvj//78DMRhkoj+6bizYH2SiiIeHx2FjY+P/2DBIDqSGAQSOHTtmYWZm9hldEUgMJAdWBAJAHSzt7e056ApBYiA5qDIIAAoIhIaGroYpArFBYlBpVLB3715DmEIQGyqMCUDWwBRiWIkOYAqhXNwApMjX13c7lIsbgBQBrdWAcqGAgQEAdOGTrvsYKXIAAAAASUVORK5CYII=') no-repeat; } + table.grid-table .grid-filter-btn.filtered { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAMCAYAAABbayygAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAJNJREFUKFNjYGj//58o/P//fwdiMIOkpKQ/VhOQMFgNULWIh4fHYWNj4//YMEgOpIYBBI4dO2ZhZmb2GV0RSAwkB1YEAkAdLO3t7TnoCkFiIDmoMggACgiEhoauhikCsUFiUGlUsHfvXkOYQhAbKowJQNbAFGJYiQ5gCqFc3ACkyNfXdzuUixuAFAGt1YByoYCBAQAUDanUpFB4UQAAAABJRU5ErkJggg==') no-repeat; } +table.grid-table .grid-filter-buttons { padding: 0; } +table.grid-table .grid-filter-datepicker { font-size: 12px; } + table.grid-table .grid-filter-datepicker table td { padding: 1px!important; } + table.grid-table .grid-filter-datepicker .ui-datepicker { width: auto; } +table.grid-table .grid-dropdown-inner ul.menu-list li a.grid-filter-clear { white-space: nowrap; padding-left: 23px; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAMCAYAAABbayygAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAARpJREFUKFNjYGj//58o/P//fwdiMIOkpKQ/VhOQMFgNULWIh4fHYWNj4//YMEgOpIYBBI4dO2axOC/396GinP/O+vpwRVbGxl92+vluXm1kuASsEKiD5VB99aG3eTH/HxjL/A/RUPsfrqb6f7e21uutlhbRYEUwAFQskOLmun2+lND/0xxM/7dycXzd6OxoCpVGBduWLjXv4+f/v5WF+f9RbtYvfeysqlApBKhhY2Hcxsy0+xAL038nbe3/m8W4ss/Jcx2GSiPAal6uvGtczP9TFOXBHgGJ7RHlmLGOjy0UrAAGzgT7rn7urP/P3NDgv6+v73aQWAMzM+dqTtbJYAUwsNzeyuhImE8GSBHQYxpQYYYJQCcxMDAwAAB7/bt5uWh9FAAAAABJRU5ErkJggg=='); background-position: 3px center; background-repeat: no-repeat; } +table.grid-table .grid-filter-choose.choose-selected { background-color: white!important; cursor: default; color: #999; } +table.grid-table .grid-popup-additional { padding: 3px 0 0 0; } + +/* POP-UP */ +.grid-dropdown { font-weight: normal; left: -102px; top: 16px!important; min-width: 180px; } +.grid-dropdown-arrow { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAICAYAAADJEc7MAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAl0lEQVQoU42PMQuFMAyE6xN5gpOjjsIb/P9/o3O3zh27dY25kIPq8DBwmLT35WoQkUEVOmGec84CaW2q7+N+AdCD6M9SisQYTei1jsfyCeCu+vjFVGs1AN++94DRfUOfuNLoKUiyRC5y2F5I8NdaM4P/l0EswvBorQTnfxBhLMRih+2pklIy+eEtjQPu6MNZwIBNbwteMBd5X4ZGHcwL3QAAAABJRU5ErkJggg==") no-repeat; height: 8px; left: 99px; position: absolute; top: -8px; width: 14px; } +.grid-dropdown-inner { padding: 5px 7px; } +.grid-dropdown ul.menu-list { list-style-type: none; margin: 3px 0 0 0; padding: 0; } + .grid-dropdown ul.menu-list li a { text-decoration: none; background-position: 6px center; background-repeat: no-repeat; display: block; padding: 4px 5px; } + .grid-dropdown ul.menu-list li a:hover { background-color: #EEE; text-decoration: none; } diff --git a/StockManMVC/Content/PagedList.css b/StockManMVC/Content/PagedList.css new file mode 100644 index 0000000..d9b9f5d --- /dev/null +++ b/StockManMVC/Content/PagedList.css @@ -0,0 +1,166 @@ +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} + +.pagination > li { + display: inline; +} + +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} + +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} + +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} + +.pagination > .disabled > span, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; + border-color: #dddddd; +} + +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} + +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} + +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} + +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} + +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager:before, +.pager:after { + display: table; + content: " "; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: not-allowed; + background-color: #ffffff; +} \ No newline at end of file diff --git a/StockManMVC/Controllers/ItemStockStatusController.cs b/StockManMVC/Controllers/ItemStockStatusController.cs index 34184a3..25bfd9b 100644 --- a/StockManMVC/Controllers/ItemStockStatusController.cs +++ b/StockManMVC/Controllers/ItemStockStatusController.cs @@ -7,6 +7,7 @@ using System.Net; using System.Web; using System.Web.Mvc; using StockManMVC.Models; +using X.PagedList; namespace StockManMVC.Controllers { diff --git a/StockManMVC/Controllers/ItemsController.cs b/StockManMVC/Controllers/ItemsController.cs index ef474b0..bb2b8be 100644 --- a/StockManMVC/Controllers/ItemsController.cs +++ b/StockManMVC/Controllers/ItemsController.cs @@ -21,6 +21,22 @@ namespace StockManMVC.Controllers return View(item.ToList()); } + + public ActionResult Grid() + { + + StockManEntities GVDB = new StockManEntities(); + + var ItemList = (from art in GVDB.Item + select art).ToList(); + + + return View(ItemList); + + //var item = db.Item.Include(i => i.ItemFamily); + //return View(item.ToList()); + } + // GET: Items/Details/5 public ActionResult Details(int? id) { diff --git a/StockManMVC/Grid.mvc.readme b/StockManMVC/Grid.mvc.readme new file mode 100644 index 0000000..d9b0089 --- /dev/null +++ b/StockManMVC/Grid.mvc.readme @@ -0,0 +1,60 @@ +http://gridmvc.codeplex.com/ + +Note: Grid.Mvc installer has already made the following changes to your project: +- Views/Shared/_Grid.cshtml, Views/Shared/_GridPager.cshtml - views for grid +- Content/Gridmvc.css - default stylesheet for the grid +- Scripts/gridmvc.js, Scripts/gridmvc.min.js - Grid.Mvc scripts +- Reference GridMvc.dll + +Follow these steps to start use Grid.mvc: + +1. Define a model for display in the grid, like: + + public class Foo + { + public string Title { get; set; } + public string Description { get;set; } + } + + +2. Prepare your model in your controller, like: + + public ActionResult Index() + { + var items = fooRepository.GetAll(); + return View(items); + } + + +3. Render GridMvc in the View: You can use Html helper extenstion: + + Reference Grid.Mvc.Html in your view: + + @using GridMvc.Html + + Render Grid.Mvc: + + @Html.Grid(Model).Columns(columns => + { + columns.Add(foo => foo.Title).Titled("Custom column title").SetWidth(110); + columns.Add(foo => foo.Description).Sortable(true); + }).WithPaging(20) + + +4. Register a grid stylesheet and scripts in your _Layouts.cshtml file: + + + + + +Notes: + +Default layout of Grid.Mvc uses Twitter Bootstrap (css framework). You also need to include stylesheets on your page. You can download it from - http://twitter.github.com/bootstrap/ +like: + + + + +Also you need to ensure that jQuery has registred on the page before gridmvc.min.js script. + +For more documetation, please see: http://gridmvc.codeplex.com/ \ No newline at end of file diff --git a/StockManMVC/Scripts/_references.js b/StockManMVC/Scripts/_references.js index 4630fa3..585e185 100644 Binary files a/StockManMVC/Scripts/_references.js and b/StockManMVC/Scripts/_references.js differ diff --git a/StockManMVC/Scripts/gridmvc.js b/StockManMVC/Scripts/gridmvc.js new file mode 100644 index 0000000..2f892f5 --- /dev/null +++ b/StockManMVC/Scripts/gridmvc.js @@ -0,0 +1,724 @@ +/*** +* Grid.Mvc +* Examples and documentation at: http://gridmvc.codeplex.com +* Version: 3.0.0 +* Requires: window.jQuery v1.3+ +* LGPL license: http://gridmvc.codeplex.com/license +*/ +window.pageGrids = window.pageGrids || {}; +$.fn.extend({ + gridmvc: function () { + var aObj = []; + $(this).each(function () { + if (!$(this).data("gridmvc")) { + var options = { lang: $(this).attr("data-lang"), selectable: $(this).attr("data-selectable") == "true", multiplefilters: $(this).attr("data-multiplefilters") == "true" }; + var grid = new GridMvc(this, options); + var name = $(this).attr("data-gridname"); + if (name.length > 0) + window.pageGrids[$(this).attr("data-gridname")] = grid; + + aObj.push(grid); + $(this).data("gridmvc", grid); + } else { + aObj.push($(this).data("gridmvc")); + } + }); + if (aObj.length == 1) + return aObj[0]; + return aObj; + } +}); + +GridMvc = (function ($) { + function gridMvc(container, options) { + this.jqContainer = $(container); + options = options || {}; + this.options = $.extend({}, this.defaults(), options); + this.init(); + } + + gridMvc.prototype.init = function () { + //load current lang options: + this.lang = GridMvc.lang[this.options.lang]; + if (typeof (this.lang) == 'undefined') + this.lang = GridMvc.lang.en; + this.events = []; + if (this.options.selectable) + this.initGridRowsEvents(); + //Register default filter widgets: + this.filterWidgets = []; + this.addFilterWidget(new TextFilterWidget()); + this.addFilterWidget(new NumberFilterWidget()); + this.addFilterWidget(new DateTimeFilterWidget()); + this.addFilterWidget(new BooleanFilterWidget()); + + this.openedMenuBtn = null; + this.initFilters(); + }; + /*** + * Handle Grid row events + */ + gridMvc.prototype.initGridRowsEvents = function () { + var $this = this; + this.jqContainer.on("click", ".grid-row", function () { + $this.rowClicked.call(this, $this); + }); + }; + /*** + * Trigger on Grid row click + */ + gridMvc.prototype.rowClicked = function ($context) { + if (!$context.options.selectable) + return; + var row = $(this).closest(".grid-row"); + if (row.length <= 0) + return; + var gridRow = {}; + row.find(".grid-cell").each(function () { + var columnName = $(this).attr("data-name"); + if (columnName.length > 0) + gridRow[columnName] = $(this).text(); + }); + var evt = $.Event("RowClicked"); + $context.notifyOnRowSelect(gridRow, evt); + if (!evt.isDefaultPrevented()) + $context.markRowSelected(row); + }; + /*** + * Mark Grid row as selected + */ + gridMvc.prototype.markRowSelected = function (row) { + this.jqContainer.find(".grid-row.grid-row-selected").removeClass("grid-row-selected"); + row.addClass("grid-row-selected"); + }; + /*** + * Default Grid.Mvc options + */ + gridMvc.prototype.defaults = function () { + return { + selectable: true, + multiplefilters: false, + lang: 'en' + }; + }; + /*** + * ============= EVENTS ============= + * Methods that provides functionality for grid events + */ + gridMvc.prototype.onRowSelect = function (func) { + this.events.push({ name: "onRowSelect", callback: func }); + }; + + gridMvc.prototype.notifyOnRowSelect = function (row, e) { + e.row = row; + this.notifyEvent("onRowSelect", e); + }; + + gridMvc.prototype.notifyEvent = function (eventName, e) { + for (var i = 0; i < this.events.length; i++) { + if (this.events[i].name == eventName) + if (!this.events[i].callback(e)) break; + } + }; + /*** + * ============= FILTERS ============= + * Methods that provides functionality for filtering + */ + /*** + * Method search all filter buttons and register 'onclick' event handlers: + */ + gridMvc.prototype.initFilters = function () { + var filterHtml = this.filterMenuHtml(); + var self = this; + this.jqContainer.find(".grid-filter").each(function () { + $(this).click(function () { + return self.openFilterPopup.call(this, self, filterHtml); + }); + }); + }; + /*** + * Shows filter popup window and render filter widget + */ + gridMvc.prototype.openFilterPopup = function (self, html) { + //retrive all column filter parameters from html attrs: + var columnType = $(this).attr("data-type") || ""; + //determine widget + var widget = self.getFilterWidgetForType(columnType); + //if widget for specified column type not found - do nothing + if (widget == null) + return false; + + //if widget allready rendered - just open popup menu: + if (this.hasAttribute("data-rendered")) { + var or = self.openMenuOnClick.call(this, self); + self.setupPopupInitialPosition($(this)); + if (!or && typeof (widget.onShow) != 'undefined') + widget.onShow(); + return or; + } + + var columnName = $(this).attr("data-name") || ""; + var filterData = $(this).attr("data-filterdata") || ""; + var widgetData = $(this).attr("data-widgetdata") || "{}"; + var filterDataObj = self.parseFilterValues(filterData) || {}; + var filterUrl = $(this).attr("data-url") || ""; + + //mark filter as rendered + $(this).attr("data-rendered", "1"); + //append base popup layout: + $(this).append(html); + + //determine widget container: + var widgetContainer = $(this).find(".grid-popup-widget"); + //onRender target widget + if (typeof (widget.onRender) != 'undefined') + widget.onRender(widgetContainer, self.lang, columnType, filterDataObj, function (values) { + self.closeOpenedPopups(); + self.applyFilterValues(filterUrl, columnName, values, false); + }, $.parseJSON(widgetData)); + //adding 'clear filter' button if needed: + if ($(this).find(".grid-filter-btn").hasClass("filtered") && widget.showClearFilterButton()) { + var inner = $(this).find(".grid-popup-additional"); + inner.append(self.getClearFilterButton(filterUrl)); + inner.find(".grid-filter-clear").click(function () { + self.applyFilterValues(filterUrl, columnName, "", true); + }); + } + var openResult = self.openMenuOnClick.call(this, self); + if (typeof (widget.onShow) != 'undefined') + widget.onShow(); + self.setupPopupInitialPosition($(this)); + return openResult; + }; + + gridMvc.prototype.setupPopupInitialPosition = function (popup) { + var drop = popup.find(".grid-dropdown"); + function getInfo() { + var arrow = popup.find(".grid-dropdown-arrow"); + return { arrow: arrow, currentDropLeft: parseInt(drop.css("left")), currentArrowLeft: parseInt(arrow.css("left")) }; + } + var dropLeft = drop.offset().left; + if (dropLeft < 0) { + var info = getInfo(); + info.arrow.css({ left: (info.currentArrowLeft + dropLeft - 10) + "px" }); + drop.css({ left: (info.currentDropLeft - dropLeft + 10) + "px" }); + return; + } + var dropWidth = drop.width(); + var offsetRight = $(window).width() - (dropLeft + dropWidth); + if (offsetRight < 0) { + var info = getInfo(); + info.arrow.css({ left: (info.currentArrowLeft - offsetRight + 10) + "px" }); + drop.css({ left: (info.currentDropLeft + offsetRight - 10) + "px" }); + } + }; + /*** + * Returns layout of filter popup menu + */ + gridMvc.prototype.filterMenuHtml = function () { + return ''; + }; + /*** + * Returns layout of 'clear filter' button + */ + gridMvc.prototype.getClearFilterButton = function () { + return ''; + }; + /*** + * Register filter widget in widget collection + */ + gridMvc.prototype.addFilterWidget = function (widget) { + this.filterWidgets.push(widget); + }; + /*** + * Parse filter settings from data attribute + */ + gridMvc.prototype.parseFilterValues = function (filterData) { + var opt = $.parseJSON(filterData); + var filters = []; + for (var i = 0; i < opt.length; i++) { + filters.push({ filterValue: this.urldecode(opt[i].FilterValue), filterType: opt[i].FilterType, columnName: opt[i].ColumnName }); + } + return filters; + }; + + gridMvc.prototype.urldecode = function (str) { + return decodeURIComponent((str + '').replace(/\+/g, '%20')); + }; + + /*** + * Return registred widget for specific column type name + */ + gridMvc.prototype.getFilterWidgetForType = function (typeName) { + for (var i = 0; i < this.filterWidgets.length; i++) { + if ($.inArray(typeName, this.filterWidgets[i].getAssociatedTypes()) >= 0) + return this.filterWidgets[i]; + } + return null; + }; + /*** + * Replace existed filter widget + */ + gridMvc.prototype.replaceFilterWidget = function (typeNameToReplace, widget) { + for (var i = 0; i < this.filterWidgets.length; i++) { + if ($.inArray(typeNameToReplace, this.filterWidgets[i].getAssociatedTypes()) >= 0) { + this.filterWidgets.splice(i, 1); + this.addFilterWidget(widget); + return true; + } + } + return false; + }; + /*** + * Applies selected filter value by redirecting to another url: + */ + gridMvc.prototype.applyFilterValues = function (initialUrl, columnName, values, skip) { + var filters = this.jqContainer.find(".grid-filter"); + if (initialUrl.length > 0) + initialUrl += "&"; + + var url = ""; + if (!skip) { + url += this.getFilterQueryData(columnName, values); + } + + if (this.options.multiplefilters) { //multiple filters enabled + for (var i = 0; i < filters.length; i++) { + if ($(filters[i]).attr("data-name") != columnName) { + var filterData = this.parseFilterValues($(filters[i]).attr("data-filterdata")); + if (filterData.length == 0) continue; + if (url.length > 0) url += "&"; + url += this.getFilterQueryData($(filters[i]).attr("data-name"), filterData); + } else { + continue; + } + } + } + + window.location.search = initialUrl + url; + }; + gridMvc.prototype.getFilterQueryData = function (columnName, values) { + var url = ""; + for (var i = 0; i < values.length; i++) { + url += "grid-filter=" + encodeURIComponent(columnName) + "__" + values[i].filterType + "__" + encodeURIComponent(values[i].filterValue); + if (i != values.length - 1) + url += "&"; + } + return url; + }; + /*** + * ============= POPUP MENU ============= + * Methods that provides base functionality for popup menus + */ + gridMvc.prototype.openMenuOnClick = function (self) { + if ($(this).hasClass("clicked")) return true; + self.closeOpenedPopups(); + $(this).addClass("clicked"); + var popup = $(this).find(".dropdown-menu"); + if (popup.length == 0) return true; + popup.show(); + popup.addClass("opened"); + self.openedMenuBtn = $(this); + $(document).bind("click.gridmvc", function (e) { + self.documentCallback(e, self); + }); + return false; + }; + + gridMvc.prototype.documentCallback = function (e, $context) { + e = e || event; + var target = e.target || e.srcElement; + var box = $(".dropdown-menu.opened").get(0); + var html = $("html").get(0); + if (typeof box != "undefined") { + do { + if (box == target) { + // Click occured inside the box, do nothing. + return; + } + if (html == target) { + box.style.display = "none"; + $(box).removeClass("opened"); + } + target = target.parentNode; + } while (target); // Click was outside the box, hide it. + + } + if ($context.openedMenuBtn != null) + $context.openedMenuBtn.removeClass("clicked"); + $(document).unbind("click.gridmvc"); + }; + + gridMvc.prototype.closeOpenedPopups = function () { + var openedPopup = $(".dropdown-menu.opened"); + openedPopup.hide(); + openedPopup.removeClass("opened"); + if (this.openedMenuBtn != null) + this.openedMenuBtn.removeClass("clicked"); + }; + + /* Grid.Mvc clients functions */ + + gridMvc.prototype.selectable = function (enable) { + this.options.selectable = enable; + }; + + return gridMvc; +})(window.jQuery); + +/*** +* ============= LOCALIZATION ============= +* You can localize Grid.Mvc by creating localization files and include it on the page after this script file +* This script file provides localization only for english language. +* For more documentation see: http://gridmvc.codeplex.com/documentation +*/ +if (typeof (GridMvc.lang) == 'undefined') + GridMvc.lang = {}; +GridMvc.lang.en = { + filterTypeLabel: "Type: ", + filterValueLabel: "Value:", + applyFilterButtonText: "Apply", + filterSelectTypes: { + Equals: "Equals", + StartsWith: "StartsWith", + Contains: "Contains", + EndsWith: "EndsWith", + GreaterThan: "Greater than", + LessThan: "Less than" + }, + code: 'en', + boolTrueLabel: "Yes", + boolFalseLabel: "No", + clearFilterLabel: "Clear filter" +}; +/*** +* ============= FILTER WIDGETS ============= +* Filter widget allows onRender custom filter user interface for different columns. +* For example if your added column is of type "DateTime" - widget can onRender calendar for picking filter value. +* This script provider base widget for default .Net types: System.String, System.Int32, System.Decimal etc. +* If you want to provide custom filter functionality - you can assign your own widget type for column and write widget for this types. +* For more documentation see: http://gridmvc.codeplex.com/documentation +*/ + +/*** +* TextFilterWidget - Provides filter interface for text columns (of type "System.String") +* This widget onRenders filter interface with conditions, which specific for text types: contains, starts with etc. +*/ +TextFilterWidget = (function ($) { + function textFilterWidget() { } + /*** + * This method must return type of columns that must be associated with current widget + * If you not specify your own type name for column (see 'SetFilterWidgetType' method), GridMvc setup column type name from .Net type ("System.DateTime etc.) + */ + textFilterWidget.prototype.getAssociatedTypes = function () { return ["System.String"]; }; + /*** + * This method invokes when filter widget was shown on the page + */ + textFilterWidget.prototype.onShow = function () { + var textBox = this.container.find(".grid-filter-input"); + if (textBox.length <= 0) return; + textBox.focus(); + }; + /*** + * This method specify whether onRender 'Clear filter' button for this widget. + */ + textFilterWidget.prototype.showClearFilterButton = function () { return true; }; + /*** + * This method will invoke when user first clicked on filter button. + * container - html element, which must contain widget layout; + * lang - current language settings; + * typeName - current column type (if widget assign to multipile types, see: getAssociatedTypes); + * filterType - current filter type (like equals, starts with etc); + * filterValue - current filter value; + * cb - callback function that must invoked when user want to filter this column. Widget must pass filter type and filter value. + */ + textFilterWidget.prototype.onRender = function (container, lang, typeName, values, cb) { + this.cb = cb; + this.container = container; + this.lang = lang; + this.value = values.length > 0 ? values[0] : { filterType: 1, filterValue: "" };//support only one filter value + this.renderWidget(); + this.registerEvents(); + }; + /*** + * Internal method that build widget layout and append it to the widget container + */ + textFilterWidget.prototype.renderWidget = function () { + var html = '
\ + \ + \ +
\ +
\ + \ + \ +
\ +
\ + \ +
'; + this.container.append(html); + }; + /*** + * Internal method that register event handlers for 'apply' button. + */ + textFilterWidget.prototype.registerEvents = function () { + //get apply button from: + var applyBtn = this.container.find(".grid-apply"); + //save current context: + var $context = this; + //register onclick event handler + applyBtn.click(function () { + //get selected filter type: + var type = $context.container.find(".grid-filter-type").val(); + //get filter value: + var value = $context.container.find(".grid-filter-input").val(); + //invoke callback with selected filter values: + var filterValues = [{ filterType: type, filterValue: value }]; + $context.cb(filterValues); + }); + //register onEnter event for filter text box: + this.container.find(".grid-filter-input").keyup(function (event) { + if (event.keyCode == 13) { applyBtn.click(); } + if (event.keyCode == 27) { GridMvc.closeOpenedPopups(); } + }); + }; + + return textFilterWidget; +})(window.jQuery); + +/*** +* NumberFilterWidget - Provides filter interface for number columns +* This widget onRenders filter interface with conditions, which specific for number types: great than, less that etc. +* Also validates user's input for digits +*/ +NumberFilterWidget = (function ($) { + + function numberFilterWidget() { } + + numberFilterWidget.prototype.showClearFilterButton = function () { return true; }; + + numberFilterWidget.prototype.getAssociatedTypes = function () { + return ["System.Int32", "System.Double", "System.Decimal", "System.Byte", "System.Single", "System.Float", "System.Int64"]; + }; + + numberFilterWidget.prototype.onShow = function () { + var textBox = this.container.find(".grid-filter-input"); + if (textBox.length <= 0) return; + textBox.focus(); + }; + + numberFilterWidget.prototype.onRender = function (container, lang, typeName, values, cb) { + this.cb = cb; + this.container = container; + this.lang = lang; + this.typeName = typeName; + this.value = values.length > 0 ? values[0] : { filterType: 1, filterValue: "" };//support only one filter value + this.renderWidget(); + this.registerEvents(); + }; + + numberFilterWidget.prototype.renderWidget = function () { + var html = '
\ + \ + \ +
\ +
\ + \ + \ +
\ +
\ + \ +
'; + this.container.append(html); + }; + + numberFilterWidget.prototype.registerEvents = function () { + var $context = this; + var applyBtn = this.container.find(".grid-apply"); + applyBtn.click(function () { + var type = $context.container.find(".grid-filter-type").val(); + var value = $context.container.find(".grid-filter-input").val(); + var filters = [{ filterType: type, filterValue: value }]; + $context.cb(filters); + }); + var txt = this.container.find(".grid-filter-input"); + txt.keyup(function (event) { + if (event.keyCode == 13) { applyBtn.click(); } + if (event.keyCode == 27) { GridMvc.closeOpenedPopups(); } + }) + .keypress(function (event) { return $context.validateInput.call($context, event); }); + if (this.typeName == "System.Byte") + txt.attr("maxlength", "3"); + }; + + numberFilterWidget.prototype.validateInput = function (evt) { + var $event = evt || window.event; + var key = $event.keyCode || $event.which; + key = String.fromCharCode(key); + var regex; + switch (this.typeName) { + case "System.Byte": + case "System.Int32": + case "System.Int64": + regex = /[0-9]/; + break; + default: + regex = /[0-9]|\.|\,/; + } + if (!regex.test(key)) { + $event.returnValue = false; + if ($event.preventDefault) $event.preventDefault(); + } + }; + + return numberFilterWidget; +})(window.jQuery); + +/*** +* DateTimeFilterWidget - Provides filter interface for date columns (of type "System.DateTime"). +* If datepicker script included, this widget will render calendar for pick filter values +* In other case he onRender textbox field for specifing date value (more info at http://window.jQueryui.com/) +*/ +DateTimeFilterWidget = (function ($) { + + function dateTimeFilterWidget() { } + + dateTimeFilterWidget.prototype.getAssociatedTypes = function () { return ["System.DateTime"]; }; + + dateTimeFilterWidget.prototype.showClearFilterButton = function () { return true; }; + + dateTimeFilterWidget.prototype.onRender = function (container, lang, typeName, values, applycb, data) { + this.datePickerIncluded = typeof ($.fn.datepicker) != 'undefined'; + this.cb = applycb; + this.data = data; + this.container = container; + this.lang = lang; + this.value = values.length > 0 ? values[0] : { filterType: 1, filterValue: "" };//support only one filter value + this.renderWidget(); + this.registerEvents(); + }; + + dateTimeFilterWidget.prototype.renderWidget = function () { + var html = '
\ + \ + \ +
' + + (this.datePickerIncluded ? + '
' + : + '
\ + \ + \ +
\ +
\ + \ +
'); + this.container.append(html); + //if window.jQueryUi included: + if (this.datePickerIncluded) { + var datePickerOptions = this.data || {}; + datePickerOptions.format = datePickerOptions.format || "yyyy-mm-dd"; + datePickerOptions.language = datePickerOptions.language || this.lang.code; + + var $context = this; + var dateContainer = this.container.find(".grid-filter-datepicker"); + dateContainer.datepicker(datePickerOptions).on('changeDate', function (ev) { + var type = $context.container.find(".grid-filter-type").val(); + var filterValues = [{ filterType: type, filterValue: ev.format() }]; + $context.cb(filterValues); + }); + if (this.value.filterValue) + dateContainer.datepicker('update', this.value.filterValue); + } + }; + + dateTimeFilterWidget.prototype.registerEvents = function () { + var $context = this; + var applyBtn = this.container.find(".grid-apply"); + applyBtn.click(function () { + var type = $context.container.find(".grid-filter-type").val(); + var value = $context.container.find(".grid-filter-input").val(); + var filterValues = [{ filterType: type, filterValue: value }]; + $context.cb(filterValues); + }); + this.container.find(".grid-filter-input").keyup(function (event) { + if (event.keyCode == 13) { + applyBtn.click(); + } + }); + }; + + return dateTimeFilterWidget; +})(window.jQuery); + +/*** +* BooleanFilterWidget - Provides filter interface for boolean columns (of type "System.Boolean"). +* Renders two button for filter - true and false +*/ +BooleanFilterWidget = (function ($) { + + function booleanFilterWidget() { } + + booleanFilterWidget.prototype.getAssociatedTypes = function () { return ["System.Boolean"]; }; + + booleanFilterWidget.prototype.showClearFilterButton = function () { return true; }; + + booleanFilterWidget.prototype.onRender = function (container, lang, typeName, values, cb) { + this.cb = cb; + this.container = container; + this.lang = lang; + this.value = values.length > 0 ? values[0] : { filterType: 1, filterValue: "" };//support only one filter value + this.renderWidget(); + this.registerEvents(); + }; + + booleanFilterWidget.prototype.renderWidget = function () { + var html = '\ + '; + this.container.append(html); + }; + + booleanFilterWidget.prototype.registerEvents = function () { + var $context = this; + var applyBtn = this.container.find(".grid-filter-choose"); + applyBtn.click(function () { + var filterValues = [{ filterType: "1", filterValue: $(this).attr("data-value") }]; + $context.cb(filterValues); + }); + }; + + return booleanFilterWidget; +})(window.jQuery); + +//startup init: +(function ($) { + if (!$) return;//jquery not referenced + $(function () { + $(".grid-mvc").each(function () { + $(".grid-mvc").gridmvc(); + }); + }); +})(window.jQuery); \ No newline at end of file diff --git a/StockManMVC/Scripts/gridmvc.lang.ru.js b/StockManMVC/Scripts/gridmvc.lang.ru.js new file mode 100644 index 0000000..f006684 --- /dev/null +++ b/StockManMVC/Scripts/gridmvc.lang.ru.js @@ -0,0 +1,22 @@ +/*** +* Grid.Mvc russian language (ru-RU) http://gridmvc.codeplex.com/ +*/ +window.GridMvc = window.GridMvc || {}; +window.GridMvc.lang = window.GridMvc.lang || {}; +GridMvc.lang.ru = { + filterTypeLabel: "Тип фильтра: ", + filterValueLabel: "Значение:", + applyFilterButtonText: "Применить", + filterSelectTypes: { + Equals: "Равно", + StartsWith: "Начинается с", + Contains: "Содержит", + EndsWith: "Оканчивается", + GreaterThan: "Больше", + LessThan: "Меньше" + }, + code: 'ru', + boolTrueLabel: "Да", + boolFalseLabel: "Нет", + clearFilterLabel: "Очистить фильтр" +}; \ No newline at end of file diff --git a/StockManMVC/Scripts/gridmvc.min.js b/StockManMVC/Scripts/gridmvc.min.js new file mode 100644 index 0000000..868c6af --- /dev/null +++ b/StockManMVC/Scripts/gridmvc.min.js @@ -0,0 +1 @@ +window.pageGrids=window.pageGrids||{},$.fn.extend({gridmvc:function(){var n=[];return($(this).each(function(){if($(this).data("gridmvc"))n.push($(this).data("gridmvc"));else{var i={lang:$(this).attr("data-lang"),selectable:$(this).attr("data-selectable")=="true",multiplefilters:$(this).attr("data-multiplefilters")=="true"},t=new GridMvc(this,i),r=$(this).attr("data-gridname");r.length>0&&(window.pageGrids[$(this).attr("data-gridname")]=t),n.push(t),$(this).data("gridmvc",t)}}),n.length==1)?n[0]:n}}),GridMvc=function(n){function t(t,i){this.jqContainer=n(t),i=i||{},this.options=n.extend({},this.defaults(),i),this.init()}return t.prototype.init=function(){this.lang=GridMvc.lang[this.options.lang],typeof this.lang=="undefined"&&(this.lang=GridMvc.lang.en),this.events=[],this.options.selectable&&this.initGridRowsEvents(),this.filterWidgets=[],this.addFilterWidget(new TextFilterWidget),this.addFilterWidget(new NumberFilterWidget),this.addFilterWidget(new DateTimeFilterWidget),this.addFilterWidget(new BooleanFilterWidget),this.openedMenuBtn=null,this.initFilters()},t.prototype.initGridRowsEvents=function(){var n=this;this.jqContainer.on("click",".grid-row",function(){n.rowClicked.call(this,n)})},t.prototype.rowClicked=function(t){var i,r,u;t.options.selectable&&((i=n(this).closest(".grid-row"),i.length<=0)||(r={},i.find(".grid-cell").each(function(){var t=n(this).attr("data-name");t.length>0&&(r[t]=n(this).text())}),u=n.Event("RowClicked"),t.notifyOnRowSelect(r,u),u.isDefaultPrevented()||t.markRowSelected(i)))},t.prototype.markRowSelected=function(n){this.jqContainer.find(".grid-row.grid-row-selected").removeClass("grid-row-selected"),n.addClass("grid-row-selected")},t.prototype.defaults=function(){return{selectable:!0,multiplefilters:!1,lang:"en"}},t.prototype.onRowSelect=function(n){this.events.push({name:"onRowSelect",callback:n})},t.prototype.notifyOnRowSelect=function(n,t){t.row=n,this.notifyEvent("onRowSelect",t)},t.prototype.notifyEvent=function(n,t){for(var i=0;i