Build: Add grunt build process

Rearranged, renamed & broke apart other files
This commit is contained in:
Mottie 2015-02-12 21:10:38 -06:00
parent 5263aa75ae
commit 2774abf8d8
45 changed files with 3260 additions and 703 deletions

1
.gitignore vendored
View File

@ -49,6 +49,7 @@ node_modules/
*_i.c
*_p.c
*.ilk
*.log
*.meta
*.obj
*.pch

325
Gruntfile.js Normal file
View File

@ -0,0 +1,325 @@
/*global module:false*/
module.exports = function( grunt ) {
'use strict';
var pkg = grunt.file.readJSON( 'package.json' ),
tasks,
widgetFilePrefix,
widgetFileSuffix,
defaults = {
dependencies : {
widgets: {
'saveSort resizable pager filter columnSelector' : 'storage',
'filter-formatter-html5 filter-formatter-jui filter-formatter-select2' : 'filter'
// 'stickyHeaders' : 'addResizeEvent' // included with stickyHeaders widget (for now)
}
},
standardWidgets: [
'storage', // req by saveSort; optional in others
'uitheme',
'columns',
'filter',
'stickyHeaders',
'resizable',
'saveSort'
// 'addResizeEvent', // included with stickyHeaders widget
// 'zeba' // included in core
]
},
// example widgets = [ 'pager','column', 'filter', 'stickyHeaders' ];
addWidgetDependencies = function(widgets) {
var indx, dep,
maxDeps = 40, // just in case (there are currently 27 widgets)
len = widgets.length,
deps = defaults.dependencies.widgets;
for ( dep in deps ) {
if ( typeof dep === 'string' ) {
for ( indx = 0; indx < len; indx++ ) {
// make sure indexOf is not matching "column" instead of "columnSelector" with surrounding spaces
if ( (' ' + dep + ' ').indexOf(' ' + widgets[indx] + ' ') >= 0 && widgets.indexOf( deps[dep] ) < 0 ) {
widgets.push( deps[dep] );
// keep checking newly added widgets, in case "filter" is added and "storage" hasn't been
if (len < maxDeps) { len++; }
continue;
}
}
}
}
return widgets;
},
formFileNames = function(){
// add widget path & file extension
pkg.processedWidgets = ( widgetFilePrefix +
pkg.selectedWidgets.join( widgetFileSuffix + ',' + widgetFilePrefix ) +
widgetFileSuffix ).split( ',' );
console.info( 'Creating a widgets file with: ' + pkg.selectedWidgets.join(', ') );
};
// minified banner template - updated 2/9/2015 (v2.19.1)
pkg.banner = '/*! <%= pkg.name %> (FORK) widgets - updated ' +
'<%= grunt.template.today("mm-dd-yyyy") %> (v<%= pkg.version %>)*/\n';
widgetFilePrefix = 'js/widgets/widget-';
widgetFileSuffix = '.js';
pkg.buildWidget = 'dist/js/jquery.tablesorter.widgets.js';
// Project configuration.
grunt.initConfig({
pkg: pkg,
clean: {
build: {
src: [ 'dist/**/**/**/*', 'dist/**/**/*', 'dist/**/*', 'dist' ]
},
cleancss: {
src: [ 'dist/temp/*', 'dist/temp', 'dist/css/*.css', '!dist/css/*.min.css' ]
}
},
copy: {
main: {
expand: true,
src: [
'js/jquery.*.js',
'!js/_test-*.js',
'!js/*.min.js',
],
dest: 'dist/',
filter: 'isFile'
},
css: {
files : [{
expand: true,
dot: true,
flatten: true,
src: ['css/*.css', 'addons/pager/*.css'],
dest: 'dist/temp/',
rename: function(dest, src) {
return dest + src.replace( /\./g, '+' ).replace( /\+css/g, '.css' );
}
}]
},
less: {
expand: true,
flatten: true,
src: 'css/*.less',
dest: 'dist/css/less/'
},
images: {
expand: true,
flatten: true,
src: [ 'addons/pager/icons/*', 'css/images/*' ],
dest: 'dist/css/images/'
},
fixnames: {
files : [{
expand: true,
dot: true,
flatten: true,
src: ['dist/temp/*.css'],
dest: 'dist/css/',
rename: function(dest, src) {
return dest + src.replace( /\+/g, '.' );
}
}]
}
},
concat: {
widgets: {
options: {
banner: '<%= pkg.banner %>/* Includes: <%= pkg.selectedWidgets %> */\n'
},
src: [
'<%= pkg.processedWidgets %>',
'!js/widgets/_test-*.js',
'!js/widgets/*.min.js'
],
dest: '<%= pkg.buildWidget %>'
},
// keep all the existing jsFiddle demos from breaking
copyback: {
options: {
banner: '/*** This file is dynamically generated ***\n' +
'█████▄ ▄████▄ █████▄ ▄████▄ ██████ ███████▄ ▄████▄ █████▄ ██ ██████ ██ ██\n' +
'██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n' +
'██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██\n' +
'█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀\n*/\n'
},
src : ['<%= pkg.buildWidget %>'],
dest: 'js/jquery.tablesorter.widgets.js'
}
},
jshint: {
files: {
src: [
'addons/pager/*.js',
'!addons/pager/*.min.js',
'js/jquery.*.js',
'js/**/*.js',
'!js/_test-*.js',
'!js/**/_test-*.js',
'!js/*.min.js',
'!js/**/semver*.js'
]
},
options: {
globals: {
"localStorage": false,
"navigator": false,
"console": false,
"alert": false
},
"loopfunc": true,
"jquery": true,
"browser": true
}
},
uglify: {
options: {
preserveComments: 'some',
report: 'gzip'
},
allFiles: {
files: [
{
expand: true,
cwd: './js/', // Src matches are relative to this path.
src: [
'*.js',
'**/*.js',
'!_test-*.js',
'!**/_test-*.js',
'!*.min.js',
'!**/semver.js'
],
dest: 'dist/js/',
ext: '.min.js', // Dist files will have this extension.
extDot: 'last' // Extensions in filenames begin after the first dot
}
]
},
pageraddon: {
files: {
'dist/js/extras/jquery.tablesorter.pager.min.js': [ 'addons/pager/*.js' ]
}
}
},
cssmin: {
target: {
files: [{
expand: true,
flatten: true,
cwd: 'dist/temp',
src: ['*.css'],
dest: 'dist/temp',
ext: '.min.css'
}]
}
},
qunit: {
files: [ 'test.html' ]
},
watch: {
scripts: {
files: [
'js/*.js',
'js/**/*.js',
'!js/_test-*.js',
'!js/*.min.js'
],
tasks: [ 'build' ]
}
}
});
grunt.loadNpmTasks( 'grunt-contrib-clean' );
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-contrib-qunit' );
grunt.loadNpmTasks( 'grunt-contrib-concat' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
grunt.loadNpmTasks( 'grunt-contrib-copy' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
grunt.registerTask( 'test', [ 'jshint', 'qunit' ] );
/* grunt-contrib-cssmin does not work with multiple periods in the file name.
* see https://github.com/gruntjs/grunt-contrib-cssmin/issues/175
* Css files are copied to 'dist/temp' folder & '.' are replaced with '+'.
* Css files are minified & copied to 'dist/css'.
* 'dist/temp' is deleted.
*/
tasks = [
'clean:build',
'copy:main',
'copy:css',
'copy:less',
'copy:images',
'concat',
'jshint',
'uglify',
'cssmin',
'copy:fixnames',
'clean:cleancss',
'updateManifest'
];
// basic = same as before: core, widgets, filterformatter all separate
grunt.registerTask( 'default', 'Default build', function(){
pkg.selectedWidgets = addWidgetDependencies( defaults.standardWidgets );
formFileNames();
grunt.task.run(tasks);
});
// enter "grunt custom:{filename}" (not including the ".json")
// to load in a custom json file
// the expected JSON format is (with custom widgets in a string):
// { "widgets" : "columnHighlight filter resizable saveSort stickyHeaders uitheme" }
grunt.registerTask( 'custom', 'Custom build', function(file){
var temp, deps = true;
/* Allow developer to set up a custom widget build (json file will have settings)*/
try {
temp = grunt.file.readJSON( file );
if (temp) {
deps = ('includeDependencies' in temp) ? temp.includeDependencies : true;
temp = temp.widgets.split(/\s+/);
}
} catch (err) {
grunt.log.error('Custom build json not found - Use "grunt custom:{filename}" (no .json ending)');
temp = defaults.standardWidgets;
}
// add dependencies
pkg.selectedWidgets = deps ? addWidgetDependencies( temp ) : temp;
formFileNames();
grunt.task.run(tasks);
});
// update bower.json & tablesorter.jquery.json file version numbers to match the package.json version
grunt.registerTask( 'updateManifest', function() {
var i, project,
projectFile = [ 'tablesorter.jquery.json', 'bower.json' ],
len = projectFile.length;
for ( i = 0; i < len; i++ ) {
if ( !grunt.file.exists( projectFile[ i ] ) ) {
grunt.log.error( "file " + projectFile[ i ] + " not found" );
return true; // return false to abort the execution
}
project = grunt.file.readJSON( projectFile[ i ] ); // get file as json object
project.version = pkg.version;
grunt.file.write( projectFile[i], JSON.stringify( project, null, 2 ) ); // serialize it back to file
}
});
};

View File

@ -4,5 +4,8 @@
"dependencies": {
"jquery": ">=1.2.6"
},
"main": "js/jquery.tablesorter.js"
"main": [
"js/jquery.tablesorter.js",
"js/jquery.tablesorter.widgets.js"
]
}

View File

@ -79,7 +79,7 @@
.tablesorter-blackice .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -114,7 +114,7 @@
.tablesorter-blue .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -78,7 +78,7 @@
.tablesorter-dark .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -81,7 +81,7 @@ Default Theme
.tablesorter-default .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -111,7 +111,7 @@
.tablesorter-dropbox .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -96,7 +96,7 @@
.tablesorter-green .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -132,7 +132,7 @@
.tablesorter-grey .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -88,7 +88,7 @@
.tablesorter-ice .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -71,7 +71,7 @@
.tablesorter-jui .tablesorter-processing .tablesorter-header-inner {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
}

View File

@ -79,7 +79,7 @@ Metro Dark Theme
.tablesorter-metro-dark .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
/* background-image: url(images/loading.gif) !important; */
background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important;
}

View File

