zoukankan      html  css  js  c++  java
  • jQueryUI Plugin TableSorter的2个widget扩展

    因为项目需要对Table进行汇总以及定义列的显示隐藏,所以需要对jQueryUI的TableSorter进行扩展,下面2个插件是我写的,第一个是用显示/隐藏列(右键点击列头会出现右键菜单)。第二个是对列宽度的修正(可以忽略)。第三个是对数据进行汇总,再table footer处会显示汇总列)


    Widget的代码:

    ; (function ($) {
        "use strict";
    
        function getColumnsByIndex(table, iColIndex) {
            var expression = ':eq(' + iColIndex + ')';
            var $table = $(table);
            var $items = $table.find("tr").find('td' + expression);
            $.merge($items, $table.find('th' + expression));
            return $items;
        }
    
        function getColumnIndexById(table, colId) {
            return $(table).find("th").filter('[data-column-id="' + colId + '"]').index();
        }
    
        function getColumnsById(table, colId) {
            var index = getColumnIndexById(table, colId);
            return getColumnsByIndex(table, index);
        }
    
        function ColumnVisibilitySettings() {
            this.serialize = function (objSettings) {
                return {
                    version: "1",
                    visibilities: objSettings
                };
            };
            this.deserialize = function (jsonSettings) {
                if (jsonSettings) {
                    var version = jsonSettings.version;
                    var objSettings = {};
                    switch (version) {
                        case "1":
                            return jsonSettings.visibilities;
                    }
                }
    
                return undefined;
            };
        }
    
        $.tablesorter.addWidget({
            id: 'column-selector',
            priority: 51,   // Should be called later than filter
            options: {
                selector_contextmenu: '.tablesorter-context-menu'
            },
    
            m_config: null,
            m_widgetOptions: null,
            m_settingsLoaded: false,
    
            init: function (table, thisWidget, config, widgetOptions) {
                // widget initialization code - this is only *RUN ONCE*
                this.m_config = config;
                this.m_widgetOptions = widgetOptions;
    
                var self = this;
                var $table = config.$table;
    
                $(widgetOptions.selector_contextmenu).hide();
    
                $table.children('thead').bind("contextmenu", $.proxy(this.onShowContextMenu, this));
    
                // setup our event handler
                $table.on("save_column_visibility", $.proxy(this.saveColumnVisibility, this));
                $table.on("show_context_menu", $.proxy(this.onShowContextMenu, this));
            },
    
            format: function (table, config, widgetOptions) {
                // widget code to apply to the table *AFTER EACH SORT*
                if (!this.m_settingsLoaded) {
                    this.loadColumnVisibility();
                    this.m_settingsLoaded = true;
                }
            },
    
            remove: function (table, config, widgetOptions) {
                // do what ever needs to be done to remove stuff added by your widget
                // unbind events, restore hidden content, etc.
                $table.children('thead').unbind("contextmenu", $.proxy(this.onShowContextMenu, this));
    
                $table.off("save_column_visibility", $.proxy(this.saveColumnVisibility, this));
                $table.off("show_context_menu", $.proxy(this.onShowContextMenu, this));
            },
    
            onShowContextMenu: function (event, extraEvent) {
    
                // We allow to fack the event
                if (extraEvent) event = extraEvent;
    
                event.preventDefault();
    
                var self = this;
                var $table = this.m_config.$table;
                var $columnsUl = $('<ul></ul>');
                var $columns = $table.find("thead>tr>th");
                for (var i = 0; i < $columns.length; i++) {
    
                    var $column = $($columns[i]);
                    var columnDisplayName = $column.text();
                    var columnId = $column.data('column-id');
                    var columnIsFixed = $column.data('column-fixed');
                    if (!columnId) {
                        console.log("No column id avaliable. Cannot config columns!");
                        return;
                    }
                    
                    // Create li element
                    var $columnLi = $('<li></li>').appendTo($columnsUl);
    
                    // Create label for the checkbox
                    var $label = $('<label for="' + columnDisplayName + '"></label>')
                        .append($('<span>' + columnDisplayName + '</span>'))
                        .appendTo($columnLi);
    
                    // Create checkbox
                    var $checkbox = $('<input type="checkbox" />')
                        .attr('name', columnDisplayName)
                        .data('column-id', columnId)
                        .prependTo($label)
                        .click(function () {
                            var $clickedCheckbox = $(this);
                            var columnId = $clickedCheckbox.data('column-id');
                            var $columns = getColumnsById($table, columnId);
                            $columns.fadeToggle("fast");
                            self.saveColumnVisibility();
                        });
    
                    if (columnIsFixed)
                        $checkbox.attr('disabled', "disabled");
    
                    // Update checkbox state
                    if ($(":visible", $($columns[i])).length > 0) {
                        $checkbox.attr('checked', 'checked');
                    }
                }
    
                // Show context menu
                this.showContextMenu($columnsUl, event);
            },
    
            showContextMenu: function (contextMenuContent, event) {
                var contextMenu = $(this.m_widgetOptions.selector_contextmenu).hide().empty();
                contextMenu.append(contextMenuContent);
    
                // Marker
                $('<div />')
                    .css({
                        position: "fixed",
                        left: "0px",
                        top: "0px",
                         "100%",
                        height: "100%",
                        "z-index": "100"
                    })
                    .click(function () {
                        $(this).remove();
                        contextMenu.hide();
                    })
                    .bind('contextmenu', function () { return false; })
                    .appendTo(document.body);
    
                contextMenu.css({
                    left: event.pageX,
                    top: event.pageY,
                    "z-index": 101
                }).show();
            },
    
            loadColumnVisibility: function () {
                var $table = this.m_config.$table;
                var ts = $.tablesorter.storage;
                var jsonSettings = ts && ts(this.m_config.$table[0], "tablesorter-column-selector");
                var settings = new ColumnVisibilitySettings().deserialize(jsonSettings);
                if (settings) {
                    for (var col in settings) {
                        if (settings[col] === true) getColumnsById($table, col).show();
                        else getColumnsById($table, col).hide();
                    }
                }
            },
    
            saveColumnVisibility: function () {
                var $table = this.m_config.$table;
                var ts = $.tablesorter.storage;
                var settings = ts && ts(this.m_config.$table[0], "tablesorter-column-selector");
    
                if (ts) {
                    setTimeout(function () {
                        var visibilities = {};
                        $table.find("thead>tr>th").each(function (index) {
                            var $col = $(this);
                            visibilities[$col.data("column-id")] = ($col.css('display') !== "none");
                        });
                        ts($table[0], "tablesorter-column-selector", new ColumnVisibilitySettings().serialize(visibilities));
                    }, 1000);
                }
            },
        });
    
        $.tablesorter.addWidget({
            id: 'column-width-setter',
            priority: 81,   // Should be called later than filter
            options: {
            },
    
            m_config: null,
    
            init: function (table, thisWidget, config, widgetOptions) {
                this.m_config = config;
                this.resetColumnWidth();
            },
    
            resetColumnWidth: function () {
                var $columns = this.m_config.$headers;
                for (var i = 0; i < $columns.length; i++) {
                    var width = parseInt($($columns[i]).attr("data-width"));
                    if (width) {
                        getColumnsByIndex(this.m_config.$table, i).width(width);
                    }
                }
            }
        });
    
        $.tablesorter.addWidget({
            id: 'summery-row',
            options: {
                selector_summery_row: '.tablesorter-summery-row',
                selector_column_enable_summery: '.tablesorter-enable-summery',
                show_NaN: true
            },
    
            init: function (table, thisWidget, config, widgetOptions) {
                // widget initialization code - this is only *RUN ONCE*
                this.m_config = config;
                this.m_widgetOptions = widgetOptions;
                var $table = config.$table;
                $table.bind("filterEnd", $.proxy(this.updateSummeryRow, this));
                this.updateSummeryRow();
            },
    
            updateSummeryRow: function () {
                var self = this;
                var $table = this.m_config.$table;
                var summery = $table.find(this.m_widgetOptions.selector_summery_row)
                var $headers = $table.find("thead>tr>th");
                $headers.each(function (index) {
                    var $column = $(this);
                    if ($column.filter(self.m_widgetOptions.selector_column_enable_summery).length <= 0)
                        return;
                    var sum = 0;
                    var isPercentage = false;
                    var td = summery.find('td:eq(' + index + ')');
                    $table.find("tbody:not(" + self.m_widgetOptions.selector_summery_row + ")>tr:visible").find("td:eq(" + index + ")").each(function (index) {
                        var sVal = $(this).text();
                        if (sVal.indexOf("%") !== -1) {
                            isPercentage = true;
                        }
                        var iVal = parseFloat(sVal);
                        sum += iVal;
                    });
    
                    if (!isNaN(sum) || self.m_widgetOptions.show_NaN) {
                        if (isPercentage) {
                            td.text(sum.toFixed(2) + "%");
                        }
                        else {
                            td.text(sum);
                        }
                    }
                });
            }
        });
    
    })(jQuery);

    下面是在nodeJs的EJS模板里面的应用,支持右键点击列头以及左键点击Custom View按钮对显示的列进行定制:


    js_make_table_sortable代码:

    <!-- Require jQuery, jQueryUI -->
    <!-- Table should has id "data-table" -->
    
    <% include header_table %>
    <script class="code" type="text/javascript">
        $(document).ready(function () {
    
            // Make table sort-able
            {
                // Extend the themes to change any of the default class names ** NEW **
                $.extend($.tablesorter.themes.jui, {
                    // change default jQuery uitheme icons - find the full list of icons here: http://jqueryui.com/themeroller/ (hover over them for their name)
                    table: 'ui-widget ui-widget-content ui-corner-all', // table classes
                    header: 'ui-widget-header ui-corner-all ui-state-default', // header classes
                    footerRow: '',
                    footerCells: '',
                    icons: 'ui-icon', // icon class added to the <i> in the header
                    sortNone: 'ui-icon-carat-2-n-s',
                    sortAsc: 'ui-icon-carat-1-n',
                    sortDesc: 'ui-icon-carat-1-s',
                    active: 'ui-state-active', // applied when column is sorted
                    hover: 'ui-state-hover',  // hover class
                    filterRow: '',
                    even: 'ui-widget-content', // odd row zebra striping
                    odd: 'ui-state-default'   // even row zebra striping
                });
    
                var dataTable = $("#data-table");
    
                // call the tablesorter plugin and apply the ui theme widget
                dataTable.tablesorter({
                    theme: 'jui',
                    headerTemplate: '{content} {icon}',
                    widgets: ['uitheme', 'zebra', 'filter', 'column-selector', 'summery-row'],
                    widgetOptions: {
                        zebra: ["even", "odd"],
                    }
                });
            }
        });
    </script>
    


    EJS代码:

    <% include js_make_table_sortable %>
    <script class="code" type="text/javascript">
        $(document).ready(function () {
    
            var $table = $("#data-table");
    
            // Different View switch buttons
            $(".view-button[data-filter]").button().click(function () {
                var filter = $(this).data('filter');
    
                $table.find("th").each(function (index, header) {
                    var $header = $(header);
                    var index = $header.index();
    
                    if ($header.filter(filter).length > 0) {
                        $table.find("tr").find("td:eq(" + index + ")").show();
                        $header.show();
                    }
                    else {
                        $table.find("tr").find("td:eq(" + index + ")").hide();
                        $header.hide();
                    }
                });
    
                // Persist our settings
                $table.trigger("save_column_visibility");
            });
    
            $(".custom-view-button").button().click(function (event) {
                $table.trigger("show_context_menu", event);
            });
        });
    </script>
    
    <div id="table-container">
        <div class="tablesorter-context-menu" style="position: absolute;"></div>
        <div class="switch-view-area">
            <button class="view-button" data-filter=":not(false)">Full View</button>
            <button class="view-button" data-filter=".swd_view">SWD View</button>
            <button class="view-button" data-filter=".td_view">TD View</button>
            <button class="view-button" data-filter=".report_view">Report View</button>
            <button class="custom-view-button">Custom View</button>
        </div>
        <table id="data-table" class="tablesorter" style="max-1750px;">
            <caption><%= title %></caption>
            <thead>
                <tr>
                    <th class="report_view swd_view td_view" data-width="10px" data-column-id="Ranking">Ranking</th>
                    <th class="report_view swd_view td_view" data-width="10px" data-column-id="Bucket" data-column-fixed="true">Bucket</th>
                    <th class="report_view swd_view td_view" data-width="10px" data-column-id="Resolved">Resolved</th>
                    <th class="td_view" data-width="50px" data-column-id="PurportedlyFixedin">Purportedly Fixed in</th>
                    <th class="swd_view" data-width="100px" data-column-id="Notes">Notes</th>
                    <th class="tablesorter-enable-summery report_view swd_view" data-width="10px" data-column-id="CurrentReleaseCount">Current Release Count</th>
                    <th class="tablesorter-enable-summery report_view swd_view" data-width="10px" data-column-id="ofTotal">% of Total</th>
                    <th class="tablesorter-enable-summery swd_view" data-width="10px" data-column-id="UniqueUsers">Unique Users</th>
                    <th class="tablesorter-enable-summery swd_view" data-width="10px" data-column-id="NewReportsinThisWeek">New Reports in This Week</th>
                    <th class="tablesorter-enable-summery swd_view" data-width="10px" data-column-id="TotalCount">Total Count</th>
                    <th class="report_view swd_view td_view" data-width="10px" data-column-id="DefectId">Defect Id</th>
                    <th class="report_view td_view" data-width="400px" data-column-id="DefectStatus">Defect Status</th>
                    <th class="swd_view" data-width="20px" data-column-id="Module">Module</th>
                    <th class="swd_view" data-width="20px" data-column-id="Object">Object</th>
                    <th class="swd_view" data-width="20px" data-column-id="Function">Function</th>
                    <th class="swd_view" data-width="20px" data-column-id="Offset">Offset</th>
                </tr>
            </thead>
            <tbody>
                <% for (var i = 0; i < items.length; ++ i) { %>
                    <tr>
                        <td><%= i+1 %></td>
                        <td><%- link('http://xxxx.xxxx.com/cer/ViewBucket.aspx?bucket=' + items[i].bucketId, items[i].bucketId, "class='bucket-link' target='_blank'") %></td>
                        <td><%= items[i].isResolved ? "Yes" : "No" %></td>
                        <td><%= items[i].purportedlyFixedIn %></td>
                        <td><%= items[i].note %></td>
                        <td><%= items[i].currentReleaseCount %></td>
                        <td><%= (items[i].totalPercent*100).toFixed(2)+"%"  %></td>
                        <td><%= items[i].uniqueUsers %></td>
                        <td><%= items[i].newReportsInThisWeek %></td>
                        <td><%= items[i].totalCount %></td>
                        <td><%- splitDefectIds(items[i].defectId) %></td>
                        <td><%- formatDefectStatus(items[i].defectStatus) %></td>
                        <td><%= items[i].module %></td>
                        <td><%= items[i].object %></td>
                        <td><%= items[i].function %></td>
                        <td><%= items[i].offset %></td>
                    </tr>
                <% } %>
            </tbody>
            <tfoot>
                <tr class="tablesorter-summery-row">
                    <td>Sum</td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </tfoot>
        </table>
    </div>
    




  • 相关阅读:
    Python long() 函数
    Python frozenset() 函数
    java对象和构造方法的区别
    回顾方法和方法调用及加深
    面向过程&面向对象
    稀疏数组
    冒泡排序与八大排序
    Arrays类与常用功能
    二维数组的理解代码
    数组的使用
  • 原文地址:https://www.cnblogs.com/puncha/p/3876888.html
Copyright © 2011-2022 走看看