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>
    




  • 相关阅读:
    UVALive 6909 Kevin's Problem 数学排列组合
    UVALive 6908 Electric Bike dp
    UVALive 6907 Body Building tarjan
    UVALive 6906 Cluster Analysis 并查集
    八月微博
    hdu 5784 How Many Triangles 计算几何,平面有多少个锐角三角形
    hdu 5792 World is Exploding 树状数组
    hdu 5791 Two dp
    hdu 5787 K-wolf Number 数位dp
    hdu 5783 Divide the Sequence 贪心
  • 原文地址:https://www.cnblogs.com/puncha/p/3876888.html
Copyright © 2011-2022 走看看