@ -19,7 +19,7 @@
<!-- Tablesorter: optional -->
<script src="../addons/pager/jquery.tablesorter.pager.js"></script>
<script src="../js/jquery.metadata.js"></script>
<script src="../js/extras/jquery.metadata.js"></script>
<script>
// not sure why this is here...
@ -106,7 +106,7 @@
&lt;script src=&quot;../js/jquery.tablesorter.js&quot;&gt;&lt;/script&gt;
&lt;!-- Tablesorter: optional (but required for this demo) --&gt;
&lt;script src=&quot;../js/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/extras/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>Javascript</h1>
<div id="javascript">

View File

@ -16,7 +16,7 @@
<!-- Tablesorter: required -->
<link rel="stylesheet" href="../css/theme.blue.css">
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/jquery.metadata.js"></script>
<script src="../js/extras/jquery.metadata.js"></script>
<script src="../addons/pager/jquery.tablesorter.pager.js"></script>
<script id="js">$(function() {
@ -99,7 +99,7 @@
&lt;script src=&quot;../js/jquery.tablesorter.js&quot;&gt;&lt;/script&gt;
&lt;!-- Tablesorter: optional (but required for this demo) --&gt;
&lt;script src=&quot;../js/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/extras/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>Javascript</h1>
<div id="javascript">

View File

@ -18,7 +18,7 @@
<script src="../js/jquery.tablesorter.js"></script>
<!-- Tablesorter: optional (but required for this demo) -->
<script src="../js/jquery.metadata.js"></script>
<script src="../js/extras/jquery.metadata.js"></script>
<script id="js">$(function() {
// call the tablesorter plugin, the magic happens in the markup
@ -101,7 +101,7 @@
&lt;script src=&quot;../js/jquery.tablesorter.js&quot;&gt;&lt;/script&gt;
&lt;!-- Tablesorter: optional (but required for this demo) --&gt;
&lt;script src=&quot;../js/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/extras/jquery.metadata.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>Javascript</h1>
<div id="javascript">

View File

@ -374,7 +374,7 @@ td.pager {
<pre class="prettyprint lang-html">&lt;table class=&quot;tablesorter&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;td class=&quot;pager sorter-false&quot; colspan=&quot;5&quot;&gt;
&lt;td class=&quot;pager&quot; colspan=&quot;5&quot;&gt;
&lt;img src=&quot;../addons/pager/icons/first.png&quot; class=&quot;first&quot;/&gt;
&lt;img src=&quot;../addons/pager/icons/prev.png&quot; class=&quot;prev&quot;/&gt;
&lt;span class=&quot;pagedisplay&quot;&gt;&lt;/span&gt; &lt;!-- this can be any element, including an input --&gt;

View File

@ -34,7 +34,7 @@
<link href="../css/filter.formatter.css" rel="stylesheet">
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script src="../js/jquery.tablesorter.widgets-filter-formatter.js"></script>
<script src="../js/widgets/widget-filter-formatter-jui.js"></script>
<script>
$(function(){
@ -246,7 +246,7 @@
<li>In <span class="version">v2.10.1</span> the <code>compare</code> option was added. This allows comparing the slider's value to the column value. The slider in the Age column is selecting values greater than or equal to itself.</li>
<li>A search delay was added in v2.7.11 (time set by <code>filter_searchDelay</code> option). It can be disabled by setting the <code>delayed</code> option to <code>false</code>.<br><br></li>
<li>This example shows how you can add a jQuery UI slider to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.</li>
<li>Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.</li>
<li>Add the following code to apply a slider to filter a column:<pre class="prettyprint lang-javascript">$(function() {
@ -313,7 +313,7 @@
<div>
<ul>
<li>This example shows how you can add a jQuery UI range slider to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.</li>
<li>Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.</li>
<li>The range slider is actually the same as the single slider described above, but was built to handle a range of values.</li>
<li>Add the following code to apply a range slider to filter a column:<pre class="prettyprint lang-javascript">$(function() {
@ -359,7 +359,7 @@
<ul>
<li>In <span class="version">v2.15.0</span> the <code>compare</code> option was updated to allow adding a selector along with the input. The <code>selected</code> option allows choosing the default setting.<br><br></li>
<li>This example shows how you can add a jQuery UI spinner to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.</li>
<li>Add the following code to apply a spinner to filter a column:<pre class="prettyprint lang-javascript">$(function() {
$("table").tablesorter({
@ -413,7 +413,7 @@
<br>
</li>
<li>This example shows how you can add a jQuery UI Datepicker to compare to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.</li>
<li>This code follows the <a class="external" href="http://jqueryui.com/datepicker/#default">default functionality</a> example from the jQuery UI docs.</li>
<li>Add the following code to apply a datepicker comparison selector to the filter row:<pre class="prettyprint lang-javascript">$(function() {
@ -475,7 +475,7 @@
</li>
<li>In <span class="version">v2.15.0</span>, an <code>endOfDay</code> option was added, which when <code>true</code> and searching within one day, all times within that selected day will be included - try searching for <button data-column="5" data-value="1/20/2014 - 1/20/2014">1/20/2014 - 1/20/2014</button> to note that the day include various times.<br></li>
<li>This example shows how you can add a jQuery UI Datepicker range to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-jui.js" file is used to add this custom control within the filter row.</li>
<li>This code follows the <a class="external" href="http://jqueryui.com/datepicker/#date-range">date range</a> example from the jQuery UI docs.</li>
<li>Updated two input functions so that if the "to" input is empty, all dates greater than the "from" date are shown. If the "from" input is empty, all dates less than the "to" input date are shown (<span class="version updated">v2.10.1</span>).</li>
<li>Add the following code to apply a datepicker range selector to the filter row:<pre class="prettyprint lang-javascript">$(function() {
@ -608,7 +608,7 @@
&lt;!-- filter formatter code --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;../css/filter.formatter.css&quot;&gt;
&lt;script src=&quot;../js/jquery.tablesorter.widgets-filter-formatter.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/widgets/widget-filter-formatter-jui.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>CSS</h1>

View File

@ -20,7 +20,7 @@
<link href="../css/filter.formatter.css" rel="stylesheet">
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script src="../js/jquery.tablesorter.widgets-filter-formatter.js"></script>
<script src="../js/widgets/widget-filter-formatter-html5.js"></script>
<style id="css">/* css needed to get compare selector & slider in-line */
.compare-select-wrapper { width: 60%; float: right; }</style>
@ -140,7 +140,7 @@
<ul>
<li>In <span class="version">v2.15.0</span> the <code>compare</code> option was updated to allow adding a selector along with the input. The <code>selected</code> option allows choosing the default setting.</li>
<li>This example shows how you can add an HTML5 range input slider to filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-html5.js" file is used to add this custom control within the filter row.</li>
<li>Make sure to include all values within the selected range, otherwise rows outside of this range will be forever hidden.</li>
<li>Add the following code to apply an HTML5 range slider to the filter row:<pre class="prettyprint lang-javascript">$(function() {
@ -238,7 +238,7 @@
<ul>
<li>In <span class="version">v2.15.0</span> the <code>compare</code> option was updated to allow adding a selector along with the input. The <code>selected</code> option allows choosing the default setting.</li>
<li>This example shows how you can add an HTML5 number spinner to the filter column content.</li>
<li>The <code>filter_formatter</code> function provided in the extra "jquery.tablesorter.widgets-filter-formatter.js" file is used to add this custom control within the filter row.</li>
<li>The <code>filter_formatter</code> function provided in the extra "widget-filter-formatter-html5.js" file is used to add this custom control within the filter row.</li>
<li>Add the following code to apply an HTML spinner to filter a column:<pre class="prettyprint lang-javascript">$(function() {
$("table").tablesorter({
@ -328,7 +328,7 @@
&lt;!-- filter formatter code --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;../css/filter.formatter.css&quot;&gt;
&lt;script src=&quot;../js/jquery.tablesorter.widgets-filter-formatter.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/widgets/widget-filter-formatter-html5.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>Javascript</h1>
@ -350,4 +350,3 @@
</body>
</html>

View File

@ -23,7 +23,7 @@
<!-- Select2 code -->
<link href="css/select2-3.4.6.min.css" rel="stylesheet">
<script src="js/select2-3.4.6.min.js"></script>
<script src="../js/jquery.tablesorter.widgets-filter-formatter-select2.js"></script>
<script src="../js/widgets/widget-filter-formatter-select2.js"></script>
<script id="js">$(function(){
@ -212,7 +212,7 @@
&lt;!-- Select2 code --&gt;
&lt;link href=&quot;http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.6/select2.min.css&quot; rel=&quot;stylesheet&quot;&gt;
&lt;script src=&quot;http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.6/select2.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;../js/jquery.tablesorter.widgets-filter-formatter-select2.js&quot;&gt;&lt;/script&gt;</pre>
&lt;script src=&quot;../js/widgets/widget-filter-formatter-select2.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>HTML</h1>

View File

@ -303,7 +303,7 @@ td.pager {
&lt;table class=&quot;tablesorter&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;td class=&quot;pager sorter-false&quot; colspan=&quot;5&quot;&gt;
&lt;td class=&quot;pager&quot; colspan=&quot;5&quot;&gt;
&lt;img src=&quot;../addons/pager/icons/first.png&quot; class=&quot;first&quot;/&gt;
&lt;img src=&quot;../addons/pager/icons/prev.png&quot; class=&quot;prev&quot;/&gt;
&lt;span class=&quot;pagedisplay&quot;&gt;&lt;/span&gt; &lt;!-- this can be any element, including an input --&gt;

View File

@ -2421,7 +2421,7 @@ $(function(){
}</pre>
<span class="label label-warning">Warning</span> What <em>won't work</em> is if you try to target the header using a filtering selector that uses an index, e.g. <code>"th:eq()"</code>, <code>":gt()"</code>, <code>":lt()"</code>, <code>":first"</code>, <code>":last"</code>, <code>":even"</code> or <code>":odd"</code>, <code>":first-child"</code>, <code>":last-child"</code>, <code>":nth-child()"</code>, <code>":nth-last-child()"</code>, etc.<br>
<br>
A new file has been included named "jquery.tablesorter.widgets-filter-formatter.js". It includes code to add jQuery UI and HTML5 controls via the <a href="#widget-filter-formatter"><code>filter_formatter</code></a> option.<br>
A new file has been included named "widget-filter-formatter-jui.js" &amp; "widget-filter-formatter-html5.js". The files include code to add jQuery UI and HTML5 controls via the <a href="#widget-filter-formatter"><code>filter_formatter</code></a> option.<br>
<br>
Most of the formatter functions have an option named <code>valueToHeader</code> which, when <code>true</code> adds a span to the header cell above the filter row and updates it with the current control's value (see <a href="example-widget-filter-formatter-2.html">example 2</a>). If the option exists and is set to <code>false</code>, then the current value is added to the control's handle and css can be used to create a popup to show the current value (see <a href="example-widget-filter-formatter-1.html">example 1</a>).<br>
<br>
@ -2698,7 +2698,7 @@ $(function(){
</ul>
The <code>filter_placeholder.select</code> setting adds the text to the first select option (default option to show all rows).<br>
<br>
<span class="label label-info">Note:</span> The <code>jquery.tablesorter.widgets-filter-formatter.js</code> jQuery UI Datepicker Range Selector creates two inputs, so this option then includes two additional settings:<br>
<span class="label label-info">Note:</span> The <code>widget-filter-formatter-jui.js</code> jQuery UI Datepicker Range Selector creates two inputs, so this option then includes two additional settings:<br>
<br>
<pre class="prettyprint lang-js">filter_placeholder : {
search : '',

4
example.json Normal file
View File

@ -0,0 +1,4 @@
{
"widgets" : "filter stickyHeaders uitheme",
"includeDependencies" : false
}

View File

@ -11,9 +11,9 @@
<script src="docs/js/jquery-1.2.6.min.js"></script>
<!-- Pick a theme, load the plugin & initialize plugin -->
<link href="css/theme.default.css" rel="stylesheet">
<script src="js/jquery.tablesorter.min.js"></script>
<script src="js/jquery.tablesorter.widgets.min.js"></script>
<link href="dist/css/theme.default.min.css" rel="stylesheet">
<script src="dist/js/jquery.tablesorter.min.js"></script>
<script src="dist/js/jquery.tablesorter.widgets.min.js"></script>
<script>
$(function(){
$('table').tablesorter({

View File

@ -92,6 +92,7 @@ $.extend({
if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; }
/*jshint evil:true */
data = eval("(" + data + ")");
$.data( elem, settings.single, data );

View File

@ -32,7 +32,7 @@
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
testQuery: function (query, txt) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
@ -44,13 +44,13 @@
this.go = function () {
var i = 0,
var len, i = 0,
numMatchedRows = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
for (i = 0, len = rowcache.length; i < len; i++) {
if (val_empty || options.testQuery(query, cache[i], rowcache[i]) ||
($(rowcache[i]).hasClass(options.childRow) && $(rowcache[i > 1 ? i - 1 : 0]).is(':visible'))) {
options.show.apply(rowcache[i]);
@ -125,7 +125,11 @@
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
if (bool) {
$(options.loader).show();
} else {
$(options.loader).hide();
}
}
return this;
};

View File

@ -1,8 +1,10 @@
/**!
* TableSorter (FORK) 2.19.1 - Client-side table sorting with ease!
/*! TableSorter (FORK) v2.19.1 *//*
* Client-side table sorting with ease!
* @requires jQuery v1.2.6+
*
* Copyright (c) 2007 Christian Bach
* fork maintained by Rob Garrison
*
* Examples and docs at: http://tablesorter.com
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,90 @@
/*! tableSorter (FORK) 2.16+ widgets - updated 2/9/2015 (v2.19.1)
*
* Column Styles
* Column Filters
* Column Resizing
* Sticky Header
* UI Theme (generalized)
* Save Sort
* [ "columns", "filter", "resizable", "stickyHeaders", "uitheme", "saveSort" ]
*/
/*jshint browser:true, jquery:true, unused:false, loopfunc:true */
/*global jQuery: false, localStorage: false */
;(function ($, window) {
/*** This file is dynamically generated ***
*/
/*! tablesorter (FORK) widgets - updated 02-12-2015 (v2.19.1)*/
/* Includes: storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort */
/*! Widget: storage */
;(function ($, window, document) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
// *** Store data in local storage, with a cookie fallback ***
/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
if you need it, then include https://github.com/douglascrockford/JSON-js
$.parseJSON is not available is jQuery versions older than 1.4.1, using older
versions will only allow storing information for one page at a time
// *** Save data (JSON format only) ***
// val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
// $.tablesorter.storage(table, key, val);
$.tablesorter.storage(table, 'tablesorter-mywidget', val);
// *** Get data: $.tablesorter.storage(table, key); ***
v = $.tablesorter.storage(table, 'tablesorter-mywidget');
// val may be empty, so also check for your data
val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
alert(val); // "data1" if saved, or "" if not
*/
ts.storage = function(table, key, value, options) {
table = $(table)[0];
var cookieIndex, cookies, date,
hasLocalStorage = false,
values = {},
c = table.config,
$table = $(table),
id = options && options.id || $table.attr(options && options.group ||
'data-table-group') || table.id || $('.tablesorter').index( $table ),
url = options && options.url || $table.attr(options && options.page ||
'data-table-page') || c && c.fixedUrl || window.location.pathname;
// https://gist.github.com/paulirish/5558557
if ('localStorage' in window) {
try {
window.localStorage.setItem('_tmptest', 'temp');
hasLocalStorage = true;
window.localStorage.removeItem('_tmptest');
} catch(error) {}
}
// *** get value ***
if ($.parseJSON) {
if (hasLocalStorage) {
values = $.parseJSON(localStorage[key] || 'null') || {};
} else {
// old browser, using cookies
cookies = document.cookie.split(/[;\s|=]/);
// add one to get from the key to the value
cookieIndex = $.inArray(key, cookies) + 1;
values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
}
}
// allow value to be an empty string too
if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) {
// add unique identifiers = url pathname > table ID/index on page > data
if (!values[url]) {
values[url] = {};
}
values[url][id] = value;
// *** set value ***
if (hasLocalStorage) {
localStorage[key] = JSON.stringify(values);
} else {
date = new Date();
date.setTime(date.getTime() + (31536e+6)); // 365 days
document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/';
}
} else {
return values && values[url] ? values[url][id] : '';
}
};
})(jQuery, window, document);
/*! Widget: uitheme */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
@ -60,129 +134,9 @@ ts.themes = {
};
$.extend(ts.css, {
filterRow : 'tablesorter-filter-row', // filter
filter : 'tablesorter-filter',
wrapper : 'tablesorter-wrapper', // ui theme & resizable
resizer : 'tablesorter-resizer', // resizable
sticky : 'tablesorter-stickyHeader', // stickyHeader
stickyVis : 'tablesorter-sticky-visible',
stickyWrap: 'tablesorter-sticky-wrapper'
wrapper : 'tablesorter-wrapper' // ui theme & resizable
});
// *** Store data in local storage, with a cookie fallback ***
/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
if you need it, then include https://github.com/douglascrockford/JSON-js
$.parseJSON is not available is jQuery versions older than 1.4.1, using older
versions will only allow storing information for one page at a time
// *** Save data (JSON format only) ***
// val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
// $.tablesorter.storage(table, key, val);
$.tablesorter.storage(table, 'tablesorter-mywidget', val);
// *** Get data: $.tablesorter.storage(table, key); ***
v = $.tablesorter.storage(table, 'tablesorter-mywidget');
// val may be empty, so also check for your data
val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
alert(val); // "data1" if saved, or "" if not
*/
ts.storage = function(table, key, value, options) {
table = $(table)[0];
var cookieIndex, cookies, date,
hasLocalStorage = false,
values = {},
c = table.config,
$table = $(table),
id = options && options.id || $table.attr(options && options.group ||
'data-table-group') || table.id || $('.tablesorter').index( $table ),
url = options && options.url || $table.attr(options && options.page ||
'data-table-page') || c && c.fixedUrl || window.location.pathname;
// https://gist.github.com/paulirish/5558557
if ("localStorage" in window) {
try {
window.localStorage.setItem('_tmptest', 'temp');
hasLocalStorage = true;
window.localStorage.removeItem('_tmptest');
} catch(error) {}
}
// *** get value ***
if ($.parseJSON) {
if (hasLocalStorage) {
values = $.parseJSON(localStorage[key] || 'null') || {};
} else {
// old browser, using cookies
cookies = document.cookie.split(/[;\s|=]/);
// add one to get from the key to the value
cookieIndex = $.inArray(key, cookies) + 1;
values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
}
}
// allow value to be an empty string too
if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) {
// add unique identifiers = url pathname > table ID/index on page > data
if (!values[url]) {
values[url] = {};
}
values[url][id] = value;
// *** set value ***
if (hasLocalStorage) {
localStorage[key] = JSON.stringify(values);
} else {
date = new Date();
date.setTime(date.getTime() + (31536e+6)); // 365 days
document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/';
}
} else {
return values && values[url] ? values[url][id] : '';
}
};
// Add a resize event to table headers
// **************************
ts.addHeaderResizeEvent = function(table, disable, settings) {
table = $(table)[0]; // make sure we're using a dom element
var headers,
defaults = {
timer : 250
},
options = $.extend({}, defaults, settings),
c = table.config,
wo = c.widgetOptions,
checkSizes = function(triggerEvent) {
wo.resize_flag = true;
headers = [];
c.$headers.each(function() {
var $header = $(this),
sizes = $header.data('savedSizes') || [0,0], // fixes #394
width = this.offsetWidth,
height = this.offsetHeight;
if (width !== sizes[0] || height !== sizes[1]) {
$header.data('savedSizes', [ width, height ]);
headers.push(this);
}
});
if (headers.length && triggerEvent !== false) {
c.$table.trigger('resize', [ headers ]);
}
wo.resize_flag = false;
};
checkSizes(false);
clearInterval(wo.resize_timer);
if (disable) {
wo.resize_flag = false;
return false;
}
wo.resize_timer = setInterval(function() {
if (wo.resize_flag) { return; }
checkSizes();
}, options.timer);
};
// Widget: General UI theme
// "uitheme" option in "widgetOptions"
// **************************
ts.addWidget({
id: "uitheme",
priority: 10,
@ -312,10 +266,13 @@ ts.addWidget({
}
});
// Widget: Column styles
// "columns", "columns_thead" (true) and
// "columns_tfoot" (true) options in "widgetOptions"
// **************************
})(jQuery);
/*! Widget: columns */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
ts.addWidget({
id: "columns",
priority: 30,
@ -388,8 +345,18 @@ ts.addWidget({
}
});
// Widget: filter
// **************************
})(jQuery);
/*! Widget: filter */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
$.extend(ts.css, {
filterRow : 'tablesorter-filter-row',
filter : 'tablesorter-filter'
});
ts.addWidget({
id: "filter",
priority: 50,
@ -1660,8 +1627,60 @@ ts.setFilters = function(table, filter, apply, skipFirst) {
return !!valid;
};
// Widget: Sticky headers
// based on this awesome article:
})(jQuery);
/*! Widget: stickyHeaders */
;(function ($, window) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
$.extend(ts.css, {
sticky : 'tablesorter-stickyHeader', // stickyHeader
stickyVis : 'tablesorter-sticky-visible',
stickyWrap: 'tablesorter-sticky-wrapper'
});
// Add a resize event to table headers
ts.addHeaderResizeEvent = function(table, disable, settings) {
table = $(table)[0]; // make sure we're using a dom element
var headers,
defaults = {
timer : 250
},
options = $.extend({}, defaults, settings),
c = table.config,
wo = c.widgetOptions,
checkSizes = function(triggerEvent) {
wo.resize_flag = true;
headers = [];
c.$headers.each(function() {
var $header = $(this),
sizes = $header.data('savedSizes') || [0,0], // fixes #394
width = this.offsetWidth,
height = this.offsetHeight;
if (width !== sizes[0] || height !== sizes[1]) {
$header.data('savedSizes', [ width, height ]);
headers.push(this);
}
});
if (headers.length && triggerEvent !== false) {
c.$table.trigger('resize', [ headers ]);
}
wo.resize_flag = false;
};
checkSizes(false);
clearInterval(wo.resize_timer);
if (disable) {
wo.resize_flag = false;
return false;
}
wo.resize_timer = setInterval(function() {
if (wo.resize_flag) { return; }
checkSizes();
}, options.timer);
};
// Sticky headers based on this awesome article:
// http://css-tricks.com/13465-persistent-headers/
// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
// **************************
@ -1878,7 +1897,17 @@ ts.addWidget({
}
});
// Add Column resizing widget
})(jQuery, window);
/*! Widget: resizable */
;(function ($, window) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
$.extend(ts.css, {
resizer : 'tablesorter-resizer' // resizable
});
// this widget saves the column widths if
// $.tablesorter.storage function is included
// **************************
@ -2045,7 +2074,13 @@ ts.resizableReset = function(table, nosave) {
});
};
// Save table sort widget
})(jQuery, window);
/*! Widget: saveSort */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
// this widget saves the last sort only if the
// saveSort widget option is true AND the
// $.tablesorter.storage function is included
@ -2108,4 +2143,4 @@ ts.addWidget({
}
});
})(jQuery, window);
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,78 @@
/*! Widget: columns */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
ts.addWidget({
id: "columns",
priority: 30,
options : {
columns : [ "primary", "secondary", "tertiary" ]
},
format: function(table, c, wo) {
var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
$table = c.$table,
$tbodies = c.$tbodies,
sortList = c.sortList,
len = sortList.length,
// removed c.widgetColumns support
css = wo && wo.columns || [ "primary", "secondary", "tertiary" ],
last = css.length - 1;
remove = css.join(' ');
// check if there is a sort (on initialization there may not be one)
for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
$rows = $tbody.children('tr');
// loop through the visible rows
$rows.each(function() {
$row = $(this);
if (this.style.display !== 'none') {
// remove all columns class names
$cells = $row.children().removeClass(remove);
// add appropriate column class names
if (sortList && sortList[0]) {
// primary sort column class
$cells.eq(sortList[0][0]).addClass(css[0]);
if (len > 1) {
for (indx = 1; indx < len; indx++) {
// secondary, tertiary, etc sort column classes
$cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
}
}
}
}
});
ts.processTbody(table, $tbody, false);
}
// add classes to thead and tfoot
rows = wo.columns_thead !== false ? ['thead tr'] : [];
if (wo.columns_tfoot !== false) {
rows.push('tfoot tr');
}
if (rows.length) {
$rows = $table.find( rows.join(',') ).children().removeClass(remove);
if (len) {
for (indx = 0; indx < len; indx++) {
// add primary. secondary, tertiary, etc sort column classes
$rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
}
}
}
},
remove: function(table, c, wo) {
var tbodyIndex, $tbody,
$tbodies = c.$tbodies,
remove = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' ');
c.$headers.removeClass(remove);
c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
$tbody.children('tr').each(function() {
$(this).children().removeClass(remove);
});
ts.processTbody(table, $tbody, false); // restore tbody
}
}
});
})(jQuery);

View File

@ -0,0 +1,429 @@
/*! Filter widget formatter html5 functions *//* updated 7/17/2014 (v2.17.5)
* requires: tableSorter (FORK) 2.15+ and jQuery 1.4.3+
*
* html5Number (spinner)
* html5Range (slider)
* html5Color (color)
*/
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
;(function($){
"use strict";
var ts = $.tablesorter || {},
// compare option selector class name (jQuery selector)
compareSelect = '.compare-select',
tsff = ts.filterFormatter = {
addCompare: function($cell, indx, options){
if (options.compare && $.isArray(options.compare) && options.compare.length > 1) {
var opt = '',
compareSelectClass = [ compareSelect.slice(1), ' ' + compareSelect.slice(1), '' ],
txt = options.cellText ? '<label class="' + compareSelectClass.join('-label') + indx + '">' + options.cellText + '</label>' : '';
$.each(options.compare, function(i, c){
opt += '<option ' + (options.selected === i ? 'selected' : '') + '>' + c + '</option>';
});
$cell
.wrapInner('<div class="' + compareSelectClass.join('-wrapper') + indx + '" />')
.prepend( txt + '<select class="' + compareSelectClass.join('') + indx + '" />' )
.find('select')
.append(opt);
}
},
updateCompare : function($cell, $input, o) {
var val = $input.val() || '',
num = val.replace(/\s*?[><=]\s*?/g, ''),
compare = val.match(/[><=]/g) || '';
if (o.compare) {
if ($.isArray(o.compare)){
compare = (compare || []).join('') || o.compare[o.selected || 0];
}
$cell.find(compareSelect).val( compare );
}
return [ val, num ];
},
/**********************\
HTML5 Number (spinner)
\**********************/
html5Number : function($cell, indx, def5Num) {
var t, o = $.extend({
value : 0,
min : 0,
max : 100,
step : 1,
delayed : true,
disabled : false,
addToggle : false,
exactMatch : false,
cellText : '',
compare : '',
skipTest: false
}, def5Num),
$input,
// test browser for HTML5 range support
$number = $('<input type="number" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 number is supported - from Modernizr
numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateNumber = function(delayed, notrigger){
var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true,
v = $cell.find('.number').val(),
compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
$input
// add equal to the beginning, so we filter exact numbers
.val( !o.addToggle || chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
.trigger( notrigger ? '' : 'search', searchType ).end()
.find('.number').val(v);
if ($cell.find('.number').length) {
$cell.find('.number')[0].disabled = (o.disabled || !chkd);
}
// update sticky header cell
if ($shcell.length) {
$shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd);
$shcell.find(compareSelect).val(compare);
if (o.addToggle) {
$shcell.find('.toggle')[0].checked = chkd;
}
}
};
$number.remove();
if (numberSupported) {
t = o.addToggle ? '<div class="button"><input id="html5button' + indx + '" type="checkbox" class="toggle" />' +
'<label for="html5button' + indx + '"></label></div>' : '';
t += '<input class="number" type="number" min="' + o.min + '" max="' + o.max + '" value="' +
o.value + '" step="' + o.step + '" />';
// add HTML5 number (spinner)
$cell
.append(t + '<input type="hidden" />')
.find('.toggle, .number').bind('change', function(){
updateNumber();
})
.closest('thead').find('th[data-column=' + indx + ']')
.addClass('filter-parsed') // get exact numbers from column
// on reset
.closest('table').bind('filterReset', function(){
if ($.isArray(o.compare)) {
$cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
}
// turn off the toggle checkbox
if (o.addToggle) {
$cell.find('.toggle')[0].checked = false;
if ($shcell.length) {
$shcell.find('.toggle')[0].checked = false;
}
}
$cell.find('.number').val( o.value );
setTimeout(function(){
updateNumber();
}, 0);
});
$input = $cell.find('input[type=hidden]').bind('change', function(){
$cell.find('.number').val( this.value );
updateNumber();
});
// update slider from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
var val = tsff.updateCompare($cell, $input, o)[0] || o.value;
$cell.find('.number').val( ((val || '') + '').replace(/[><=]/g,'') );
updateNumber(false, true);
ts.filter.formatterUpdated($cell, indx);
});
if (o.compare) {
// add compare select
tsff.addCompare($cell, indx, o);
$cell.find(compareSelect).bind('change', function(){
updateNumber();
});
}
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
$shcell
.append(t)
.find('.toggle, .number').bind('change', function(){
$cell.find('.number').val( $(this).val() );
updateNumber();
});
if (o.compare) {
// add compare select
tsff.addCompare($shcell, indx, o);
$shcell.find(compareSelect).bind('change', function(){
$cell.find(compareSelect).val( $(this).val() );
updateNumber();
});
}
updateNumber();
});
updateNumber();
}
return numberSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
},
/**********************\
HTML5 range slider
\**********************/
html5Range : function($cell, indx, def5Range) {
var o = $.extend({
value : 0,
min : 0,
max : 100,
step : 1,
delayed : true,
valueToHeader : true,
exactMatch : true,
cellText : '',
compare : '',
allText : 'all',
skipTest : false
}, def5Range),
$input,
// test browser for HTML5 range support
$range = $('<input type="range" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4)
// see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js
rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateRange = function(v, delayed, notrigger){
/*jshint eqeqeq:false */
// hidden input changes may include compare symbols
v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace(/[<>=]/g,'') || o.value;
var compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
t = ' (' + (compare ? compare + v : v == o.min ? o.allText : v) + ')',
searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
$cell.find('input[type=hidden]')
// add equal to the beginning, so we filter exact numbers
.val( ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) )
//( val == o.min ? '' : val + (o.exactMatch ? '=' : ''))
.trigger( notrigger ? '' : 'search', searchType ).end()
.find('.range').val(v);
// or add current value to the header cell, if desired
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
// update sticky header cell
if ($shcell.length) {
$shcell
.find('.range').val(v).end()
.find(compareSelect).val( compare );
$shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
}
};
$range.remove();
if (rangeSupported) {
// add HTML5 range
$cell
.html('<input type="hidden"><input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
.closest('thead').find('th[data-column=' + indx + ']')
.addClass('filter-parsed') // get exact numbers from column
// add span to header for the current slider value
.find('.tablesorter-header-inner').append('<span class="curvalue" />');
// hidden filter update namespace trigger by filter widget
$input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
/*jshint eqeqeq:false */
var v = this.value,
compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '';
if (v !== this.lastValue) {
this.lastValue = ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) );
this.value = this.lastValue;
updateRange( v );
}
});
$cell.find('.range').bind('change', function(){
updateRange( this.value );
});
// update spinner from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
var val = tsff.updateCompare($cell, $input, o)[0];
$cell.find('.range').val( val );
updateRange(val, false, true);
ts.filter.formatterUpdated($cell, indx);
});
if (o.compare) {
// add compare select
tsff.addCompare($cell, indx, o);
$cell.find(compareSelect).bind('change', function(){
updateRange();
});
}
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
$shcell
.html('<input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
.find('.range').bind('change', function(){
updateRange( $shcell.find('.range').val() );
});
updateRange();
if (o.compare) {
// add compare select
tsff.addCompare($shcell, indx, o);
$shcell.find(compareSelect).bind('change', function(){
$cell.find(compareSelect).val( $(this).val() );
updateRange();
});
}
});
// on reset
$cell.closest('table').bind('filterReset', function(){
if ($.isArray(o.compare)) {
$cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
}
setTimeout(function(){
updateRange(o.value, false, true);
}, 0);
});
updateRange();
}
return rangeSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
},
/**********************\
HTML5 Color picker
\**********************/
html5Color: function($cell, indx, defColor) {
var t, o = $.extend({
value : '#000000',
disabled : false,
addToggle : true,
exactMatch : true,
valueToHeader : false,
skipTest : false
}, defColor),
$input,
// Add a hidden input to hold the range values
$color = $('<input type="color" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 color is supported - from Modernizr
colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateColor = function(v, notrigger){
v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace('=','') || o.value;
var chkd = true,
t = ' (' + v + ')';
if (o.addToggle) {
chkd = $cell.find('.toggle').is(':checked');
}
if ($cell.find('.colorpicker').length) {
$cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
}
$input
.val( chkd ? v + (o.exactMatch ? '=' : '') : '' )
.trigger( !c.$table[0].hasInitialized || notrigger ? '' : 'search' );
if (o.valueToHeader) {
// add current color to the header cell
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
} else {
// current color to span in cell
$cell.find('.currentColor').html(t);
}
// update sticky header cell
if ($shcell.length) {
$shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
if (o.addToggle) {
$shcell.find('.toggle')[0].checked = chkd;
}
if (o.valueToHeader) {
// add current color to the header cell
$shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
} else {
// current color to span in cell
$shcell.find('.currentColor').html(t);
}
}
};
$color.remove();
if (colorSupported) {
t = '' + indx + Math.round(Math.random() * 100);
// add HTML5 color picker
t = '<div class="color-controls-wrapper">' +
(o.addToggle ? '<div class="button"><input id="colorbutton' + t + '" type="checkbox" class="toggle" /><label for="colorbutton' +
t + '"></label></div>' : '') +
'<input type="hidden"><input class="colorpicker" type="color" />' +
(o.valueToHeader ? '' : '<span class="currentColor">(#000000)</span>') + '</div>';
$cell.html(t);
// add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out
if (o.valueToHeader) {
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('<span class="curcolor" />');
}
$cell.find('.toggle, .colorpicker').bind('change', function(){
updateColor( $cell.find('.colorpicker').val() );
});
// hidden filter update namespace trigger by filter widget
$input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
updateColor( this.value );
});
// update slider from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
updateColor( $input.val(), true );
ts.filter.formatterUpdated($cell, indx);
});
// on reset
$cell.closest('table').bind('filterReset', function(){
// just turn off the colorpicker
if (o.addToggle) {
$cell.find('.toggle')[0].checked = false;
}
// delay needed because default color needs to be set in the filter
// there is no compare option here, so if addToggle = false,
// default color is #000000 (even with no value set)
setTimeout(function(){
updateColor();
}, 0);
});
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx);
$shcell
.html(t)
.find('.toggle, .colorpicker').bind('change', function(){
updateColor( $shcell.find('.colorpicker').val() );
});
updateColor( $shcell.find('.colorpicker').val() );
});
updateColor( o.value );
}
return colorSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
}
};
})(jQuery);

View File

@ -1,4 +1,4 @@
/*! Filter widget formatter functions - updated 7/17/2014 (v2.17.5)
/*! Filter widget formatter jQuery UI functions *//* updated 7/17/2014 (v2.17.5)
* requires: tableSorter (FORK) 2.15+ and jQuery 1.4.3+
*
* uiSpinner (jQuery UI spinner)
@ -6,9 +6,6 @@
* uiRange (jQuery UI range slider)
* uiDateCompare (jQuery UI datepicker; 1 input)
* uiDatepicker (jQuery UI datepicker; 2 inputs, filter range)
* html5Number (spinner)
* html5Range (slider)
* html5Color (color)
*/
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
@ -761,383 +758,6 @@ tsff = ts.filterFormatter = {
// return the hidden input so the filter widget has a reference to it
return $input.val( o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : '') );
},
/**********************\
HTML5 Number (spinner)
\**********************/
html5Number : function($cell, indx, def5Num) {
var t, o = $.extend({
value : 0,
min : 0,
max : 100,
step : 1,
delayed : true,
disabled : false,
addToggle : false,
exactMatch : false,
cellText : '',
compare : '',
skipTest: false
}, def5Num),
$input,
// test browser for HTML5 range support
$number = $('<input type="number" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 number is supported - from Modernizr
numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateNumber = function(delayed, notrigger){
var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true,
v = $cell.find('.number').val(),
compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
$input
// add equal to the beginning, so we filter exact numbers
.val( !o.addToggle || chkd ? (compare ? compare : o.exactMatch ? '=' : '') + v : '' )
.trigger( notrigger ? '' : 'search', searchType ).end()
.find('.number').val(v);
if ($cell.find('.number').length) {
$cell.find('.number')[0].disabled = (o.disabled || !chkd);
}
// update sticky header cell
if ($shcell.length) {
$shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd);
$shcell.find(compareSelect).val(compare);
if (o.addToggle) {
$shcell.find('.toggle')[0].checked = chkd;
}
}
};
$number.remove();
if (numberSupported) {
t = o.addToggle ? '<div class="button"><input id="html5button' + indx + '" type="checkbox" class="toggle" />' +
'<label for="html5button' + indx + '"></label></div>' : '';
t += '<input class="number" type="number" min="' + o.min + '" max="' + o.max + '" value="' +
o.value + '" step="' + o.step + '" />';
// add HTML5 number (spinner)
$cell
.append(t + '<input type="hidden" />')
.find('.toggle, .number').bind('change', function(){
updateNumber();
})
.closest('thead').find('th[data-column=' + indx + ']')
.addClass('filter-parsed') // get exact numbers from column
// on reset
.closest('table').bind('filterReset', function(){
if ($.isArray(o.compare)) {
$cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
}
// turn off the toggle checkbox
if (o.addToggle) {
$cell.find('.toggle')[0].checked = false;
if ($shcell.length) {
$shcell.find('.toggle')[0].checked = false;
}
}
$cell.find('.number').val( o.value );
setTimeout(function(){
updateNumber();
}, 0);
});
$input = $cell.find('input[type=hidden]').bind('change', function(){
$cell.find('.number').val( this.value );
updateNumber();
});
// update slider from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
var val = tsff.updateCompare($cell, $input, o)[0] || o.value;
$cell.find('.number').val( ((val || '') + '').replace(/[><=]/g,'') );
updateNumber(false, true);
ts.filter.formatterUpdated($cell, indx);
});
if (o.compare) {
// add compare select
tsff.addCompare($cell, indx, o);
$cell.find(compareSelect).bind('change', function(){
updateNumber();
});
}
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
$shcell
.append(t)
.find('.toggle, .number').bind('change', function(){
$cell.find('.number').val( $(this).val() );
updateNumber();
});
if (o.compare) {
// add compare select
tsff.addCompare($shcell, indx, o);
$shcell.find(compareSelect).bind('change', function(){
$cell.find(compareSelect).val( $(this).val() );
updateNumber();
});
}
updateNumber();
});
updateNumber();
}
return numberSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
},
/**********************\
HTML5 range slider
\**********************/
html5Range : function($cell, indx, def5Range) {
var o = $.extend({
value : 0,
min : 0,
max : 100,
step : 1,
delayed : true,
valueToHeader : true,
exactMatch : true,
cellText : '',
compare : '',
allText : 'all',
skipTest : false
}, def5Range),
$input,
// test browser for HTML5 range support
$range = $('<input type="range" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4)
// see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js
rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateRange = function(v, delayed, notrigger){
/*jshint eqeqeq:false */
// hidden input changes may include compare symbols
v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace(/[<>=]/g,'') || o.value;
var compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '',
t = ' (' + (compare ? compare + v : v == o.min ? o.allText : v) + ')',
searchType = c.$table[0].hasInitialized ? (delayed ? delayed : o.delayed) || '' : true;
$cell.find('input[type=hidden]')
// add equal to the beginning, so we filter exact numbers
.val( ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) )
//( val == o.min ? '' : val + (o.exactMatch ? '=' : ''))
.trigger( notrigger ? '' : 'search', searchType ).end()
.find('.range').val(v);
// or add current value to the header cell, if desired
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
// update sticky header cell
if ($shcell.length) {
$shcell
.find('.range').val(v).end()
.find(compareSelect).val( compare );
$shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t);
}
};
$range.remove();
if (rangeSupported) {
// add HTML5 range
$cell
.html('<input type="hidden"><input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
.closest('thead').find('th[data-column=' + indx + ']')
.addClass('filter-parsed') // get exact numbers from column
// add span to header for the current slider value
.find('.tablesorter-header-inner').append('<span class="curvalue" />');
// hidden filter update namespace trigger by filter widget
$input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
/*jshint eqeqeq:false */
var v = this.value,
compare = ($.isArray(o.compare) ? $cell.find(compareSelect).val() || o.compare[ o.selected || 0] : o.compare) || '';
if (v !== this.lastValue) {
this.lastValue = ( compare ? compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) );
this.value = this.lastValue;
updateRange( v );
}
});
$cell.find('.range').bind('change', function(){
updateRange( this.value );
});
// update spinner from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
var val = tsff.updateCompare($cell, $input, o)[0];
$cell.find('.range').val( val );
updateRange(val, false, true);
ts.filter.formatterUpdated($cell, indx);
});
if (o.compare) {
// add compare select
tsff.addCompare($cell, indx, o);
$cell.find(compareSelect).bind('change', function(){
updateRange();
});
}
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
$shcell
.html('<input class="range" type="range" min="' + o.min + '" max="' + o.max + '" value="' + o.value + '" />')
.find('.range').bind('change', function(){
updateRange( $shcell.find('.range').val() );
});
updateRange();
if (o.compare) {
// add compare select
tsff.addCompare($shcell, indx, o);
$shcell.find(compareSelect).bind('change', function(){
$cell.find(compareSelect).val( $(this).val() );
updateRange();
});
}
});
// on reset
$cell.closest('table').bind('filterReset', function(){
if ($.isArray(o.compare)) {
$cell.add($shcell).find(compareSelect).val( o.compare[ o.selected || 0 ] );
}
setTimeout(function(){
updateRange(o.value, false, true);
}, 0);
});
updateRange();
}
return rangeSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
},
/**********************\
HTML5 Color picker
\**********************/
html5Color: function($cell, indx, defColor) {
var t, o = $.extend({
value : '#000000',
disabled : false,
addToggle : true,
exactMatch : true,
valueToHeader : false,
skipTest : false
}, defColor),
$input,
// Add a hidden input to hold the range values
$color = $('<input type="color" style="visibility:hidden;" value="test">').appendTo($cell),
// test if HTML5 color is supported - from Modernizr
colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test',
$shcell = [],
c = $cell.closest('table')[0].config,
updateColor = function(v, notrigger){
v = ( typeof v === "undefined" ? $input.val() : v ).toString().replace('=','') || o.value;
var chkd = true,
t = ' (' + v + ')';
if (o.addToggle) {
chkd = $cell.find('.toggle').is(':checked');
}
if ($cell.find('.colorpicker').length) {
$cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
}
$input
.val( chkd ? v + (o.exactMatch ? '=' : '') : '' )
.trigger( !c.$table[0].hasInitialized || notrigger ? '' : 'search' );
if (o.valueToHeader) {
// add current color to the header cell
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
} else {
// current color to span in cell
$cell.find('.currentColor').html(t);
}
// update sticky header cell
if ($shcell.length) {
$shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd);
if (o.addToggle) {
$shcell.find('.toggle')[0].checked = chkd;
}
if (o.valueToHeader) {
// add current color to the header cell
$shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t);
} else {
// current color to span in cell
$shcell.find('.currentColor').html(t);
}
}
};
$color.remove();
if (colorSupported) {
t = '' + indx + Math.round(Math.random() * 100);
// add HTML5 color picker
t = '<div class="color-controls-wrapper">' +
(o.addToggle ? '<div class="button"><input id="colorbutton' + t + '" type="checkbox" class="toggle" /><label for="colorbutton' +
t + '"></label></div>' : '') +
'<input type="hidden"><input class="colorpicker" type="color" />' +
(o.valueToHeader ? '' : '<span class="currentColor">(#000000)</span>') + '</div>';
$cell.html(t);
// add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out
if (o.valueToHeader) {
$cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append('<span class="curcolor" />');
}
$cell.find('.toggle, .colorpicker').bind('change', function(){
updateColor( $cell.find('.colorpicker').val() );
});
// hidden filter update namespace trigger by filter widget
$input = $cell.find('input[type=hidden]').bind('change' + c.namespace + 'filter', function(){
updateColor( this.value );
});
// update slider from hidden input, in case of saved filters
c.$table.bind('filterFomatterUpdate', function(){
updateColor( $input.val(), true );
ts.filter.formatterUpdated($cell, indx);
});
// on reset
$cell.closest('table').bind('filterReset', function(){
// just turn off the colorpicker
if (o.addToggle) {
$cell.find('.toggle')[0].checked = false;
}
// delay needed because default color needs to be set in the filter
// there is no compare option here, so if addToggle = false,
// default color is #000000 (even with no value set)
setTimeout(function(){
updateColor();
}, 0);
});
// has sticky headers?
c.$table.bind('stickyHeadersInit', function(){
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx);
$shcell
.html(t)
.find('.toggle, .colorpicker').bind('change', function(){
updateColor( $shcell.find('.colorpicker').val() );
});
updateColor( $shcell.find('.colorpicker').val() );
});
updateColor( o.value );
}
return colorSupported ? $cell.find('input[type="hidden"]') : $('<input type="search">');
}
};

1281
js/widgets/widget-filter.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,176 @@
/*! Widget: resizable */
;(function ($, window) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
$.extend(ts.css, {
resizer : 'tablesorter-resizer' // resizable
});
// this widget saves the column widths if
// $.tablesorter.storage function is included
// **************************
ts.addWidget({
id: "resizable",
priority: 40,
options: {
resizable : true,
resizable_addLastColumn : false,
resizable_widths : [],
resizable_throttle : false // set to true (5ms) or any number 0-10 range
},
format: function(table, c, wo) {
if (c.$table.hasClass('hasResizable')) { return; }
c.$table.addClass('hasResizable');
ts.resizableReset(table, true); // set default widths
var $rows, $columns, $column, column, timer,
storedSizes = {},
$table = c.$table,
$wrap = $table.parent(),
overflow = $table.parent().css('overflow') === 'auto',
mouseXPosition = 0,
$target = null,
$next = null,
fullWidth = Math.abs($table.parent().width() - $table.width()) < 20,
mouseMove = function(event){
if (mouseXPosition === 0 || !$target) { return; }
// resize columns
var leftEdge = event.pageX - mouseXPosition,
targetWidth = $target.width();
$target.width( targetWidth + leftEdge );
if ($target.width() !== targetWidth && fullWidth) {
$next.width( $next.width() - leftEdge );
} else if (overflow) {
$table.width(function(i, w){
return w + leftEdge;
});
if (!$next.length) {
// if expanding right-most column, scroll the wrapper
$wrap[0].scrollLeft = $table.width();
}
}
mouseXPosition = event.pageX;
},
stopResize = function() {
if (ts.storage && $target && $next) {
storedSizes = {};
storedSizes[$target.index()] = $target.width();
storedSizes[$next.index()] = $next.width();
$target.width( storedSizes[$target.index()] );
$next.width( storedSizes[$next.index()] );
if (wo.resizable !== false) {
// save all column widths
ts.storage(table, 'tablesorter-resizable', c.$headers.map(function(){ return $(this).width(); }).get() );
}
}
mouseXPosition = 0;
$target = $next = null;
$(window).trigger('resize'); // will update stickyHeaders, just in case
};
storedSizes = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {};
// process only if table ID or url match
if (storedSizes) {
for (column in storedSizes) {
if (!isNaN(column) && column < c.$headers.length) {
c.$headers.eq(column).width(storedSizes[column]); // set saved resizable widths
}
}
}
$rows = $table.children('thead:first').children('tr');
// add resizable-false class name to headers (across rows as needed)
$rows.children().each(function() {
var canResize,
$column = $(this);
column = $column.attr('data-column');
canResize = ts.getData( $column, ts.getColumnData( table, c.headers, column ), 'resizable') === "false";
$rows.children().filter('[data-column="' + column + '"]')[canResize ? 'addClass' : 'removeClass']('resizable-false');
});
// add wrapper inside each cell to allow for positioning of the resizable target block
$rows.each(function() {
$column = $(this).children().not('.resizable-false');
if (!$(this).find('.' + ts.css.wrapper).length) {
// Firefox needs this inner div to position the resizer correctly
$column.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
}
// don't include the last column of the row
if (!wo.resizable_addLastColumn) { $column = $column.slice(0,-1); }
$columns = $columns ? $columns.add($column) : $column;
});
$columns
.each(function() {
var $column = $(this),
padding = parseInt($column.css('padding-right'), 10) + 10; // 10 is 1/2 of the 20px wide resizer
$column
.find('.' + ts.css.wrapper)
.append('<div class="' + ts.css.resizer + '" style="cursor:w-resize;position:absolute;z-index:1;right:-' +
padding + 'px;top:0;height:100%;width:20px;"></div>');
})
.find('.' + ts.css.resizer)
.bind('mousedown', function(event) {
// save header cell and mouse position
$target = $(event.target).closest('th');
var $header = c.$headers.filter('[data-column="' + $target.attr('data-column') + '"]');
if ($header.length > 1) { $target = $target.add($header); }
// if table is not as wide as it's parent, then resize the table
$next = event.shiftKey ? $target.parent().find('th').not('.resizable-false').filter(':last') : $target.nextAll(':not(.resizable-false)').eq(0);
mouseXPosition = event.pageX;
});
$(document)
.bind('mousemove.tsresize', function(event) {
// ignore mousemove if no mousedown
if (mouseXPosition === 0 || !$target) { return; }
if (wo.resizable_throttle) {
clearTimeout(timer);
timer = setTimeout(function(){
mouseMove(event);
}, isNaN(wo.resizable_throttle) ? 5 : wo.resizable_throttle );
} else {
mouseMove(event);
}
})
.bind('mouseup.tsresize', function() {
stopResize();
});
// right click to reset columns to default widths
$table.find('thead:first').bind('contextmenu.tsresize', function() {
ts.resizableReset(table);
// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
var allowClick = $.isEmptyObject ? $.isEmptyObject(storedSizes) : true;
storedSizes = {};
return allowClick;
});
},
remove: function(table, c) {
c.$table
.removeClass('hasResizable')
.children('thead')
.unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize')
.children('tr').children()
.unbind('mousemove.tsresize mouseup.tsresize')
// don't remove "tablesorter-wrapper" as uitheme uses it too
.find('.' + ts.css.resizer).remove();
ts.resizableReset(table);
}
});
ts.resizableReset = function(table, nosave) {
$(table).each(function(){
var $t,
c = this.config,
wo = c && c.widgetOptions;
if (table && c) {
c.$headers.each(function(i){
$t = $(this);
if (wo.resizable_widths && wo.resizable_widths[i]) {
$t.css('width', wo.resizable_widths[i]);
} else if (!$t.hasClass('resizable-false')) {
// don't clear the width of any column that is not resizable
$t.css('width','');
}
});
if (ts.storage && !nosave) { ts.storage(this, 'tablesorter-resizable', {}); }
}
});
};
})(jQuery, window);

View File

@ -0,0 +1,68 @@
/*! Widget: saveSort */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
// this widget saves the last sort only if the
// saveSort widget option is true AND the
// $.tablesorter.storage function is included
// **************************
ts.addWidget({
id: 'saveSort',
priority: 20,
options: {
saveSort : true
},
init: function(table, thisWidget, c, wo) {
// run widget format before all other widgets are applied to the table
thisWidget.format(table, c, wo, true);
},
format: function(table, c, wo, init) {
var stored, time,
$table = c.$table,
saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
sortList = { "sortList" : c.sortList };
if (c.debug) {
time = new Date();
}
if ($table.hasClass('hasSaveSort')) {
if (saveSort && table.hasInitialized && ts.storage) {
ts.storage( table, 'tablesorter-savesort', sortList );
if (c.debug) {
ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time);
}
}
} else {
// set table sort on initial run of the widget
$table.addClass('hasSaveSort');
sortList = '';
// get data
if (ts.storage) {
stored = ts.storage( table, 'tablesorter-savesort' );
sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : '';
if (c.debug) {
ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time);
}
$table.bind('saveSortReset', function(event) {
event.stopPropagation();
ts.storage( table, 'tablesorter-savesort', '' );
});
}
// init is true when widget init is run, this will run this widget before all other widgets have initialized
// this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
if (init && sortList && sortList.length > 0) {
c.sortList = sortList;
} else if (table.hasInitialized && sortList && sortList.length > 0) {
// update sort change
$table.trigger('sorton', [sortList]);
}
}
},
remove: function(table, c) {
c.$table.removeClass('hasSaveSort');
// clear storage
if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
}
});
})(jQuery);

View File

@ -0,0 +1,269 @@
/*! Widget: stickyHeaders */
;(function ($, window) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
$.extend(ts.css, {
sticky : 'tablesorter-stickyHeader', // stickyHeader
stickyVis : 'tablesorter-sticky-visible',
stickyWrap: 'tablesorter-sticky-wrapper'
});
// Add a resize event to table headers
ts.addHeaderResizeEvent = function(table, disable, settings) {
table = $(table)[0]; // make sure we're using a dom element
var headers,
defaults = {
timer : 250
},
options = $.extend({}, defaults, settings),
c = table.config,
wo = c.widgetOptions,
checkSizes = function(triggerEvent) {
wo.resize_flag = true;
headers = [];
c.$headers.each(function() {
var $header = $(this),
sizes = $header.data('savedSizes') || [0,0], // fixes #394
width = this.offsetWidth,
height = this.offsetHeight;
if (width !== sizes[0] || height !== sizes[1]) {
$header.data('savedSizes', [ width, height ]);
headers.push(this);
}
});
if (headers.length && triggerEvent !== false) {
c.$table.trigger('resize', [ headers ]);
}
wo.resize_flag = false;
};
checkSizes(false);
clearInterval(wo.resize_timer);
if (disable) {
wo.resize_flag = false;
return false;
}
wo.resize_timer = setInterval(function() {
if (wo.resize_flag) { return; }
checkSizes();
}, options.timer);
};
// Sticky headers based on this awesome article:
// http://css-tricks.com/13465-persistent-headers/
// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
// **************************
ts.addWidget({
id: "stickyHeaders",
priority: 60, // sticky widget must be initialized after the filter widget!
options: {
stickyHeaders : '', // extra class name added to the sticky header row
stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to
stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element
stickyHeaders_filteredToTop: true, // scroll table top into view after filtering
stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers
stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
},
format: function(table, c, wo) {
// filter widget doesn't initialize on an empty table. Fixes #449
if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
return;
}
var $table = c.$table,
$attach = $(wo.stickyHeaders_attachTo),
namespace = c.namespace + 'stickyheaders ',
// element to watch for the scroll event
$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
$thead = $table.children('thead:first'),
$header = $thead.children('tr').not('.sticky-false').children(),
$tfoot = $table.children('tfoot'),
$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
stickyOffset = $attach.length ? 0 : $stickyOffset.length ?
$stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
// is this table nested? If so, find parent sticky header wrapper (div, not table)
$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
// clone table, then wrap to make sticky header
$stickyTable = wo.$sticky = $table.clone()
.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders)
.wrap('<div class="' + ts.css.stickyWrap + '">'),
$stickyWrap = $stickyTable.parent().css({
position : $attach.length ? 'absolute' : 'fixed',
padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
top : stickyOffset + nestedStickyTop,
left : 0,
visibility : 'hidden',
zIndex : wo.stickyHeaders_zIndex || 2
}),
$stickyThead = $stickyTable.children('thead:first'),
$stickyCells,
laststate = '',
spacing = 0,
setWidth = function($orig, $clone){
$orig.filter(':visible').each(function(i) {
var width, border,
$cell = $clone.filter(':visible').eq(i),
$this = $(this);
// code from https://github.com/jmosbech/StickyTableHeaders
if ($this.css('box-sizing') === 'border-box') {
width = $this.outerWidth();
} else {
if ($cell.css('border-collapse') === 'collapse') {
if (window.getComputedStyle) {
width = parseFloat( window.getComputedStyle(this, null).width );
} else {
// ie8 only
border = parseFloat( $this.css('border-width') );
width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
}
} else {
width = $this.width();
}
}
$cell.css({
'min-width': width,
'max-width': width
});
});
},
resizeHeader = function() {
stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
spacing = 0;
$stickyWrap.css({
left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
width: $table.outerWidth()
});
setWidth( $table, $stickyTable );
setWidth( $header, $stickyCells );
};
// save stickyTable element to config
// it is also saved to wo.$sticky
if (c.$extraTables && c.$extraTables.length) {
c.$extraTables.add($stickyTable);
} else {
c.$extraTables = $stickyTable;
}
// fix clone ID, if it exists - fixes #271
if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; }
// clear out cloned table, except for sticky header
// include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
$stickyTable.find('thead:gt(0), tr.sticky-false').hide();
$stickyTable.find('tbody, tfoot').remove();
$stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
// issue #172 - find td/th in sticky header
$stickyCells = $stickyThead.children().children();
$stickyTable.css({ height:0, width:0, margin: 0 });
// remove resizable block
$stickyCells.find('.' + ts.css.resizer).remove();
// update sticky header class names to match real header after sorting
$table
.addClass('hasStickyHeaders')
.bind( $.trim('pagerComplete' + namespace), function() {
resizeHeader();
});
ts.bindEvents(table, $stickyThead.children().children('.tablesorter-header'));
// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
$table.after( $stickyWrap );
// onRenderHeader is defined, we need to do something about it (fixes #641)
if (c.onRenderHeader) {
$stickyThead.children('tr').children().each(function(index){
// send second parameter
c.onRenderHeader.apply( $(this), [ index, c, $stickyTable ] );
});
}
// make it sticky!
$xScroll.add($yScroll)
.unbind( $.trim('scroll resize '.split(' ').join( namespace )) )
.bind( $.trim('scroll resize '.split(' ').join( namespace )), function(event) {
if (!$table.is(':visible')) { return; } // fixes #278
// Detect nested tables - fixes #724
nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
var prefix = 'tablesorter-sticky-',
offset = $table.offset(),
yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
xWindow = $.isWindow( $xScroll[0] ),
// scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
cssSettings = { visibility : isVisible };
if ($attach.length) {
cssSettings.top = yWindow ? scrollTop : $attach.scrollTop();
}
if (xWindow) {
// adjust when scrolling horizontally - fixes issue #143
cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
}
if ($nestedSticky.length) {
cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
}
$stickyWrap
.removeClass(prefix + 'visible ' + prefix + 'hidden')
.addClass(prefix + isVisible)
.css(cssSettings);
if (isVisible !== laststate || event.type === 'resize') {
// make sure the column widths match
resizeHeader();
laststate = isVisible;
}
});
if (wo.stickyHeaders_addResizeEvent) {
ts.addHeaderResizeEvent(table);
}
// look for filter widget
if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
// scroll table into view after filtering, if sticky header is active - #482
$table.bind( $.trim('filterEnd' + namespace), function() {
// $(':focus') needs jQuery 1.6+
var $td = $(document.activeElement).closest('td'),
column = $td.parent().children().index($td);
// only scroll if sticky header is active
if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
// scroll to original table (not sticky clone)
window.scrollTo(0, $table.position().top);
// give same input/select focus; check if c.$filters exists; fixes #594
if (column >= 0 && c.$filters) {
c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
}
}
});
ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
// support hideFilters
if (wo.filter_hideFilters) {
ts.filter.hideFilters($stickyTable, c);
}
}
$table.trigger('stickyHeadersInit');
},
remove: function(table, c, wo) {
var namespace = c.namespace + 'stickyheaders ';
c.$table
.removeClass('hasStickyHeaders')
.unbind( $.trim('pagerComplete filterEnd '.split(' ').join(namespace)) )
.next('.' + ts.css.stickyWrap).remove();
if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
$(window)
.add(wo.stickyHeaders_xScroll)
.add(wo.stickyHeaders_yScroll)
.add(wo.stickyHeaders_attachTo)
.unbind( $.trim('scroll resize '.split(' ').join(namespace)) );
ts.addHeaderResizeEvent(table, false);
}
});
})(jQuery, window);

View File

@ -0,0 +1,76 @@
/*! Widget: storage */
;(function ($, window, document) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
// *** Store data in local storage, with a cookie fallback ***
/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
if you need it, then include https://github.com/douglascrockford/JSON-js
$.parseJSON is not available is jQuery versions older than 1.4.1, using older
versions will only allow storing information for one page at a time
// *** Save data (JSON format only) ***
// val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
// $.tablesorter.storage(table, key, val);
$.tablesorter.storage(table, 'tablesorter-mywidget', val);
// *** Get data: $.tablesorter.storage(table, key); ***
v = $.tablesorter.storage(table, 'tablesorter-mywidget');
// val may be empty, so also check for your data
val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
alert(val); // "data1" if saved, or "" if not
*/
ts.storage = function(table, key, value, options) {
table = $(table)[0];
var cookieIndex, cookies, date,
hasLocalStorage = false,
values = {},
c = table.config,
$table = $(table),
id = options && options.id || $table.attr(options && options.group ||
'data-table-group') || table.id || $('.tablesorter').index( $table ),
url = options && options.url || $table.attr(options && options.page ||
'data-table-page') || c && c.fixedUrl || window.location.pathname;
// https://gist.github.com/paulirish/5558557
if ('localStorage' in window) {
try {
window.localStorage.setItem('_tmptest', 'temp');
hasLocalStorage = true;
window.localStorage.removeItem('_tmptest');
} catch(error) {}
}
// *** get value ***
if ($.parseJSON) {
if (hasLocalStorage) {
values = $.parseJSON(localStorage[key] || 'null') || {};
} else {
// old browser, using cookies
cookies = document.cookie.split(/[;\s|=]/);
// add one to get from the key to the value
cookieIndex = $.inArray(key, cookies) + 1;
values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
}
}
// allow value to be an empty string too
if ((value || value === '') && window.JSON && JSON.hasOwnProperty('stringify')) {
// add unique identifiers = url pathname > table ID/index on page > data
if (!values[url]) {
values[url] = {};
}
values[url][id] = value;
// *** set value ***
if (hasLocalStorage) {
localStorage[key] = JSON.stringify(values);
} else {
date = new Date();
date.setTime(date.getTime() + (31536e+6)); // 365 days
document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g,'\"') + '; expires=' + date.toGMTString() + '; path=/';
}
} else {
return values && values[url] ? values[url][id] : '';
}
};
})(jQuery, window, document);

View File

@ -0,0 +1,184 @@
/*! Widget: uitheme */
;(function ($) {
'use strict';
var ts = $.tablesorter = $.tablesorter || {};
ts.themes = {
'bootstrap' : {
table : 'table table-bordered table-striped',
caption : 'caption',
// header class names
header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css)
sortNone : '',
sortAsc : '',
sortDesc : '',
active : '', // applied when column is sorted
hover : '', // custom css required - a defined bootstrap style may not override other classes
// icon class names
icons : '', // add "icon-white" to make them white; this icon class is added to the <i> in the header
iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted
iconSortAsc : 'icon-chevron-up glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort
iconSortDesc : 'icon-chevron-down glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort
filterRow : '', // filter row class
footerRow : '',
footerCells : '',
even : '', // even row zebra striping
odd : '' // odd row zebra striping
},
'jui' : {
table : 'ui-widget ui-widget-content ui-corner-all', // table classes
caption : 'ui-widget-content',
// header class names
header : 'ui-widget-header ui-corner-all ui-state-default', // header classes
sortNone : '',
sortAsc : '',
sortDesc : '',
active : 'ui-state-active', // applied when column is sorted
hover : 'ui-state-hover', // hover class
// icon class names
icons : 'ui-icon', // icon class added to the <i> in the header
iconSortNone : 'ui-icon-carat-2-n-s', // class name added to icon when column is not sorted
iconSortAsc : 'ui-icon-carat-1-n', // class name added to icon when column has ascending sort
iconSortDesc : 'ui-icon-carat-1-s', // class name added to icon when column has descending sort
filterRow : '',
footerRow : '',
footerCells : '',
even : 'ui-widget-content', // even row zebra striping
odd : 'ui-state-default' // odd row zebra striping
}
};
$.extend(ts.css, {
wrapper : 'tablesorter-wrapper' // ui theme & resizable
});
ts.addWidget({
id: "uitheme",
priority: 10,
format: function(table, c, wo) {
var i, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
themesAll = ts.themes,
$table = c.$table.add( c.$extraTables ),
$headers = c.$headers.add( c.$extraHeaders ),
theme = c.theme || 'jui',
themes = themesAll[theme] || {},
remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) );
if (c.debug) { time = new Date(); }
// initialization code - run once
if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
wo.uitheme_applied = true;
oldtheme = themesAll[c.appliedTheme] || {};
hasOldTheme = !$.isEmptyObject(oldtheme);
oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
if (hasOldTheme) {
wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
c.$tbodies.children().removeClass( [oldtheme.even, oldtheme.odd].join(' ') );
}
// update zebra stripes
if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
// add caption style
$table.children('caption')
.removeClass(oldtheme.caption || '')
.addClass(themes.caption);
// add table/footer class names
$tfoot = $table
// remove other selected themes
.removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
.addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
.children('tfoot');
c.appliedTheme = c.theme;
if ($tfoot.length) {
$tfoot
// if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
.children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
.children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
}
// update header classes
$headers
.removeClass( (hasOldTheme ? [oldtheme.header, oldtheme.hover, oldremove].join(' ') : '') || '' )
.addClass(themes.header)
.not('.sorter-false')
.unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
.bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
// toggleClass with switch added in jQuery 1.3
$(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
});
$headers.each(function(){
var $this = $(this);
if (!$this.find('.' + ts.css.wrapper).length) {
// Firefox needs this inner div to position the icon & resizer correctly
$this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
}
});
if (c.cssIcon) {
// if c.cssIcon is '', then no <i> is added to the header
$headers
.find('.' + ts.css.icon)
.removeClass(hasOldTheme ? [oldtheme.icons, oldIconRmv].join(' ') : '')
.addClass(themes.icons || '');
}
if ($table.hasClass('hasFilters')) {
$table.children('thead').children('.' + ts.css.filterRow)
.removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
.addClass(themes.filterRow || '');
}
}
for (i = 0; i < c.columns; i++) {
$header = c.$headers.add(c.$extraHeaders).not('.sorter-false').filter('[data-column="' + i + '"]');
$icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
$h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
if ($h.length) {
$header.removeClass(remove);
$icon.removeClass(iconRmv);
if ($h[0].sortDisabled) {
// no sort arrows for disabled columns!
$icon.removeClass(themes.icons || '');
} else {
hdr = themes.sortNone;
icon = themes.iconSortNone;
if ($h.hasClass(ts.css.sortAsc)) {
hdr = [themes.sortAsc, themes.active].join(' ');
icon = themes.iconSortAsc;
} else if ($h.hasClass(ts.css.sortDesc)) {
hdr = [themes.sortDesc, themes.active].join(' ');
icon = themes.iconSortDesc;
}
$h
.addClass(hdr)
.find('.' + ts.css.icon)
.addClass(icon || '');
}
}
}
if (c.debug) {
ts.benchmark("Applying " + theme + " theme", time);
}
},
remove: function(table, c, wo, refreshing) {
if (!wo.uitheme_applied) { return; }
var $table = c.$table,
theme = c.appliedTheme || 'jui',
themes = ts.themes[ theme ] || ts.themes.jui,
$headers = $table.children('thead').children(),
remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
$table.removeClass('tablesorter-' + theme + ' ' + themes.table);
wo.uitheme_applied = false;
if (refreshing) { return; }
$table.find(ts.css.header).removeClass(themes.header);
$headers
.unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
.removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
.filter('.' + ts.css.filterRow)
.removeClass(themes.filterRow);
$headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
}
});
})(jQuery);

View File

@ -7,18 +7,23 @@
"name": "Christian Bach",
"url": "http://tablesorter.com/"
},
"maintainers": [{
"maintainers": [
{
"name": "Rob Garrison",
"url": "https://github.com/Mottie",
"email": "wowmotty@gmail.com"
}],
"licenses": [{
}
],
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
},{
},
{
"type": "GPL",
"url": "http://www.gnu.org/licenses/gpl.html"
}],
}
],
"homepage": "http://mottie.github.com/tablesorter/",
"bugs": "https://github.com/Mottie/tablesorter/issues",
"docs": "http://mottie.github.com/tablesorter/docs/index.html",
@ -36,40 +41,45 @@
],
"main": "js/jquery.tablesorter.js",
"files": [
"css/theme.default.css",
"js/jquery.tablesorter.js",
"js/jquery.tablesorter.min.js",
"js/jquery.tablesorter.widgets.js",
"js/jquery.tablesorter.widgets.min.js",
"addons/pager/"
"dist/css/theme.default.css",
"dist/js/jquery.tablesorter.js",
"dist/js/jquery.tablesorter.min.js",
"dist/js/jquery.tablesorter.widgets.js",
"dist/js/jquery.tablesorter.widgets.min.js",
"dist/js/extras/jquery.tablesorter.pager.min.js"
],
"repository": {
"type": "git",
"url": "git://github.com/Mottie/tablesorter.git"
},
"npmName": "tablesorter",
"npmFileMap": [{
"npmFileMap": [
{
"basePath": "",
"files": [
"js/*",
"js/**/*",
"css/*",
"css/images/*",
"addons/pager/*",
"addons/pager/icons/*"
"dist/**/*"
]
}],
}
],
"autoupdate": {
"source": "git",
"target": "git://github.com/Mottie/tablesorter.git",
"basePath": "",
"files": [
"js/*",
"js/**/*",
"css/*",
"css/images/*",
"addons/pager/*",
"addons/pager/icons/*"
"dist/**/*"
]
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-cli": "~0.1.13",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-copy": "^0.7.0",
"grunt-contrib-cssmin": "^0.12.1",
"grunt-contrib-jshint": "^0.11.0",
"grunt-contrib-qunit": "^0.5.2",
"grunt-contrib-uglify": "^0.7.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-string-replace": "^1.0.0"
}
}

View File

@ -7,18 +7,23 @@
"name": "Christian Bach",
"url": "http://tablesorter.com/"
},
"maintainers": [{
"maintainers": [
{
"name": "Rob Garrison",
"url": "https://github.com/Mottie",
"email": "wowmotty@gmail.com"
}],
"licenses": [{
}
],
"licenses": [
{
"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
},{
},
{
"type": "GPL",
"url": "http://www.gnu.org/licenses/gpl.html"
}],
}
],
"homepage": "http://mottie.github.com/tablesorter/",
"bugs": "https://github.com/Mottie/tablesorter/issues",
"docs": "http://mottie.github.com/tablesorter/docs/index.html",
@ -34,11 +39,10 @@
"natural",
"jquery-plugin"
],
"main": "js/tablesorter.js",
"main": "dist/js/jquery.tablesorter.js",
"files": [
"css/theme.default.css",
"js/jquery.tablesorter.min.js",
"js/jquery.tablesorter.widgets.min.js",
"addons/pager/"
"dist/css/theme.default.min.css",
"dist/js/jquery.tablesorter.min.js",
"dist/js/jquery.tablesorter.widgets.min.js"
]
}

View File

@ -11,7 +11,7 @@
<script src="js/jquery.tablesorter.js"></script>
<script src="js/jquery.tablesorter.widgets.js"></script>
<script src="js/parsers/parser-network.js"></script>
<script src="js/jquery.metadata.js"></script>
<script src="js/extras/jquery.metadata.js"></script>
<script src="testing/testing.js"></script>
<script src="testing/testing-ipv6.js"></script>
<script src="testing/testing-widgets.js"></script>

View File

@ -625,6 +625,7 @@ $(function(){
tester.cacheCompare( table4, 3, [ 2, 1, 7, 6, 5, 3, 4, 8, 9, 10 ], 'force x2 + sorted x2 + append x2, ascending' );
$table4.on('sortEnd', function(){
count++;
console.log(count);
if (count === 1) {
tester.cacheCompare( table4, 3, [ 2, 1, 6, 7, 5, 4, 3, 8, 10, 9 ], 'force x2 + sorted x2 + append x2, descending' );
c4.sortResetKey = 'shiftKey';
@ -632,9 +633,9 @@ $(function(){
e.which = 1;
e.shiftKey = true; // testing sortResetKey
c4.$headers.eq(0).trigger(e);
} else {
} else if (count === 2) {
tester.cacheCompare( table4, 3, [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], 'sortResetKey' );
$table4.off('sortEnd');
// $table4.off('sortEnd');
// start();
}
});