Stupid-Table-Plugin-1.1.3/000077500000000000000000000000001316766721000152565ustar00rootroot00000000000000Stupid-Table-Plugin-1.1.3/CHANGELOG.md000066400000000000000000000032631316766721000170730ustar00rootroot00000000000000v1.1.2 (Released 07/11/2017) ---------------------------- Added multicolumn sort capabilities. See [examples/multicolumn-sort.html](https://rawgit.com/joequery/Stupid-Table-Plugin/master/examples/multicolumn-sort.html). v1.1.1 (Released 07/02/2017) ---------------------------- Updated internal representation of tables. Added `will_manually_build_table` setting. v1.1.0 (Released 06/28/2017) ---------------------------- We are introducing an implementation of settings for StupidTable. The first setting is `should_redraw`. This setting allows you to specify a function that can conditionally prevent the table from redrawing after a sort. v1.0.7 (Released 06/25/2017) ---------------------------- A `` element can now be provided with a `data-sort-onload=yes` attribute. Once `$table.stupidtable()` is called the table will immediately be sorted by the column with the `data-sort-onload=yes` attribute if one is found. Resolves [Issue #180](https://github.com/joequery/Stupid-Table-Plugin/issues/180) and [Issue #126](https://github.com/joequery/Stupid-Table-Plugin/issues/126). v1.0.6 (Released 06/24/2017) ---------------------------- Fixed [Issue #183](https://github.com/joequery/Stupid-Table-Plugin/issues/183) that prevented consecutive calls to `$th.stupidsort()` from running when the same sort direction was specified. v1.0.5 (Released 06/10/2017) ---------------------------- before/aftertablesort callbacks can access the column header element via `data.$th`. v1.0.4 (Released 06/10/2017) ---------------------------- Force a stable sort to circumvent [unstable sorting implementations](https://stackoverflow.com/questions/3026281/array-sort-sorting-stability-in-different-browsers). Stupid-Table-Plugin-1.1.3/LICENSE000066400000000000000000000021071316766721000162630ustar00rootroot00000000000000Copyright (c) 2012 Joseph McCullough Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Stupid-Table-Plugin-1.1.3/README.md000066400000000000000000000253041316766721000165410ustar00rootroot00000000000000Stupid jQuery Table Sort ======================== This is a stupid jQuery table sorting plugin. Nothing fancy, nothing really impressive. Overall, stupidly simple. Requires jQuery 1.7 or newer. [View the demo here][0] See the examples directory. Installation via [npm][2] ------------------------- $ npm i stupid-table-plugin Installation via Bower ---------------------- $ bower install jquery-stupid-table Example Usage ------------- The JS: $("table").stupidtable(); The HTML: ... ... ... The thead and tbody tags must be used. Add a `data-sort` attribute of "DATATYPE" to the th elements to make them sortable by that data type. If you don't want that column to be sortable, just omit the `data-sort` attribute. Predefined data types --------------------- Our aim is to keep this plugin as lightweight as possible. Consequently, the only predefined datatypes that you can pass to the th elements are * `int` * `float` * `string` (case-sensitive) * `string-ins` (case-insensitive) These data types will be sufficient for many simple tables. However, if you need different data types for sorting, you can easily create your own! Data with multiple representations/predefined order --------------------------------------------------- Stupid Table lets you sort a column by computer friendly values while displaying human friendly values via the `data-sort-value` attribute on a td element. For example, to sort timestamps (computer friendly) but display pretty formated dates (human friendly)
int float string
15 -.18 banana
... ... ... In this example, Stupid Table will sort the Birthday column by the timestamps provided in the `data-sort-value` attributes of the corresponding tds. Since timestamps are integers, and that's what we're sorting the column by, we specify the Birthday column as an `int` column in the `data-sort` value of the column header. Default sorting direction ------------------------- By default, columns will sort ascending. You can specify a column to sort "asc" or "desc" first.
Name Birthday
Joe McCullough April 25, 1991
Clint Dempsey March 9, 1983
...
float
Sorting a column on load ------------------------ If you want a specific column to be sorted immediately after `$table.stupidtable()` is called, you can provide a `data-sort-onload=yes` attribute. ...
float
Multicolumn sorting ------------------- A multicolumn sort allows you to define secondary columns to sort by in the event of a tie with two elements in the sorted column. See [examples/multicolumn-sort.html](https://rawgit.com/joequery/Stupid-Table-Plugin/master/examples/multicolumn-sort.html). Specify a comma-separated list of th identifiers in a `data-sort-multicolumn` attribute on a `` element. An identifier can be an integer (which represents the index of the th element of the multicolumn target) or a string (which represents the id of the th element of the multicolumn target). Sorting a column programatically -------------------------------- After you have called `$("#mytable").stupidtable()`, if you wish to sort a column without requiring the user to click on it, select the column th and call var $table = $("#mytable").stupidtable(); var $th_to_sort = $table.find("thead th").eq(0); $th_to_sort.stupidsort(); // You can also force a direction. $th_to_sort.stupidsort('asc'); $th_to_sort.stupidsort('desc'); Updating a table cell's value ----------------------------- If you wish for Stupid Table to respond to changes in the table cell values, you must explicitely inform Stupid Table to update its cache with the new values. If you update the table display/sort values without using this mechanism, your newly updated table **will not sort correctly!** /* * Suppose $age_td is some td in a table under a column specified as an int * column. stupidtable() must already be called for this table. */ $age_td.updateSortVal(23); Note that this only changes the internal sort value (whether you specified a `data-sort-value` or not). Use the standard jQuery `.text()` / `.html()` methods if you wish to change the display values. Callbacks --------- To execute a callback function after a table column has been sorted, you can bind on `aftertablesort`. var table = $("table").stupidtable(); table.bind('aftertablesort', function (event, data) { // data.column - the index of the column sorted after a click // data.direction - the sorting direction (either asc or desc) // data.$th - the th element (in jQuery wrapper) // $(this) - this table object console.log("The sorting direction: " + data.direction); console.log("The column index: " + data.column); }); Similarly, to execute a callback before a table column has been sorted, you can bind on `beforetablesort`. See the complex_example.html file. Creating your own data types ---------------------------- Sometimes you don't have control over the HTML produced by the backend. In the event you need to sort complex data without a `data-sort-value` attribute, you can create your own data type. Creating your own data type for sorting purposes is easy as long as you are comfortable using custom functions for sorting. Consult [Mozilla's Docs][1] if you're not. Let's create an alphanum datatype for a User ID that takes strings in the form "D10", "A40", and sorts the column based on the numbers in the string. ... ... ... Now we need to specify how the **alphanum** type will be sorted. To do that, we do the following: $("table").stupidtable({ "alphanum":function(a,b){ var pattern = "^[A-Z](\\d+)$"; var re = new RegExp(pattern); var aNum = re.exec(a).slice(1); var bNum = re.exec(b).slice(1); return parseInt(aNum,10) - parseInt(bNum,10); } }); This extracts the integers from the cell and compares them in the style that sort functions use. StupidTable Settings -------------------- As of 1.1.0 settings have been introduced. Settings are defined like so: var $table = $("#mytable"); $table.stupidtable_settings({ // Settings for this table specified here }); $table.stupidtable(); Listed below are the available settings. ### will_manually_build_table (Introduced in verison 1.1.1) Options: * `true` * `false` (default) By default, every time a column is sorted, stupidtable reads the DOM to extract all the values from the table. For tables that will not change or for very large tables, this behavior may be suboptimal. To modify this behavior, set the `will_manually_build_table` setting to `true`. However, you will be responsible for informing stupidtable that the table has been modified by calling `$table.stupidtable_build()`. var $table = $("#mytable"); $table.stupidtable_settings({ will_manually_build_table: true }); $table.stupidtable(); // Make some modification to the table, such as deleting a row ... ... // Since will_manually_build_table is true, we must build the table in order // for future sorts to properly handle our modifications. $table.stupidtable_build(); ### should_redraw (Introduced in verison 1.1.0) The `should_redraw` setting allows you to specify a function that determines whether or not the table should be redrawn after it has been internally sorted. The `should_redraw` function takes a `sort_info` object as an argument. The object keys available are: * `column` - An array representing the sorted column. Each element of the array is of the form `[sort_val, $tr, index]` * `sort_dir` - `"asc"` or `"desc"` * `$th` - The jquery object of the `
int float string
1 10.0 a
1 10.0 a
Name Age UserID
Joseph McCullough 20 D10
Justin Edwards 29 A40
` element that was clicked * `th_index` - The index of the `` element that was cliked * `$table` - The jquery object of the `` that contains the `
` that was clicked * `datatype` - The datatype of the column * `compare_fn` - The sort/compare function associated with the `` clicked. **Example**: If you want to prevent stupidtable from redrawing the table if the column sorted has all identical values, you would do the following: var $table = $("#mytable"); $table.stupidtable_settings({ should_redraw: function(sort_info){ var sorted_column = sort_info.column; var first_val = sorted_column[0]; var last_val = sorted_column[sorted_column.length - 1][0]; // If first and last element of the sorted column are the same, we // can assume all elements are the same. return sort_info.compare_fn(first_val, last_val) !== 0; } }); $table.stupidtable(); License ------- The Stupid jQuery Plugin is licensed under the MIT license. See the LICENSE file for full details. Tests ----- Visit `tests/test.html` in your browser to run the QUnit tests. [0]: http://joequery.github.io/Stupid-Table-Plugin/ [1]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort [2]: https://www.npmjs.com/package/stupid-table-plugin Stupid-Table-Plugin-1.1.3/bower.json000066400000000000000000000007631316766721000172750ustar00rootroot00000000000000{ "name": "jquery-stupid-table", "version": "1.1.2", "homepage": "https://github.com/joequery/Stupid-Table-Plugin", "authors": [ "Joseph McCullough" ], "description": "A stupidly small and simple jQuery table sorter plugin", "main": "stupidtable.js", "dependencies": { "jquery": ">= 1.7.0" }, "keywords": [ "jquery", "table", "sort" ], "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ] } Stupid-Table-Plugin-1.1.3/examples/000077500000000000000000000000001316766721000170745ustar00rootroot00000000000000Stupid-Table-Plugin-1.1.3/examples/basic.html000066400000000000000000000031131316766721000210410ustar00rootroot00000000000000 Stupid jQuery table sort

Stupid jQuery table sort!

This example shows how a sortable table can be implemented with very little configuration. Simply specify the data type on a <th> element using the data-sort attribute, and the plugin handles the rest.

int float string
15 -.18 banana
95 36 coke
2 -152.5 apple
-53 88.5 zebra
195 -858 orange
Stupid-Table-Plugin-1.1.3/examples/colspan.html000066400000000000000000000025451316766721000214270ustar00rootroot00000000000000 Stupid jQuery table sort (colspan test)

Stupid jQuery table sort! (colspan test)

Tables using colspans are handled just fine.

The Big Table Header
Letter colspan=2 Number
def X 9 1
abc Z 8 2
bcd Y 7 0
Stupid-Table-Plugin-1.1.3/examples/complex.html000066400000000000000000000114041316766721000214310ustar00rootroot00000000000000 Stupid jQuery table sort (complex example)

Stupid jQuery table sort! (complex example)

This example showcases several of the more advanced features, including specifying sort values, custom data types and callbacks. View the source of this file or see the documentation for more details on how to implement them.

 

int int float string case Can't sort me! date Letter frequency
15 15 -.18 banana Homer arbitrary Sep 15, 2002 E
95 95 36 purple pointless Aug 07, 2004 T
2 2 -152.5 is silly Mar 15, 1986 A
-53 -53 88.5 hello a eccentric Feb 27, 2086 O
195 195 -858 orange fruit garbage Mar 15, 1986 I
Stupid-Table-Plugin-1.1.3/examples/large-table.html000066400000000000000000004621401316766721000221500ustar00rootroot00000000000000 Stupid jQuery table sort (large table example)

Stupid jQuery table sort! (large table example)

This is a large table of over 500 rows to show the plugin can handle large data sets with ease. It includes a mix of styling to mimic a more realistic website scenario. It also provides a better example of the beforetablesort callback by styling the table to appear disabled during sorting.

 

First name Last name City Country Email Registered ID
Emmanuel Owen Needham Pakistan Nov 18, 2011 17321
Stewart Dillard South Portland Italy Dec 30, 2012 94003
Tana Villarreal Waltham Solomon Islands Mar 25, 2012 44041
Wendy Greer Bellflower Mauritania Mar 6, 2011 80251
Kenneth Livingston Anaheim Honduras Jun 20, 2012 79773
Holly Strong Placentia Greenland Jul 22, 2012 56903
Lynn Cooley Temecula Papua New Guinea Apr 12, 2012 68541
Shafira Valdez Columbus Taiwan, Province of China Aug 15, 2011 67777
Autumn Barry Malden Serbia and Montenegro Oct 19, 2011 32595
Hadassah Berry Ketchikan Egypt May 29, 2012 58898
Hector Burns Kokomo Monaco Jun 22, 2012 44279
Eagan Carr Jeannette Slovakia May 3, 2011 52817
Charissa Barker Meadville New Zealand Jun 18, 2012 20900
Abigail Holman Dubuque Kiribati Nov 28, 2011 36026
Caesar Carver Jordan Valley Mexico Feb 1, 2012 14537
Jade Juarez Billings Zimbabwe May 12, 2012 40574
Barbara Shields Saint Joseph Germany Dec 7, 2011 48920
Rose Pace Moraga Ecuador Apr 12, 2011 92908
Nero William Hutchinson Serbia and Montenegro Dec 30, 2011 10398
Lucy Mcclain South El Monte Holy See (Vatican City State) Jun 17, 2012 75898
Thor Kelly Jeffersonville Liberia Nov 11, 2011 59789
Edward Barron Mandan Paraguay Mar 13, 2011 74375
Aaron Hansen Florence Svalbard and Jan Mayen Jun 2, 2012 70820
Mohammad Mcfadden Cicero Bolivia Sep 16, 2011 23056
Mia Marshall Columbia Colombia Aug 21, 2012 52458
Chester Alvarez Springfield Lesotho Oct 29, 2012 44765
Kelsey Douglas Winnemucca Pitcairn Apr 5, 2011 90683
Erin Sims La Habra Liberia Jan 28, 2012 57282
Colt Harper Mayagüez Bangladesh Jul 13, 2011 34013
Xantha Ross Lufkin United States Minor Outlying Islands Aug 6, 2012 26764
Aiko Gill Asbury Park Kyrgyzstan Jan 15, 2012 45134
Stacey Barron Salem India Apr 3, 2012 16321
Aurora Craig Stillwater Morocco Aug 23, 2012 55429
Geoffrey Kirby Sonoma Heard Island and Mcdonald Islands Feb 11, 2012 36110
Kylynn Sweeney Gilbert Greece Mar 27, 2011 31878
Celeste Gilliam Ketchikan Armenia Oct 18, 2011 90753
Travis Buckner Hot Springs Saint Pierre and Miquelon Sep 1, 2012 50696
Deanna Buckner Gloversville Mongolia Mar 6, 2012 36838
Nicholas Vang North Chicago Cameroon Jun 10, 2012 57392
Dominic Thompson North Little Rock Oman Oct 21, 2012 63825
Kenyon Good Port Arthur Thailand Sep 16, 2011 33424
Dominique Gentry Clemson Turkey Nov 16, 2011 52636
Rachel Robinson Hastings Iran, Islamic Republic of Dec 20, 2011 68943
Beau Murray Aguadilla Slovenia Jun 23, 2011 64758
Fay Coffey Waterloo Liberia Jun 29, 2011 23261
Anjolie Hudson Villa Park Israel Sep 12, 2012 61595
Aurora Wilcox Des Moines Belgium Aug 1, 2011 94743
Graiden Cantu Caguas French Guiana Aug 26, 2012 47270
Ifeoma Snyder Stockton Grenada Dec 21, 2012 64082
Fatima Dillard Minot Malta Jun 5, 2012 22642
Elvis Hurst Fairfax Iraq Jul 31, 2011 49754
Tyrone Medina Fond du Lac Serbia and Montenegro Sep 18, 2012 71427
Eleanor Moran Ventura Switzerland Jun 25, 2011 37410
Maris Thomas Roswell Uganda Feb 1, 2012 13281
Herman Webster Oak Ridge Peru Jul 6, 2011 64747
Vladimir Mccormick Durant Taiwan, Province of China Feb 6, 2011 74553
Whilemina Mcbride New Castle Puerto Rico Sep 21, 2011 36301
Harper Fitzgerald Duquesne Antarctica Aug 11, 2012 94535
Sybill Collins Manassas British Indian Ocean Territory Aug 21, 2012 55119
Tallulah Mathews Berkeley Liechtenstein Sep 24, 2012 39287
Scarlett Freeman New Haven Belarus Jul 16, 2011 38373
Ursa Reid Lockport Kazakhstan Dec 13, 2011 13237
Whoopi Mendez Nashville Antarctica Sep 2, 2011 59088
Summer Everett St. Marys Liberia Nov 14, 2012 98078
Pascale Buckner Rapid City Dominican Republic Jan 26, 2011 58219
Aladdin Ball Charleston Netherlands Antilles Jun 11, 2011 96308
Cyrus Parker Dixon Belgium May 13, 2012 52863
Drake Rhodes Moultrie American Samoa Jun 23, 2012 74539
Germaine Castro Richland Liechtenstein Dec 28, 2011 63845
Destiny Pickett Forest Lake Libyan Arab Jamahiriya Oct 25, 2012 19834
Lars Bishop Sun Valley Cayman Islands Nov 22, 2012 51458
Irma Barton New Madrid Christmas Island Apr 5, 2011 55391
Uriah Wilkerson Des Moines Cuba Aug 2, 2011 56456
Meredith Perkins Morgantown Mali Jul 7, 2012 20346
Meredith Shaw Chicago Heights Faroe Islands Oct 14, 2011 45907
Kendall West Hartford San Marino Nov 5, 2011 95793
Ignacia Benton Oxford Albania Dec 22, 2011 16838
Buffy Holder Uniontown France Dec 26, 2011 14356
Robert Knight Alameda Chile Aug 24, 2012 47454
Alyssa Lane Lansing Poland Oct 17, 2012 13091
Eaton Dominguez Laconia Cocos (Keeling) Islands Mar 6, 2012 19370
Lionel Henry New Bedford Nauru Feb 1, 2012 91015
Alexa Alvarado Irving Lithuania Aug 29, 2011 72668
Alfonso Holcomb Washington Liberia Sep 9, 2012 35378
Simone Morin Pembroke Pines Kuwait Jun 4, 2012 40163
Winifred Valencia Grand Rapids Guyana Jun 13, 2011 52119
Nigel Brady Torrance Nigeria Sep 4, 2012 25328
Knox Cantu Savannah Dominican Republic Oct 23, 2012 47569
Ezekiel Bowers Georgetown Northern Mariana Islands Nov 9, 2012 81979
Deanna Irwin Toledo Cambodia Jul 7, 2011 95674
Hoyt Fuentes Bloomington Cyprus Oct 25, 2012 48163
Kamal Yates Los Angeles Suriname Apr 9, 2011 41892
Charlotte Alexander Seaford Belarus Aug 10, 2011 39729
Rana Mcdonald Norwich Tanzania, United Republic of Apr 28, 2012 34045
Kennedy Santiago El Cerrito Aruba Sep 25, 2012 80367
Lois Kelly San Francisco Ireland Nov 15, 2011 58415
Jenna Manning Cambridge Bouvet Island Oct 11, 2011 67687
Eden Mckee Kokomo Marshall Islands Aug 7, 2011 79335
Jael William El Cerrito Dominican Republic Jun 9, 2011 97577
Emma Hughes Marlborough Israel Nov 3, 2011 49415
Kirsten Estes Astoria Algeria Apr 8, 2012 54645
Anjolie Sargent Laguna Beach Gambia Feb 15, 2011 22452
Dale Wall Murray Samoa Nov 17, 2012 74859
Chaim Morin Yonkers Costa Rica Oct 4, 2012 33924
Dylan Casey Bethlehem Saint Lucia Oct 23, 2011 33073
Quincy Morales Commerce Guatemala Aug 7, 2012 66255
Simon James Elko Sweden Jan 14, 2011 78769
Shoshana Wooten Valdosta United Kingdom Dec 4, 2011 54634
Macey Rogers Carbondale Solomon Islands Jan 17, 2012 69135
Ezra Logan Calumet City Monaco Nov 26, 2011 29331
Rylee Dyer Council Bluffs Saint Helena Dec 23, 2011 23793
Raven Velazquez Washington Tuvalu Jan 12, 2012 22906
Plato Boyer Pasco Timor-leste Mar 13, 2011 19451
Hayley Wheeler Hampton Morocco Nov 14, 2011 86373
Zane Morgan Saint Joseph Ukraine Feb 19, 2012 81948
Cassandra Guerrero Thibodaux Sweden Apr 14, 2011 16254
April Cabrera Ardmore Ireland Nov 28, 2011 86589
Branden Maddox Leominster Tokelau May 26, 2011 11319
Eugenia Duke Hialeah Colombia May 12, 2012 54556
Boris Mullen Newburgh Burkina Faso Dec 9, 2011 49827
Urielle Pollard Yuma Iran, Islamic Republic of Nov 8, 2012 60607
Althea Foley Scottsbluff Iraq Jun 3, 2012 69002
Paula Booker Frankfort Guinea-bissau Jan 10, 2012 40317
Kessie Harmon Beaumont Mali Apr 21, 2012 11691
Shaine Randolph Fullerton Norway Aug 22, 2011 60811
Tamekah Salinas Norwich Colombia Oct 11, 2012 14711
Dante Lang Kankakee French Polynesia Apr 14, 2012 73657
Blair Hamilton Kona Ireland Jan 2, 2012 36851
Ciaran Ray Bridgeport Swaziland Mar 1, 2012 72915
Lester Holcomb Danbury Antigua and Barbuda Jun 7, 2012 83293
Iris Jenkins Concord Tonga Jan 15, 2011 45170
India Blackburn Cedar Falls Mali May 30, 2011 11844
Gemma Decker Ketchikan Mayotte Aug 19, 2012 28846
Graham Green Pascagoula Martinique Sep 7, 2012 69740
Cedric Carlson Rapid City Gambia Feb 18, 2012 14817
Kellie Mullen Fairmont Western Sahara Jun 15, 2012 18378
Dominic Humphrey Kingston Uruguay Dec 5, 2012 32145
Jason Noel Hoboken Congo Jun 17, 2012 25643
Jana Burke Sharon Saint Kitts and Nevis Jan 14, 2011 45295
Griffith Hahn Spartanburg South Africa Oct 6, 2011 12676
Blaine Callahan Pittsfield Libyan Arab Jamahiriya Jan 2, 2012 23984
Hanna Marshall Erie Cook Islands Mar 7, 2011 42188
Zoe Armstrong Raleigh Swaziland Jul 22, 2011 44114
Hilda Avery Lowell Bhutan Oct 11, 2011 91133
Daryl Hoover La Puente Macedonia Dec 19, 2011 59209
Dennis Hammond Midwest City Yemen Oct 30, 2011 97193
Ferdinand Cline Yorba Linda Sri Lanka May 12, 2011 77321
Zachery Skinner Columbus Kazakhstan Apr 29, 2011 64882
Ronan Young Wynne Haiti Feb 6, 2011 60565
Adam Jimenez Reedsport Afghanistan Jul 24, 2011 20839
Patricia Bridges Wichita United Arab Emirates Jun 4, 2012 55918
Hayfa Hicks Long Beach Haiti Sep 23, 2012 77954
Cain Lott Detroit Togo Oct 14, 2011 12719
Chandler Fernandez Camden Cambodia May 10, 2012 19072
Josiah Small Macon Albania Jul 27, 2012 13477
Leila Bates Montpelier Somalia Nov 28, 2012 90708
Sydney Grimes Cleveland American Samoa Jan 20, 2012 24356
Boris Stuart Alhambra New Zealand Jan 16, 2011 87257
Ina Newman Tuscaloosa Algeria May 18, 2012 39232
Otto Mcbride Pendleton Turks and Caicos Islands Jul 26, 2011 72726
Ivana Gay Monterey Park Kiribati Jul 7, 2012 80598
Rajah Fitzpatrick Kennesaw Panama Jun 15, 2011 30196
Quincy Klein Santa Ana Kiribati Feb 8, 2011 89951
Ina Cabrera Davis Algeria Jun 13, 2012 40568
Autumn Summers Niagara Falls Malawi Apr 24, 2011 30348
Fleur Carlson Radford British Indian Ocean Territory Nov 9, 2011 28323
Cara Fuentes Gettysburg Haiti Nov 17, 2011 70564
Caldwell Foley Miami Beach Saudi Arabia Dec 9, 2011 17992
Kamal Madden Diamond Bar Dominica Jul 8, 2011 35318
Holly Elliott Myrtle Beach Rwanda Feb 19, 2012 89319
Sydney Stout Clovis Japan Sep 11, 2011 82267
Jakeem Russell Guayanilla Papua New Guinea Feb 4, 2011 66862
Odette Munoz Tonawanda Gambia Mar 11, 2011 98220
Virginia Montgomery Stamford Bouvet Island Apr 27, 2011 47952
Jack Glass Decatur Solomon Islands Jan 8, 2012 18843
Cherokee Holloway Riverton Belgium Apr 19, 2011 44159
Yuli Carter Aliquippa Suriname Nov 17, 2011 32012
Rylee Coleman Morgantown Aruba Nov 25, 2011 12895
Walter Guzman La Verne Philippines Dec 20, 2012 15512
Jayme Cotton Cypress Latvia Apr 22, 2012 37823
Maryam Patton Liberal Djibouti Jul 20, 2011 13823
Bo Fisher Iowa City Moldova Feb 20, 2011 12010
Teegan Holmes Delta Junction Botswana May 10, 2011 53872
Rhona Gentry Corinth France Oct 6, 2011 22170
Jennifer Carpenter Janesville Tokelau Jan 14, 2011 76200
Kiara Chambers City of Industry Sao Tome and Principe Jul 21, 2011 75843
Gray Hanson Bayamon Mauritius Apr 23, 2011 59870
Lucius Lowery Pittsburgh Antigua and Barbuda Nov 25, 2011 73768
Vivien Kennedy Sturgis Botswana Feb 6, 2012 81110
Amity Hardin Claremore Bosnia and Herzegovina Jun 13, 2012 84046
Aladdin Walton Hartford Qatar Jan 21, 2012 18600
Buckminster Welch Moultrie Albania Sep 1, 2011 25530
Arthur Davidson Miami Dominica Sep 13, 2012 48935
Troy Wyatt Haverhill Faroe Islands Feb 11, 2012 19612
William Valenzuela Bay St. Louis Malta Jan 17, 2011 62300
Darryl Joyce Santa Cruz Slovakia Nov 9, 2011 35416
Derek Carver Escondido New Zealand Jan 17, 2011 78970
Mannix Rutledge Pasadena Philippines Apr 8, 2012 32548
Galvin Vazquez Rancho Cucamonga Burundi Sep 1, 2011 57637
Ferris Lynch Parma Morocco Oct 12, 2011 48969
Harriet Conner Decatur Egypt Mar 3, 2011 12245
Veda Craft Madison Norfolk Island May 18, 2012 78049
Kasimir Murphy Brookings Estonia Mar 6, 2011 66453
Henry Cummings Seal Beach Netherlands Antilles Jul 19, 2012 25952
Dacey Ayers Hickory Saint Lucia Mar 9, 2012 44174
Virginia Reese Ashland Australia May 12, 2012 75418
Bertha Whitehead Washington Tuvalu Mar 2, 2011 36257
Xandra Simmons Gadsden Grenada Aug 28, 2011 88873
Gavin Byrd Nogales Haiti Jan 31, 2012 77276
Rinah Dillard Pomona Saint Kitts and Nevis Jan 20, 2011 79816
Maryam Bean New Rochelle Viet Nam Jan 6, 2012 24359
Ulysses Lee Fallon Martinique Jan 2, 2012 41896
Sebastian Grant Murray Marshall Islands Sep 29, 2012 94255
Amal Riggs Wynne Norway Aug 24, 2011 15807
Stephanie Graham Muncie Canada Jan 28, 2011 26309
Jescie Holland Mason City Bangladesh Apr 27, 2011 95718
Quinn Watkins Powell Saint Vincent and The Grenadines Oct 29, 2011 63038
Kitra Bates Waukegan Cambodia Aug 23, 2012 32026
Aladdin Hurley Paramount Mauritania May 17, 2011 19926
Fitzgerald Edwards Basin Armenia Sep 16, 2011 71509
Quamar Pennington Radford Poland Mar 29, 2012 59219
Preston Rowe Alameda Jamaica Jun 24, 2011 63620
Merritt Dennis Stafford Reunion Jan 24, 2011 60241
Jena Sawyer Escondido Congo Jul 11, 2011 93011
Marny Hess Poughkeepsie Niue Sep 8, 2011 19965
Kiona Francis Grand Junction Indonesia Jan 29, 2011 41544
Zelda Sykes City of Industry Equatorial Guinea Jul 8, 2011 15358
Carla Horne Lake Forest Timor-leste Jul 10, 2011 63680
Hilel Shelton Truth or Consequences Saint Lucia Aug 1, 2011 81858
Tanisha Grant Peekskill Bahamas Sep 18, 2011 61071
Ayanna Cohen Alexandria Mauritius Oct 1, 2012 25891
Madison Rutledge Aliquippa Malawi Dec 14, 2011 84684
Orson Owens Columbia Ireland Jun 10, 2012 30998
Beatrice Vang Isle of Palms Bhutan Jun 26, 2011 65410
Kiayada Campos Jackson Mauritius May 19, 2011 66304
Willow Moses Gaithersburg Burundi Feb 22, 2012 80779
Karyn Page Plainfield United Arab Emirates May 31, 2011 94335
Mannix Briggs Belpre Austria Mar 16, 2011 95369
Blythe Schultz Muskogee Israel May 6, 2011 20566
Nita Jenkins Scottsbluff Indonesia Apr 15, 2012 23854
Quinn Farley Eatontown Svalbard and Jan Mayen Mar 27, 2011 50873
Fay Kramer Evansville Turkmenistan Mar 17, 2011 58959
Lane Strong Altoona Holy See (Vatican City State) Oct 10, 2011 68918
Amir Bailey Visalia French Guiana Oct 3, 2012 66206
Trevor Watts Carolina Cocos (Keeling) Islands Mar 28, 2012 65347
Zia Browning Liberal American Samoa Jan 30, 2012 73063
Carly Potter Pullman Benin Jul 25, 2011 99675
TaShya William Waycross Angola Feb 1, 2011 67461
Cruz Eaton Rensselaer Qatar Oct 17, 2012 27912
Idona Valentine Wahoo Cambodia Mar 2, 2011 83045
Hadassah Burks San Bernardino Gabon Mar 25, 2012 45601
Sylvester Rogers Olympia New Caledonia Jan 22, 2011 66135
Constance Blackburn Mayagüez Cameroon Sep 30, 2012 42426
Raphael Flowers Lander Mexico Jun 23, 2012 17684
Burke Ramsey Sunbury Singapore Apr 25, 2012 44729
Stephen Meyer La Cañada Flintridge Indonesia Jan 19, 2011 90023
Devin Holt College Park Saint Helena Jun 22, 2011 30701
Lynn Obrien Winnemucca Lesotho Feb 7, 2012 34481
Lester Jones Toledo Australia Dec 31, 2012 44838
Paul Shepherd Selma Ukraine Nov 7, 2011 34189
Chaim Williamson Waycross Cameroon Mar 26, 2012 20787
Logan David Nacogdoches Liechtenstein Sep 20, 2012 77349
Helen Brady Morrison Cuba Feb 11, 2011 47325
Alea Floyd Hollister Virgin Islands, British Mar 13, 2012 12323
Baker Rosales East Hartford Panama Jul 31, 2011 57605
Colleen Wallace Newburgh Slovakia Dec 20, 2011 18444
Maggie Holcomb Hollister Andorra Jan 19, 2011 15451
Ryder Terry Springfield Bangladesh May 31, 2011 22406
Elizabeth Serrano Bellflower Turks and Caicos Islands Jun 15, 2012 97667
Neville Best Huntington Park Belize Nov 7, 2012 77231
Akeem Hobbs North Pole Tanzania, United Republic of Oct 24, 2011 67426
Dane Farrell Lafayette French Southern Territories Nov 14, 2012 98631
Otto Hernandez Bandon Burkina Faso Sep 10, 2011 59586
Chelsea Burks Wilmington Sri Lanka Dec 2, 2012 14442
Maxine Sampson Gastonia Bouvet Island Jul 16, 2011 94283
Martha Austin Great Falls Philippines Aug 20, 2011 94790
Melodie Kelley Baton Rouge Niger Nov 6, 2012 72120
Iola Phelps Little Rock Samoa Feb 27, 2011 61857
Adara Vinson Nacogdoches Guam Jun 10, 2012 56513
Hyacinth Lopez Alameda Kyrgyzstan Nov 13, 2012 64215
Zelda Castillo Gardner Lesotho Oct 10, 2012 45521
Raymond Drake Gardena Holy See (Vatican City State) Sep 9, 2012 12840
Gavin Simpson Modesto Guadeloupe May 15, 2011 46777
Jamalia Barry Milwaukee Serbia and Montenegro May 14, 2012 28311
Alyssa Keith Knoxville Guinea Nov 30, 2011 77779
Aretha Dickson Nacogdoches Nicaragua Oct 17, 2012 50273
Nadine Dillard Layton Egypt Feb 10, 2012 50001
Chastity Paul Waco Nigeria Jul 17, 2012 64750
Calvin Tran South Gate Saint Lucia Apr 4, 2012 51272
Hanna Hendricks Pierre Tajikistan Jun 26, 2011 61236
Shay Thornton Everett Senegal Dec 26, 2012 49295
Sonia Trujillo Gold Beach Portugal Dec 18, 2011 88606
Remedios Conner Everett Liberia Sep 27, 2012 93858
Kelly Cook Sheridan Somalia Aug 11, 2012 93466
Adrienne Kim Signal Hill Guadeloupe Feb 18, 2011 14452
Daquan Miller Duluth Madagascar Dec 2, 2011 83174
Dorothy Salas Albuquerque Bolivia Jul 24, 2012 20452
Octavia Mcclain New Haven Mauritania Sep 13, 2012 89452
Cooper Holt Los Angeles Korea Dec 4, 2012 14399
Dane Doyle Springfield Dominican Republic Nov 2, 2012 82940
Willow Wooten Homer Micronesia Mar 7, 2011 63843
Jerome Petty Asheville Yemen Feb 23, 2011 63889
Adrienne Mullen Spartanburg Tajikistan May 10, 2012 65453
Whilemina Albert Nashville Greenland Dec 12, 2012 26021
Lawrence David Truth or Consequences Nepal Jul 27, 2011 12423
Inez Berry Parkersburg Faroe Islands Apr 11, 2012 58958
Tatyana Nunez Merced Lithuania Apr 30, 2011 46279
Stuart Osborne Newport Saudi Arabia Jun 20, 2012 93292
Wallace Bryan Yorba Linda Netherlands Antilles Jan 22, 2011 93991
Indigo Burgess Nevada City Western Sahara Sep 5, 2012 30552
Moses Craig Vancouver French Southern Territories Sep 18, 2011 84475
Randall Bray Waltham Saudi Arabia Jul 28, 2011 93371
Sonia Moss Auburn Kyrgyzstan May 29, 2012 49758
Yeo Monroe Ocean City Trinidad and Tobago Apr 2, 2011 35465
Uriah Farmer Helena Syrian Arab Republic Jul 18, 2012 46976
Natalie Torres Battle Creek Russian Federation May 14, 2012 41665
Vaughan Hines Woodruff Monaco Aug 14, 2012 74388
Paki Washington York Bouvet Island Jun 9, 2011 33377
Holmes Knight Chickasha Kuwait Feb 16, 2011 65302
acqueline Whitaker Astoria Western Sahara Apr 22, 2012 94179
Jermaine Maldonado Taylorsville Kuwait Dec 18, 2012 40460
Cara Branch South El Monte Gambia Jan 14, 2012 90422
Germaine Pratt Springfield Holy See (Vatican City State) Jan 28, 2011 61328
Laith Moon Calabasas Kazakhstan Apr 25, 2011 84477
Xavier Soto Vermillion Somalia Jul 21, 2012 68063
Vincent Mccarty Hermosa Beach Sierra Leone Feb 20, 2011 41500
Elmo Frank Woonsocket Iraq Jan 31, 2011 93377
Oliver Osborne San Diego Niue Aug 4, 2011 43556
Aquila Weeks West Haven Japan Aug 5, 2011 35863
Elijah Walters Murfreesboro Ethiopia Feb 23, 2011 18593
Kameko Williamson San Fernando France Aug 24, 2011 35638
Caesar Rivera Downey Benin May 29, 2011 70156
Angelica Dale Needham Niue Nov 28, 2011 32735
Wyatt Berg Derby Saint Lucia Feb 1, 2011 78528
Ulric Richmond Marshall Canada Oct 11, 2011 16814
Kirk Mayer Fernley Cape Verde Mar 8, 2011 71848
Jermaine Mendez Riverside Pitcairn Dec 7, 2012 26973
Cedric Nielsen West Lafayette Poland May 23, 2012 98637
Amos Eaton Miami Beach Greenland Feb 5, 2011 80953
Daryl Juarez Huntington Park Zimbabwe Feb 15, 2011 87980
Wade Green Marshall Trinidad and Tobago Sep 21, 2011 48791
Katell Harding Perth Amboy Barbados Mar 23, 2011 88383
Mason Vega Guánica Austria May 13, 2012 11121
Theodore Dorsey Hastings Japan Jan 10, 2011 22586
Eric Kinney Manassas Park Zimbabwe Apr 6, 2011 81470
Fay Rivas Portland Pakistan Apr 29, 2011 57277
Mia Mccormick Saint Albans Armenia Jun 28, 2011 52182
Xaviera Brady Whittier Libyan Arab Jamahiriya Apr 22, 2012 88677
Abbot Frost Norwalk Puerto Rico Apr 11, 2012 13782
Orlando Ryan Newport Beach Lithuania Apr 14, 2011 29880
Rinah Huff Fullerton Saudi Arabia Sep 26, 2011 39492
Laura Mendez North Little Rock Cyprus Feb 8, 2012 85620
Paloma Mathews Norwalk Guinea Mar 22, 2012 55662
Olga Morgan West Valley City Argentina Dec 29, 2012 15762
August Conner Parkersburg Puerto Rico Nov 25, 2011 26509
Xander Huff Riverton Nauru Sep 1, 2011 94997
Germane Becker Morgan City Gabon Aug 8, 2011 85931
Lunea Shaffer Astoria Finland Sep 6, 2012 12134
Ava Lynch Lakewood Sri Lanka Jun 6, 2011 99707
Colin Kerr Bandon Slovakia Mar 27, 2012 60649
Sydnee French Hoover Tuvalu May 29, 2012 96750
Vincent Velasquez Lowell Iran, Islamic Republic of Apr 27, 2012 87557
Ifeoma Chambers Guayanilla Kyrgyzstan Dec 21, 2012 39714
Fritz Bowman North Pole Reunion Feb 12, 2011 56527
Giacomo Britt Kearney Taiwan, Province of China Aug 7, 2011 53705
Benjamin Barton Northampton Kenya Apr 10, 2012 85073
Jessamine Patrick Ventura Brazil Aug 26, 2011 58440
Madonna Nolan North Little Rock Bahrain Apr 30, 2011 90700
Lacey Kerr Watertown Cook Islands Oct 6, 2011 27521
Hunter Bray Tucson Gibraltar Oct 30, 2012 63157
Bruno Black El Monte Sao Tome and Principe Apr 7, 2011 40092
Eugenia Houston Sheridan Ecuador Jan 31, 2011 39917
Mia Robertson Jenks Micronesia Dec 9, 2011 42336
Yoko Hammond Johnson City Dominica Sep 14, 2011 93520
Illana Fisher Hawaiian Gardens Egypt Nov 9, 2011 46651
Lenore Clemons Columbia Andorra Jul 20, 2011 92360
Alec Norris Fitchburg Kenya May 18, 2012 10905
Tanisha Whitley Fontana Eritrea May 25, 2012 82800
Merritt Olsen Worland Switzerland May 7, 2011 87447
Edward Holcomb Marshall Monaco Aug 6, 2012 61315
Ursa Frazier Marshall Cuba Jul 26, 2011 24337
Myra Oneill Somerville Palau May 27, 2012 84087
Lane Copeland Easthampton Bolivia Apr 16, 2011 98227
Harriet Witt Farmington Turks and Caicos Islands Apr 10, 2012 72511
Imogene Holman Hermosa Beach Estonia Jun 21, 2012 76124
Germane Cross Waltham Myanmar Oct 30, 2012 82327
Skyler Vargas San Bernardino Cameroon Sep 15, 2011 79466
Clinton Ortega Crown Point Montserrat May 11, 2012 24649
Karleigh Cooke Hawaiian Gardens Kenya Feb 10, 2012 73887
Gisela Hoover Newport News Burkina Faso Jan 13, 2012 45465
Hayes Colon Beverly Morocco Nov 5, 2011 78814
Jasmine Glover Westlake Village Suriname Aug 1, 2011 20519
Morgan Obrien Methuen French Southern Territories Nov 1, 2012 78567
Genevieve Castro West Covina Israel Jul 15, 2012 37708
Iona Knapp Ogden Hungary May 17, 2012 54340
Abraham Browning Citrus Heights Mauritius Mar 29, 2011 53530
Wylie Fisher North Platte Turkmenistan Mar 13, 2011 72092
Kaden Knapp Corinth Canada Nov 18, 2011 13259
Lane Hopper Cedar Falls Saint Helena Aug 9, 2012 70839
Clark Pickett Westminster Svalbard and Jan Mayen Jan 28, 2011 38246
Ima Brewer Dover Dominica Apr 12, 2012 87923
Ivana Bentley Anchorage Montserrat Jul 9, 2012 51544
Alexa Bowen El Monte Belarus Oct 11, 2010 84775
Chaim Chavez Vineland Iran, Islamic Republic of Aug 6, 2010 17277
Forrest Hickman Cedar Falls Grenada Nov 17, 2011 57833
Teagan Boyle New Kensington Cayman Islands Jun 19, 2011 16784
Robert Prince Duluth Rwanda Aug 4, 2011 26445
Elmo House Naperville Jamaica May 15, 2012 36274
Susan Webster Hialeah Libyan Arab Jamahiriya Aug 5, 2010 39872
Keelie Gomez Bellflower Sao Tome and Principe May 25, 2012 59393
Jessica Potts York Belgium Mar 16, 2012 77425
Naida Anthony Pittston Bangladesh Apr 23, 2011 25448
Lysandra Ryan Macomb Papua New Guinea Mar 7, 2011 42613
Kyla Harrington Boulder Martinique Nov 24, 2011 53564
Uriah Graham Littleton Netherlands Antilles Jul 24, 2012 75568
Damian Valentine Marshall Saint Pierre and Miquelon Sep 5, 2012 34683
Tallulah Olson Orlando Western Sahara Feb 10, 2012 93023
Ashely Dillard Evanston Mexico Jun 25, 2011 89936
Amery Aguirre Santa Clara Monaco Feb 24, 2010 84137
Hermione Savage Longview Bahamas Jun 21, 2011 57413
Yuli Heath Roswell El Salvador Jan 21, 2012 76836
Jackson Young Richland Egypt Aug 20, 2010 63793
Bernard Barker Irwindale Namibia May 8, 2010 72461
Sebastian Elliott Boulder Namibia Aug 13, 2010 27289
Danielle Bowman Columbus Yemen Mar 19, 2011 22118
Lois Carpenter Citrus Heights Angola Feb 22, 2011 57546
Roary Hodge San Jose Turkey May 8, 2012 65655
Jarrod Bean Plantation Norfolk Island Apr 22, 2012 52368
Mikayla Newton New Iberia Svalbard and Jan Mayen Aug 30, 2010 73613
Jane Foley Cape Coral Egypt Apr 18, 2012 44932
Rina Trevino Kansas City Macao Sep 6, 2010 66005
Jamal Owens Fallon Bangladesh May 15, 2012 94380
Griffith Hahn Dothan Liechtenstein Jun 9, 2010 19795
Lesley Holman Allentown Antarctica Jan 24, 2012 58357
Bryar Austin Dickinson Iraq Jan 20, 2010 37722
Joan Russell Pasadena Qatar Apr 21, 2010 81376
Ava Browning Denver Benin Aug 8, 2012 31651
Chester Schneider El Paso Ireland Jun 15, 2010 67225
Warren Harvey Kalamazoo New Zealand Feb 2, 2011 51295
Aubrey Ross Milford French Guiana Mar 10, 2011 25247
Roary Mack Yonkers Bangladesh Jan 24, 2011 41355
Roth Sears Reno Egypt Apr 19, 2011 74318
Skyler Dale Loudon Ireland Aug 13, 2012 54593
Castor Rocha Azusa Cape Verde Jun 27, 2011 35174
Maris Bailey Bremerton Holy See (Vatican City State) Jul 26, 2011 45543
Zoe Shaffer New Brunswick Luxembourg Nov 27, 2010 89966
Tamekah Frazier Oxford United Kingdom May 6, 2011 26346
Camilla Hyde Cudahy Equatorial Guinea Oct 24, 2011 82129
Josiah Rivers Nome Bosnia and Herzegovina Feb 16, 2012 44720
Barbara Clements Philadelphia Saint Vincent and The Grenadines Jul 2, 2010 19925
Dominique Copeland Monongahela Latvia May 3, 2010 77608
Benjamin Ayers Manassas Park Romania Sep 22, 2010 92397
Quyn Bray Blythe Korea, Republic of Jun 20, 2012 71773
Deirdre Mathews Thibodaux Spain Jul 4, 2012 80830
Rachel Rasmussen Scarborough French Guiana May 11, 2011 20930
Alexandra Buck Danville Bouvet Island Dec 1, 2012 66928
Thomas Jennings Corvallis Sierra Leone Nov 2, 2011 82381
Geoffrey Battle Mesquite Cape Verde Jan 11, 2011 51073
Lee Clements Minnetonka Slovakia May 3, 2010 18778
Devin Ewing Missoula Korea, Republic of Mar 5, 2012 99433
Alexandra Rodgers Auburn Monaco Nov 6, 2010 79762
Kasimir Hoover West Haven Belgium Feb 29, 2012 64648
Conan Carroll Temecula Seychelles Sep 4, 2011 19256
Frances Cotton Texarkana Guinea-bissau Apr 5, 2010 66057
Charles Hess Bay St. Louis Burkina Faso Jul 19, 2011 35043
Georgia Morse Jeffersontown Czech Republic Jan 5, 2011 42891
Cleo Parsons Mission Viejo Benin Mar 8, 2012 84366
Jarrod Welch Dubuque Malaysia Oct 3, 2012 33928
Quinn Shepherd Urbana Colombia Dec 17, 2011 65585
Madonna Nguyen Galveston Colombia May 6, 2012 39223
Karly Patterson Fairbanks Saint Vincent and The Grenadines Jun 4, 2011 99687
Garrison Morales Signal Hill Egypt Feb 5, 2012 15949
Nathaniel Rosa Radford Andorra Mar 11, 2012 69517
Sophia Page Hartford Cambodia Sep 27, 2012 45944
Wylie Ayers Athens Singapore May 15, 2011 88601
Wilma Morse Orlando Papua New Guinea Sep 18, 2010 42911
Patience Benton Bayamon Botswana Jan 28, 2010 46908
Cadman Hubbard Kahului Chile Mar 27, 2011 10924
Samantha Matthews Olympia Liberia Jan 9, 2012 41131
Roary Carrillo Independence Tanzania, United Republic of Dec 13, 2010 89903
Heidi Knowles Glens Falls Sudan May 13, 2011 25299
Portia Guthrie Redlands Iran, Islamic Republic of Jul 14, 2011 22884
Grace Duncan Farmington San Marino Sep 27, 2010 78597
Ian Walter Enid Saint Pierre and Miquelon Mar 28, 2011 89844
Julian Jarvis Eden Prairie Dominica Nov 20, 2011 72256
Quinn Kent Webster Groves Azerbaijan Jan 14, 2012 24170
Ignatius Ayala Bossier City Paraguay Dec 26, 2012 43263
Aidan Parker Sitka Estonia May 4, 2010 57859
Sydnee Burton Apple Valley Spain Oct 19, 2010 56678
Wing Hahn Medford Austria Nov 18, 2011 21517
Bell Jefferson Sheridan United Kingdom Feb 11, 2011 11836
Mikayla Simpson Cedar Rapids Philippines Nov 19, 2012 95092
Bianca Boyer Gainesville Niue Jan 23, 2010 49385
Ciara Crawford Tyler Antarctica Jul 13, 2012 79513
Sasha Jarvis New Madrid Virgin Islands, U.S. Feb 14, 2011 49687
Blythe Woodward Mankato Israel Nov 19, 2011 94109
Anne Weaver Cedar Rapids Viet Nam May 31, 2012 48021
Kylee Walsh Tok Chile Nov 15, 2011 42566
Mercedes Gilmore Green Bay Colombia May 15, 2010 66483
Keaton Nielsen Monterey Pakistan Jan 2, 2011 16342
Morgan Tyson Alamogordo Moldova May 31, 2011 88703
Venus Sargent Dana Point Falkland Islands (Malvinas) Oct 15, 2012 89640
Katelyn Bruce Meriden Bermuda Mar 30, 2010 11089
Ross Caldwell Vergennes South Georgia and The South Sandwich Islands Oct 15, 2011 91296
Cynthia Larsen Powell Japan Dec 18, 2010 11310
Wyoming Cash Burlington Macedonia Sep 10, 2011 24041
Vanna Ingram Falls Church Sweden Apr 24, 2012 51287
Wallace Mays Winooski Oman Mar 26, 2012 13627
Jasper Sears Coos Bay Montserrat Feb 22, 2010 23076
Clinton Foley New Albany Libyan Arab Jamahiriya Feb 25, 2010 86135
Jesse Sweet Jamestown Korea Apr 3, 2012 20037
Abigail Guerra Warwick Comoros Mar 12, 2010 11847
Linda Lucas Gainesville Costa Rica Apr 8, 2010 15278
Hasad Willis Webster Groves Solomon Islands Oct 21, 2011 23930
Rhea Jenkins Malden Rwanda May 15, 2012 42759
Gay Lott Union City Norway Jun 25, 2010 66935
Vanna Stuart Nevada City Thailand Aug 15, 2011 86717
Bert Lewis Gardner Netherlands Antilles Mar 27, 2010 14565
Melinda Nieves Murfreesboro Micronesia Feb 17, 2012 12357
Bevis Carson Twin Falls Portugal May 4, 2011 55060
Destiny Morse Asheville Montserrat May 15, 2012 92200
Indira English Moore Anguilla May 24, 2011 63852
Henry Kelly Rialto French Polynesia Feb 13, 2010 50835
Jemima Hubbard Bowling Green Lithuania Jan 15, 2011 48072
Kevin Colon Pendleton Brazil Oct 12, 2011 48952
Chester Frank Vernon United States Feb 20, 2010 91649
Yardley Mayo Guayanilla Barbados Jul 15, 2012 28804
Fletcher Mayer Hot Springs American Samoa May 25, 2010 51273
Chaim Hebert Rosemead Bhutan Jan 26, 2010 40706
Yael Stewart Valdosta Ghana Jul 5, 2010 78757
Lynn Davis Glens Falls American Samoa Dec 16, 2010 85887
Deanna Whitaker Durant Andorra Apr 18, 2012 36856
Mark Moore Claremore Mauritius Nov 26, 2010 51924
Jasper Carrillo Pendleton Slovenia Feb 26, 2012 66731
Mara Wilson Mount Vernon Timor-leste May 23, 2011 23185
Nash Mckenzie San Antonio Taiwan, Province of China Nov 22, 2011 57595
Chelsea Wade Palos Verdes Estates Timor-leste Dec 14, 2010 58960
Colleen English Madison Slovenia Jul 6, 2012 48007
Raphael Mckee Anderson Mexico May 15, 2011 80875
Zelda Bridges Portland Oman Dec 27, 2012 22586
Gavin Dunlap Idaho Springs Taiwan, Province of China Jul 16, 2010 36437
Wendy Wood Tok Virgin Islands, British May 7, 2011 16187
Mercedes Sampson Cicero Holy See (Vatican City State) Feb 10, 2010 89633
Brianna Flowers Catskill Maldives Jun 5, 2012 36980
Selma Olson Fajardo Russian Federation Nov 28, 2011 92402
Talon Hardin Pueblo Austria Sep 16, 2010 24422
Joy Frost Knoxville Niger Apr 30, 2012 62456
David Adams Elko Malaysia Oct 2, 2011 18044
Paula Moody Lake Charles Kuwait Feb 27, 2010 88109
April Gray Cody Macao Oct 12, 2011 36822
Indigo David Forrest City Philippines May 24, 2011 43871
Colorado Mendez Alexandria Paraguay Aug 12, 2010 81867
Marah Newman Chester South Africa Apr 5, 2010 84464
Lydia Hoover Baldwin Park Turkmenistan Aug 13, 2012 84024
Caldwell Carroll Kalispell Canada Jan 6, 2010 51769
Latifah Wallace Calumet City Russian Federation Jul 21, 2010 91338
Indigo Delgado Grambling Lebanon Sep 12, 2011 30225
Urielle Hayes Haverhill Guatemala Oct 2, 2011 27377
Sydney Matthews Calumet City Algeria May 25, 2012 94769
Blaine Vargas Clearwater Kazakhstan May 21, 2010 27036
Ulric Gordon Moscow Finland May 7, 2011 55246
Rina Howard Bellingham United Arab Emirates Oct 29, 2011 37461
Octavia Orr Decatur Tonga Jul 5, 2012 68834
Devin Dickerson Alameda Sweden Apr 20, 2011 61040
Kessie Carlson Allentown Nepal Jan 3, 2011 62411
Ciaran Wilkerson Enid Ireland Dec 9, 2010 43612
Paula Rasmussen New Bedford Saint Pierre and Miquelon Feb 27, 2012 83735
Cecilia Pierce Westfield Christmas Island Oct 28, 2012 92440
Ursa Campos Texas City Colombia Apr 16, 2011 18777
Zelenia Mcguire South Portland Myanmar Oct 10, 2012 93813
Mary Diaz Omaha Nauru Aug 23, 2012 63436
Adam Erickson Raleigh Tonga Dec 22, 2012 55020
Celeste Tran Bossier City Anguilla Aug 20, 2012 58914
Charity Vincent Salinas Svalbard and Jan Mayen Apr 12, 2012 27311
Reese Francis La Mirada Malawi Mar 9, 2012 76277
Germaine Cole North Las Vegas Jordan Nov 5, 2010 25574
Dana Mccray Bozeman American Samoa Dec 27, 2012 56998
Jeanette Morales Sharon United Arab Emirates Nov 10, 2012 88808
Oleg Day Battle Creek Guinea Feb 16, 2011 92338
Pascale Cooper Livonia Svalbard and Jan Mayen Mar 31, 2012 40378
Wyoming Odonnell Wilmington Seychelles Dec 4, 2011 72703
Giselle Small Vermillion Iran, Islamic Republic of Aug 11, 2012 69244
Martena Valdez Stamford Cambodia Oct 31, 2011 36493
Leo Juarez Wilmington Mayotte Jul 26, 2010 85336
Reese Holden Pembroke Pines Puerto Rico Sep 9, 2012 54075
Ciaran Finley Huntington Beach Azerbaijan Feb 20, 2010 69408
Ronan Adams Cedar Rapids Seychelles Mar 3, 2012 51064
Bradley Frederick Texas City Slovakia Dec 1, 2010 41919
Sean Jones North Little Rock Dominica Aug 2, 2010 83748
Garrett Henry Seattle Lebanon Jul 30, 2011 48446
Althea Robertson Reading Uganda Feb 10, 2012 94806
Matthew Webster Jacksonville Finland Oct 21, 2012 97297
Ignacia Wood Healdsburg Dominica Dec 28, 2012 37242
Risa Conway Bethlehem Malta Apr 23, 2011 48783
Olympia Merrill Hidden Hills Cambodia Jan 21, 2012 78313
Dennis Mclaughlin Reno Nicaragua Aug 28, 2012 43970
Ray Head Monongahela Tajikistan May 30, 2010 55532
Nayda Crawford Cairo Barbados Jun 9, 2012 86208
Dalton Mcdowell Kettering Virgin Islands, U.S. Jun 1, 2012 81139
Sacha Mathis Concord Hungary Mar 14, 2010 62233
Stupid-Table-Plugin-1.1.3/examples/multicolumn-sort.html000066400000000000000000000044271316766721000233260ustar00rootroot00000000000000 Stupid jQuery table sort

Multicolumn sort

This example shows how to perform a multicolumn sort. A multicolumn sort allows you to define what column to sort by in the event of a tie with two elements in the initial column sorted.

int float string
1 10.0 a
1 10.0 a
2 10.0 b
0 20.0 c
1 30.0 b
2 30.0 a
0 10.0 b
0 20.0 a
0 10.0 c
1 20.0 a
2 10.0 b
3 30.0 a
2 30.0 b
Stupid-Table-Plugin-1.1.3/examples/with-settings.html000066400000000000000000000056661316766721000226100ustar00rootroot00000000000000 Stupid jQuery table sort

StupidTable with settings

This page shows how specific behaviors can be introduced by providing settings to StupidTable. View the source of this page to see the settings in use.


Example 1

This table does not redraw when attempting to sort a column that has identical values in all rows.

int float string int (identical)
15 -.18 banana 99
95 36 coke 99
2 -152.5 apple 99
-53 88.5 zebra 99
195 -858 orange 99

var $table = $("#example-1");
$table.stupidtable_settings({
    should_redraw: function(sort_info){
      var sorted_column = sort_info.column;
      var first_val = sorted_column[0];
      var last_val = sorted_column[sorted_column.length - 1][0];

      // If first and last element of the sorted column are the same, we
      // can assume all elements are the same.
      return sort_info.compare_fn(first_val, last_val) !== 0;
    }
});
$table.stupidtable();
Stupid-Table-Plugin-1.1.3/package.json000066400000000000000000000012371316766721000175470ustar00rootroot00000000000000{ "name": "stupid-table-plugin", "version": "1.1.3", "description": "Stupidly simple jquery table sorting plugin", "main": "stupidtable.js", "directories": { "example": "examples", "test": "tests" }, "repository": { "type": "git", "url": "git+https://github.com/joequery/Stupid-Table-Plugin.git" }, "devDependencies": {}, "peerDependencies": { "jquery": ">= 1.7.0" }, "keywords": [ "table", "sort", "jquery" ], "author": "JoeQuery", "license": "MIT", "bugs": { "url": "https://github.com/joequery/Stupid-Table-Plugin/issues" }, "homepage": "https://github.com/joequery/Stupid-Table-Plugin#readme" } Stupid-Table-Plugin-1.1.3/stupidtable.js000066400000000000000000000223511316766721000201370ustar00rootroot00000000000000// Stupid jQuery table plugin. (function($) { $.fn.stupidtable = function(sortFns) { return this.each(function() { var $table = $(this); sortFns = sortFns || {}; sortFns = $.extend({}, $.fn.stupidtable.default_sort_fns, sortFns); $table.data('sortFns', sortFns); $table.stupidtable_build(); $table.on("click.stupidtable", "thead th", function() { $(this).stupidsort(); }); // Sort th immediately if data-sort-onload="yes" is specified. Limit to // the first one found - only one default sort column makes sense anyway. var $th_onload_sort = $table.find("th[data-sort-onload=yes]").eq(0); $th_onload_sort.stupidsort(); }); }; // ------------------------------------------------------------------ // Default settings // ------------------------------------------------------------------ $.fn.stupidtable.default_settings = { should_redraw: function(sort_info){ return true; }, will_manually_build_table: false }; $.fn.stupidtable.dir = {ASC: "asc", DESC: "desc"}; $.fn.stupidtable.default_sort_fns = { "int": function(a, b) { return parseInt(a, 10) - parseInt(b, 10); }, "float": function(a, b) { return parseFloat(a) - parseFloat(b); }, "string": function(a, b) { return a.toString().localeCompare(b.toString()); }, "string-ins": function(a, b) { a = a.toString().toLocaleLowerCase(); b = b.toString().toLocaleLowerCase(); return a.localeCompare(b); } }; // Allow specification of settings on a per-table basis. Call on a table // jquery object. Call *before* calling .stuidtable(); $.fn.stupidtable_settings = function(settings) { return this.each(function() { var $table = $(this); var final_settings = $.extend({}, $.fn.stupidtable.default_settings, settings); $table.stupidtable.settings = final_settings; }); }; // Expects $("#mytable").stupidtable() to have already been called. // Call on a table header. $.fn.stupidsort = function(force_direction){ var $this_th = $(this); var datatype = $this_th.data("sort") || null; // No datatype? Nothing to do. if (datatype === null) { return; } var dir = $.fn.stupidtable.dir; var $table = $this_th.closest("table"); var sort_info = { $th: $this_th, $table: $table, datatype: datatype }; // Bring in default settings if none provided if(!$table.stupidtable.settings){ $table.stupidtable.settings = $.extend({}, $.fn.stupidtable.default_settings); } sort_info.compare_fn = $table.data('sortFns')[datatype]; sort_info.th_index = calculateTHIndex(sort_info); sort_info.sort_dir = calculateSortDir(force_direction, sort_info); $this_th.data("sort-dir", sort_info.sort_dir); $table.trigger("beforetablesort", {column: sort_info.th_index, direction: sort_info.sort_dir, $th: $this_th}); // More reliable method of forcing a redraw $table.css("display"); // Run sorting asynchronously on a timout to force browser redraw after // `beforetablesort` callback. Also avoids locking up the browser too much. setTimeout(function() { if(!$table.stupidtable.settings.will_manually_build_table){ $table.stupidtable_build(); } var table_structure = sortTable(sort_info); var trs = getTableRowsFromTableStructure(table_structure, sort_info); if(!$table.stupidtable.settings.should_redraw(sort_info)){ return; } $table.children("tbody").append(trs); updateElementData(sort_info); $table.trigger("aftertablesort", {column: sort_info.th_index, direction: sort_info.sort_dir, $th: $this_th}); $table.css("display"); }, 10); return $this_th; }; // Call on a sortable td to update its value in the sort. This should be the // only mechanism used to update a cell's sort value. If your display value is // different from your sort value, use jQuery's .text() or .html() to update // the td contents, Assumes stupidtable has already been called for the table. $.fn.updateSortVal = function(new_sort_val){ var $this_td = $(this); if($this_td.is('[data-sort-value]')){ // For visual consistency with the .data cache $this_td.attr('data-sort-value', new_sort_val); } $this_td.data("sort-value", new_sort_val); return $this_td; }; $.fn.stupidtable_build = function(){ return this.each(function() { var $table = $(this); var table_structure = []; var trs = $table.children("tbody").children("tr"); trs.each(function(index,tr) { // ==================================================================== // Transfer to using internal table structure // ==================================================================== var ele = { $tr: $(tr), columns: [], index: index }; $(tr).children('td').each(function(idx, td){ var sort_val = $(td).data("sort-value"); // Store and read from the .data cache for display text only sorts // instead of looking through the DOM every time if(typeof(sort_val) === "undefined"){ var txt = $(td).text(); $(td).data('sort-value', txt); sort_val = txt; } ele.columns.push(sort_val); }); table_structure.push(ele); }); $table.data('stupidsort_internaltable', table_structure); }); }; // ==================================================================== // Private functions // ==================================================================== var sortTable = function(sort_info){ var table_structure = sort_info.$table.data('stupidsort_internaltable'); var th_index = sort_info.th_index; var $th = sort_info.$th; var multicolumn_target_str = $th.data('sort-multicolumn'); var multicolumn_targets; if(multicolumn_target_str){ multicolumn_targets = multicolumn_target_str.split(','); } else{ multicolumn_targets = []; } var multicolumn_th_targets = $.map(multicolumn_targets, function(identifier, i){ return get_th(sort_info.$table, identifier); }); table_structure.sort(function(e1, e2){ var multicolumns = multicolumn_th_targets.slice(0); // shallow copy var diff = sort_info.compare_fn(e1.columns[th_index], e2.columns[th_index]); while(diff === 0 && multicolumns.length){ var multicolumn = multicolumns[0]; var datatype = multicolumn.$e.data("sort"); var multiCloumnSortMethod = sort_info.$table.data('sortFns')[datatype]; diff = multiCloumnSortMethod(e1.columns[multicolumn.index], e2.columns[multicolumn.index]); multicolumns.shift(); } // Sort by position in the table if values are the same. This enforces a // stable sort across all browsers. See https://bugs.chromium.org/p/v8/issues/detail?id=90 if (diff === 0) return e1.index - e2.index; else return diff; }); if (sort_info.sort_dir != $.fn.stupidtable.dir.ASC){ table_structure.reverse(); } return table_structure; }; var get_th = function($table, identifier){ // identifier can be a th id or a th index number; var $table_ths = $table.find('th'); var index = parseInt(identifier, 10); var $th; if(!index && index !== 0){ $th = $table_ths.siblings('#' + identifier); index = $table_ths.index($th); } else{ $th = $table_ths.eq(index); } return {index: index, $e: $th}; }; var getTableRowsFromTableStructure = function(table_structure, sort_info){ // Gather individual column for callbacks var column = $.map(table_structure, function(ele, i){ return [[ele.columns[sort_info.th_index], ele.$tr, i]]; }); /* Side effect */ sort_info.column = column; // Replace the content of tbody with the sorted rows. Strangely // enough, .append accomplishes this for us. return $.map(table_structure, function(ele) { return ele.$tr; }); }; var updateElementData = function(sort_info){ var $table = sort_info.$table; var $this_th = sort_info.$th; var sort_dir = $this_th.data('sort-dir'); var th_index = sort_info.th_index; // Reset siblings $table.find("th").data("sort-dir", null).removeClass("sorting-desc sorting-asc"); $this_th.data("sort-dir", sort_dir).addClass("sorting-"+sort_dir); }; var calculateSortDir = function(force_direction, sort_info){ var sort_dir; var $this_th = sort_info.$th; var dir = $.fn.stupidtable.dir; if(!!force_direction){ sort_dir = force_direction; } else{ sort_dir = force_direction || $this_th.data("sort-default") || dir.ASC; if ($this_th.data("sort-dir")) sort_dir = $this_th.data("sort-dir") === dir.ASC ? dir.DESC : dir.ASC; } return sort_dir; }; var calculateTHIndex = function(sort_info){ var th_index = 0; var base_index = sort_info.$th.index(); sort_info.$th.parents("tr").find("th").slice(0, base_index).each(function() { var cols = $(this).attr("colspan") || 1; th_index += parseInt(cols,10); }); return th_index; }; })(jQuery); Stupid-Table-Plugin-1.1.3/tests/000077500000000000000000000000001316766721000164205ustar00rootroot00000000000000Stupid-Table-Plugin-1.1.3/tests/qunit.css000066400000000000000000000113771316766721000203030ustar00rootroot00000000000000/** * QUnit v1.12.0 - A JavaScript Unit Testing Framework * * http://qunitjs.com * * Copyright 2012 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699a4; background-color: #0d3349; font-size: 1.5em; line-height: 1em; font-weight: normal; border-radius: 5px 5px 0 0; -moz-border-radius: 5px 5px 0 0; -webkit-border-top-right-radius: 5px; -webkit-border-top-left-radius: 5px; } #qunit-header a { text-decoration: none; color: #c2ccd1; } #qunit-header a:hover, #qunit-header a:focus { color: #fff; } #qunit-testrunner-toolbar label { display: inline-block; padding: 0 .5em 0 .1em; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 0 0.5em 2em; color: #5E740B; background-color: #eee; overflow: hidden; } #qunit-userAgent { padding: 0.5em 0 0.5em 2.5em; background-color: #2b81af; color: #fff; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } #qunit-modulefilter-container { float: right; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 0.5em 0.4em 2.5em; border-bottom: 1px solid #fff; list-style-position: inside; } #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { display: none; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li a { padding: 0.5em; color: #c2ccd1; text-decoration: none; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests li .runtime { float: right; font-size: smaller; } .qunit-assert-list { margin-top: 0.5em; padding: 0.5em; background-color: #fff; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; } .qunit-collapsed { display: none; } #qunit-tests table { border-collapse: collapse; margin-top: .2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 .5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #e0f2be; color: #374e0c; text-decoration: none; } #qunit-tests ins { background-color: #ffcaca; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: black; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { padding: 5px; background-color: #fff; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #3c510c; background-color: #fff; border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #fff; border-left: 10px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 5px 5px; -moz-border-radius: 0 0 5px 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: green; } #qunit-banner.qunit-fail { background-color: #EE5757; } /** Result */ #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; color: #2b81af; background-color: #D2E0E6; border-bottom: 1px solid white; } #qunit-testresult .module-name { font-weight: bold; } /** Fixture */ /* Custom styles */ table { border-collapse: collapse; } th, td { padding: 5px 10px; border: 1px solid #999; } th { background-color: #eee; } th[data-sort]{ cursor:pointer; } .test-hidden { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } Stupid-Table-Plugin-1.1.3/tests/qunit.js000066400000000000000000001626541316766721000201340ustar00rootroot00000000000000/** * QUnit v1.12.0 - A JavaScript Unit Testing Framework * * http://qunitjs.com * * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license. * https://jquery.org/license/ */ (function( window ) { var QUnit, assert, config, onErrorFnPrev, testId = 0, fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, // Keep a local reference to Date (GH-283) Date = window.Date, setTimeout = window.setTimeout, defined = { setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch( e ) { return false; } }()) }, /** * Provides a normalized error string, correcting an issue * with IE 7 (and prior) where Error.prototype.toString is * not properly implemented * * Based on http://es5.github.com/#x15.11.4.4 * * @param {String|Error} error * @return {String} error message */ errorString = function( error ) { var name, message, errorString = error.toString(); if ( errorString.substring( 0, 7 ) === "[object" ) { name = error.name ? error.name.toString() : "Error"; message = error.message ? error.message.toString() : ""; if ( name && message ) { return name + ": " + message; } else if ( name ) { return name; } else if ( message ) { return message; } else { return "Error"; } } else { return errorString; } }, /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ objectValues = function( obj ) { // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. /*jshint newcap: false */ var key, val, vals = QUnit.is( "array", obj ) ? [] : {}; for ( key in obj ) { if ( hasOwn.call( obj, key ) ) { val = obj[key]; vals[key] = val === Object(val) ? objectValues(val) : val; } } return vals; }; function Test( settings ) { extend( this, settings ); this.assertions = []; this.testNumber = ++Test.count; } Test.count = 0; Test.prototype = { init: function() { var a, b, li, tests = id( "qunit-tests" ); if ( tests ) { b = document.createElement( "strong" ); b.innerHTML = this.nameHtml; // `a` initialized at top of scope a = document.createElement( "a" ); a.innerHTML = "Rerun"; a.href = QUnit.url({ testNumber: this.testNumber }); li = document.createElement( "li" ); li.appendChild( b ); li.appendChild( a ); li.className = "running"; li.id = this.id = "qunit-test-output" + testId++; tests.appendChild( li ); } }, setup: function() { if ( // Emit moduleStart when we're switching from one module to another this.module !== config.previousModule || // They could be equal (both undefined) but if the previousModule property doesn't // yet exist it means this is the first test in a suite that isn't wrapped in a // module, in which case we'll just emit a moduleStart event for 'undefined'. // Without this, reporters can get testStart before moduleStart which is a problem. !hasOwn.call( config, "previousModule" ) ) { if ( hasOwn.call( config, "previousModule" ) ) { runLoggingCallbacks( "moduleDone", QUnit, { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all }); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0 }; runLoggingCallbacks( "moduleStart", QUnit, { name: this.module }); } config.current = this; this.testEnvironment = extend({ setup: function() {}, teardown: function() {} }, this.moduleTestEnvironment ); this.started = +new Date(); runLoggingCallbacks( "testStart", QUnit, { name: this.testName, module: this.module }); /*jshint camelcase:false */ /** * Expose the current test environment. * * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead. */ QUnit.current_testEnvironment = this.testEnvironment; /*jshint camelcase:true */ if ( !config.pollution ) { saveGlobal(); } if ( config.notrycatch ) { this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); return; } try { this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); } catch( e ) { QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); } }, run: function() { config.current = this; var running = id( "qunit-testresult" ); if ( running ) { running.innerHTML = "Running:
" + this.nameHtml; } if ( this.async ) { QUnit.stop(); } this.callbackStarted = +new Date(); if ( config.notrycatch ) { this.callback.call( this.testEnvironment, QUnit.assert ); this.callbackRuntime = +new Date() - this.callbackStarted; return; } try { this.callback.call( this.testEnvironment, QUnit.assert ); this.callbackRuntime = +new Date() - this.callbackStarted; } catch( e ) { this.callbackRuntime = +new Date() - this.callbackStarted; QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); // else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { QUnit.start(); } } }, teardown: function() { config.current = this; if ( config.notrycatch ) { if ( typeof this.callbackRuntime === "undefined" ) { this.callbackRuntime = +new Date() - this.callbackStarted; } this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); return; } else { try { this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); } catch( e ) { QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); } } checkPollution(); }, finish: function() { config.current = this; if ( config.requireExpects && this.expected === null ) { QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); } else if ( this.expected !== null && this.expected !== this.assertions.length ) { QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); } else if ( this.expected === null && !this.assertions.length ) { QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); } var i, assertion, a, b, time, li, ol, test = this, good = 0, bad = 0, tests = id( "qunit-tests" ); this.runtime = +new Date() - this.started; config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; if ( tests ) { ol = document.createElement( "ol" ); ol.className = "qunit-assert-list"; for ( i = 0; i < this.assertions.length; i++ ) { assertion = this.assertions[i]; li = document.createElement( "li" ); li.className = assertion.result ? "pass" : "fail"; li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); ol.appendChild( li ); if ( assertion.result ) { good++; } else { bad++; config.stats.bad++; config.moduleStats.bad++; } } // store result when possible if ( QUnit.config.reorder && defined.sessionStorage ) { if ( bad ) { sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); } else { sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); } } if ( bad === 0 ) { addClass( ol, "qunit-collapsed" ); } // `b` initialized at top of scope b = document.createElement( "strong" ); b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; addEvent(b, "click", function() { var next = b.parentNode.lastChild, collapsed = hasClass( next, "qunit-collapsed" ); ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); }); addEvent(b, "dblclick", function( e ) { var target = e && e.target ? e.target : window.event.srcElement; if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { target = target.parentNode; } if ( window.location && target.nodeName.toLowerCase() === "strong" ) { window.location = QUnit.url({ testNumber: test.testNumber }); } }); // `time` initialized at top of scope time = document.createElement( "span" ); time.className = "runtime"; time.innerHTML = this.runtime + " ms"; // `li` initialized at top of scope li = id( this.id ); li.className = bad ? "fail" : "pass"; li.removeChild( li.firstChild ); a = li.firstChild; li.appendChild( b ); li.appendChild( a ); li.appendChild( time ); li.appendChild( ol ); } else { for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[i].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } } runLoggingCallbacks( "testDone", QUnit, { name: this.testName, module: this.module, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, duration: this.runtime }); QUnit.reset(); config.current = undefined; }, queue: function() { var bad, test = this; synchronize(function() { test.init(); }); function run() { // each of these can by async synchronize(function() { test.setup(); }); synchronize(function() { test.run(); }); synchronize(function() { test.teardown(); }); synchronize(function() { test.finish(); }); } // `bad` initialized at top of scope // defer when previous test run passed, if storage is available bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); if ( bad ) { run(); } else { synchronize( run, true ); } } }; // Root QUnit object. // `QUnit` initialized at top of scope QUnit = { // call on start of module test to prepend name to all tests module: function( name, testEnvironment ) { config.currentModule = name; config.currentModuleTestEnvironment = testEnvironment; config.modules[name] = true; }, asyncTest: function( testName, expected, callback ) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test( testName, expected, callback, true ); }, test: function( testName, expected, callback, async ) { var test, nameHtml = "" + escapeText( testName ) + ""; if ( arguments.length === 2 ) { callback = expected; expected = null; } if ( config.currentModule ) { nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; } test = new Test({ nameHtml: nameHtml, testName: testName, expected: expected, async: async, callback: callback, module: config.currentModule, moduleTestEnvironment: config.currentModuleTestEnvironment, stack: sourceFromStacktrace( 2 ) }); if ( !validTest( test ) ) { return; } test.queue(); }, // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. expect: function( asserts ) { if (arguments.length === 1) { config.current.expected = asserts; } else { return config.current.expected; } }, start: function( count ) { // QUnit hasn't been initialized yet. // Note: RequireJS (et al) may delay onLoad if ( config.semaphore === undefined ) { QUnit.begin(function() { // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first setTimeout(function() { QUnit.start( count ); }); }); return; } config.semaphore -= count || 1; // don't start until equal number of stop-calls if ( config.semaphore > 0 ) { return; } // ignore if start is called more often then stop if ( config.semaphore < 0 ) { config.semaphore = 0; QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); return; } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { setTimeout(function() { if ( config.semaphore > 0 ) { return; } if ( config.timeout ) { clearTimeout( config.timeout ); } config.blocking = false; process( true ); }, 13); } else { config.blocking = false; process( true ); } }, stop: function( count ) { config.semaphore += count || 1; config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); config.timeout = setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); }, config.testTimeout ); } } }; // `assert` initialized at top of scope // Assert helpers // All of these must either call QUnit.push() or manually do: // - runLoggingCallbacks( "log", .. ); // - config.current.assertions.push({ .. }); // We attach it to the QUnit object *after* we expose the public API, // otherwise `assert` will become a global variable in browsers (#341). assert = { /** * Asserts rough true-ish result. * @name ok * @function * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); */ ok: function( result, msg ) { if ( !config.current ) { throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); } result = !!result; msg = msg || (result ? "okay" : "failed" ); var source, details = { module: config.current.module, name: config.current.testName, result: result, message: msg }; msg = "" + escapeText( msg ) + ""; if ( !result ) { source = sourceFromStacktrace( 2 ); if ( source ) { details.source = source; msg += "
Source:
" + escapeText( source ) + "
"; } } runLoggingCallbacks( "log", QUnit, details ); config.current.assertions.push({ result: result, message: msg }); }, /** * Assert that the first two arguments are equal, with an optional message. * Prints out both actual and expected values. * @name equal * @function * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); */ equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ QUnit.push( expected == actual, actual, expected, message ); }, /** * @name notEqual * @function */ notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ QUnit.push( expected != actual, actual, expected, message ); }, /** * @name propEqual * @function */ propEqual: function( actual, expected, message ) { actual = objectValues(actual); expected = objectValues(expected); QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); }, /** * @name notPropEqual * @function */ notPropEqual: function( actual, expected, message ) { actual = objectValues(actual); expected = objectValues(expected); QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); }, /** * @name deepEqual * @function */ deepEqual: function( actual, expected, message ) { QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); }, /** * @name notDeepEqual * @function */ notDeepEqual: function( actual, expected, message ) { QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); }, /** * @name strictEqual * @function */ strictEqual: function( actual, expected, message ) { QUnit.push( expected === actual, actual, expected, message ); }, /** * @name notStrictEqual * @function */ notStrictEqual: function( actual, expected, message ) { QUnit.push( expected !== actual, actual, expected, message ); }, "throws": function( block, expected, message ) { var actual, expectedOutput = expected, ok = false; // 'expected' is optional if ( typeof expected === "string" ) { message = expected; expected = null; } config.current.ignoreGlobalErrors = true; try { block.call( config.current.testEnvironment ); } catch (e) { actual = e; } config.current.ignoreGlobalErrors = false; if ( actual ) { // we don't want to validate thrown error if ( !expected ) { ok = true; expectedOutput = null; // expected is a regexp } else if ( QUnit.objectType( expected ) === "regexp" ) { ok = expected.test( errorString( actual ) ); // expected is a constructor } else if ( actual instanceof expected ) { ok = true; // expected is a validation function which returns true is validation passed } else if ( expected.call( {}, actual ) === true ) { expectedOutput = null; ok = true; } QUnit.push( ok, actual, expectedOutput, message ); } else { QUnit.pushFailure( message, null, "No exception was thrown." ); } } }; /** * @deprecated since 1.8.0 * Kept assertion helpers in root for backwards compatibility. */ extend( QUnit, assert ); /** * @deprecated since 1.9.0 * Kept root "raises()" for backwards compatibility. * (Note that we don't introduce assert.raises). */ QUnit.raises = assert[ "throws" ]; /** * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 * Kept to avoid TypeErrors for undefined methods. */ QUnit.equals = function() { QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); }; QUnit.same = function() { QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); }; // We want access to the constructor's prototype (function() { function F() {} F.prototype = QUnit; QUnit = new F(); // Make F QUnit's constructor so that we can add to the prototype later QUnit.constructor = F; }()); /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // when enabled, show only failing tests // gets persisted through sessionStorage and can be changed in UI via checkbox hidepassed: false, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, // when enabled, all tests must call expect() requireExpects: false, // add checkboxes that are persisted in the query-string // when enabled, the id is set to `true` as a `QUnit.config` property urlConfig: [ { id: "noglobals", label: "Check for Globals", tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." }, { id: "notrycatch", label: "No try-catch", tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." } ], // Set of all modules. modules: {}, // logging callback queues begin: [], done: [], log: [], testStart: [], testDone: [], moduleStart: [], moduleDone: [] }; // Export global variables, unless an 'exports' object exists, // in that case we assume we're in CommonJS (dealt with on the bottom of the script) if ( typeof exports === "undefined" ) { extend( window, QUnit.constructor.prototype ); // Expose QUnit object window.QUnit = QUnit; } // Initialize more QUnit.config and QUnit.urlParams (function() { var i, location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}, current; if ( params[ 0 ] ) { for ( i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; urlParams[ current[ 0 ] ] = current[ 1 ]; } } QUnit.urlParams = urlParams; // String search anywhere in moduleName+testName config.filter = urlParams.filter; // Exact match of the module name config.module = urlParams.module; config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; }()); // Extend QUnit object, // these after set here because they should not be exposed as global functions extend( QUnit, { assert: assert, config: config, // Initialize the configuration options init: function() { extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: +new Date(), updateRate: 1000, blocking: false, autostart: true, autorun: false, filter: "", queue: [], semaphore: 1 }); var tests, banner, result, qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = "

" + escapeText( document.title ) + "

" + "

" + "
" + "

" + "
    "; } tests = id( "qunit-tests" ); banner = id( "qunit-banner" ); result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; } if ( banner ) { banner.className = ""; } if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = "Running...
     "; } }, // Resets the test setup. Useful for tests that modify the DOM. /* DEPRECATED: Use multiple tests instead of resetting inside a test. Use testStart or testDone for custom cleanup. This method will throw an error in 2.0, and will be removed in 2.1 */ reset: function() { var fixture = id( "qunit-fixture" ); if ( fixture ) { fixture.innerHTML = config.fixture; } }, // Trigger an event on an element. // @example triggerEvent( document.body, "click" ); triggerEvent: function( elem, type, event ) { if ( document.createEvent ) { event = document.createEvent( "MouseEvents" ); event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); elem.dispatchEvent( event ); } else if ( elem.fireEvent ) { elem.fireEvent( "on" + type ); } }, // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) === type; }, objectType: function( obj ) { if ( typeof obj === "undefined" ) { return "undefined"; // consider: typeof null === object } if ( obj === null ) { return "null"; } var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), type = match && match[1] || ""; switch ( type ) { case "Number": if ( isNaN(obj) ) { return "nan"; } return "number"; case "String": case "Boolean": case "Array": case "Date": case "RegExp": case "Function": return type.toLowerCase(); } if ( typeof obj === "object" ) { return "object"; } return undefined; }, push: function( result, actual, expected, message ) { if ( !config.current ) { throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); } var output, source, details = { module: config.current.module, name: config.current.testName, result: result, message: message, actual: actual, expected: expected }; message = escapeText( message ) || ( result ? "okay" : "failed" ); message = "" + message + ""; output = message; if ( !result ) { expected = escapeText( QUnit.jsDump.parse(expected) ); actual = escapeText( QUnit.jsDump.parse(actual) ); output += ""; if ( actual !== expected ) { output += ""; output += ""; } source = sourceFromStacktrace(); if ( source ) { details.source = source; output += ""; } output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; } runLoggingCallbacks( "log", QUnit, details ); config.current.assertions.push({ result: !!result, message: output }); }, pushFailure: function( message, source, actual ) { if ( !config.current ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); } var output, details = { module: config.current.module, name: config.current.testName, result: false, message: message }; message = escapeText( message ) || "error"; message = "" + message + ""; output = message; output += ""; if ( actual ) { output += ""; } if ( source ) { details.source = source; output += ""; } output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; runLoggingCallbacks( "log", QUnit, details ); config.current.assertions.push({ result: false, message: output }); }, url: function( params ) { params = extend( extend( {}, QUnit.urlParams ), params ); var key, querystring = "?"; for ( key in params ) { if ( hasOwn.call( params, key ) ) { querystring += encodeURIComponent( key ) + "=" + encodeURIComponent( params[ key ] ) + "&"; } } return window.location.protocol + "//" + window.location.host + window.location.pathname + querystring.slice( 0, -1 ); }, extend: extend, id: id, addEvent: addEvent, addClass: addClass, hasClass: hasClass, removeClass: removeClass // load, equiv, jsDump, diff: Attached later }); /** * @deprecated: Created for backwards compatibility with test runner that set the hook function * into QUnit.{hook}, instead of invoking it and passing the hook function. * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. * Doing this allows us to tell if the following methods have been overwritten on the actual * QUnit object. */ extend( QUnit.constructor.prototype, { // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes begin: registerLoggingCallback( "begin" ), // done: { failed, passed, total, runtime } done: registerLoggingCallback( "done" ), // log: { result, actual, expected, message } log: registerLoggingCallback( "log" ), // testStart: { name } testStart: registerLoggingCallback( "testStart" ), // testDone: { name, failed, passed, total, duration } testDone: registerLoggingCallback( "testDone" ), // moduleStart: { name } moduleStart: registerLoggingCallback( "moduleStart" ), // moduleDone: { name, failed, passed, total } moduleDone: registerLoggingCallback( "moduleDone" ) }); if ( typeof document === "undefined" || document.readyState === "complete" ) { config.autorun = true; } QUnit.load = function() { runLoggingCallbacks( "begin", QUnit, {} ); // Initialize the config, saving the execution queue var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, numModules = 0, moduleNames = [], moduleFilterHtml = "", urlConfigHtml = "", oldconfig = extend( {}, config ); QUnit.init(); extend(config, oldconfig); config.blocking = false; len = config.urlConfig.length; for ( i = 0; i < len; i++ ) { val = config.urlConfig[i]; if ( typeof val === "string" ) { val = { id: val, label: val, tooltip: "[no tooltip available]" }; } config[ val.id ] = QUnit.urlParams[ val.id ]; urlConfigHtml += ""; } for ( i in config.modules ) { if ( config.modules.hasOwnProperty( i ) ) { moduleNames.push(i); } } numModules = moduleNames.length; moduleNames.sort( function( a, b ) { return a.localeCompare( b ); }); moduleFilterHtml += ""; // `userAgent` initialized at top of scope userAgent = id( "qunit-userAgent" ); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } // `banner` initialized at top of scope banner = id( "qunit-header" ); if ( banner ) { banner.innerHTML = "" + banner.innerHTML + " "; } // `toolbar` initialized at top of scope toolbar = id( "qunit-testrunner-toolbar" ); if ( toolbar ) { // `filter` initialized at top of scope filter = document.createElement( "input" ); filter.type = "checkbox"; filter.id = "qunit-filter-pass"; addEvent( filter, "click", function() { var tmp, ol = document.getElementById( "qunit-tests" ); if ( filter.checked ) { ol.className = ol.className + " hidepass"; } else { tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; ol.className = tmp.replace( / hidepass /, " " ); } if ( defined.sessionStorage ) { if (filter.checked) { sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); } else { sessionStorage.removeItem( "qunit-filter-passed-tests" ); } } }); if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { filter.checked = true; // `ol` initialized at top of scope ol = document.getElementById( "qunit-tests" ); ol.className = ol.className + " hidepass"; } toolbar.appendChild( filter ); // `label` initialized at top of scope label = document.createElement( "label" ); label.setAttribute( "for", "qunit-filter-pass" ); label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); urlConfigCheckboxesContainer = document.createElement("span"); urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); // For oldIE support: // * Add handlers to the individual elements instead of the container // * Use "click" instead of "change" // * Fallback from event.target to event.srcElement addEvents( urlConfigCheckboxes, "click", function( event ) { var params = {}, target = event.target || event.srcElement; params[ target.name ] = target.checked ? true : undefined; window.location = QUnit.url( params ); }); toolbar.appendChild( urlConfigCheckboxesContainer ); if (numModules > 1) { moduleFilter = document.createElement( "span" ); moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); moduleFilter.innerHTML = moduleFilterHtml; addEvent( moduleFilter.lastChild, "change", function() { var selectBox = moduleFilter.getElementsByTagName("select")[0], selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); window.location = QUnit.url({ module: ( selectedModule === "" ) ? undefined : selectedModule, // Remove any existing filters filter: undefined, testNumber: undefined }); }); toolbar.appendChild(moduleFilter); } } // `main` initialized at top of scope main = id( "qunit-fixture" ); if ( main ) { config.fixture = main.innerHTML; } if ( config.autostart ) { QUnit.start(); } }; addEvent( window, "load", QUnit.load ); // `onErrorFnPrev` initialized at top of scope // Preserve other handlers onErrorFnPrev = window.onerror; // Cover uncaught exceptions // Returning true will suppress the default browser handler, // returning false will let it run. window.onerror = function ( error, filePath, linerNr ) { var ret = false; if ( onErrorFnPrev ) { ret = onErrorFnPrev( error, filePath, linerNr ); } // Treat return value as window.onerror itself does, // Only do our handling if not suppressed. if ( ret !== true ) { if ( QUnit.config.current ) { if ( QUnit.config.current.ignoreGlobalErrors ) { return true; } QUnit.pushFailure( error, filePath + ":" + linerNr ); } else { QUnit.test( "global failure", extend( function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); }, { validTest: validTest } ) ); } return false; } return ret; }; function done() { config.autorun = true; // Log the last module results if ( config.currentModule ) { runLoggingCallbacks( "moduleDone", QUnit, { name: config.currentModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all }); } delete config.previousModule; var i, key, banner = id( "qunit-banner" ), tests = id( "qunit-tests" ), runtime = +new Date() - config.started, passed = config.stats.all - config.stats.bad, html = [ "Tests completed in ", runtime, " milliseconds.
    ", "", passed, " assertions of ", config.stats.all, " passed, ", config.stats.bad, " failed." ].join( "" ); if ( banner ) { banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); } if ( tests ) { id( "qunit-testresult" ).innerHTML = html; } if ( config.altertitle && typeof document !== "undefined" && document.title ) { // show ✖ for good, ✔ for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ ( config.stats.bad ? "\u2716" : "\u2714" ), document.title.replace( /^[\u2714\u2716] /i, "" ) ].join( " " ); } // clear own sessionStorage items if all tests passed if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { // `key` & `i` initialized at top of scope for ( i = 0; i < sessionStorage.length; i++ ) { key = sessionStorage.key( i++ ); if ( key.indexOf( "qunit-test-" ) === 0 ) { sessionStorage.removeItem( key ); } } } // scroll back to top to show results if ( window.scrollTo ) { window.scrollTo(0, 0); } runLoggingCallbacks( "done", QUnit, { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime }); } /** @return Boolean: true if this test should be ran */ function validTest( test ) { var include, filter = config.filter && config.filter.toLowerCase(), module = config.module && config.module.toLowerCase(), fullName = (test.module + ": " + test.testName).toLowerCase(); // Internally-generated tests are always valid if ( test.callback && test.callback.validTest === validTest ) { delete test.callback.validTest; return true; } if ( config.testNumber ) { return test.testNumber === config.testNumber; } if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { return false; } if ( !filter ) { return true; } include = filter.charAt( 0 ) !== "!"; if ( !include ) { filter = filter.slice( 1 ); } // If the filter matches, we need to honour include if ( fullName.indexOf( filter ) !== -1 ) { return include; } // Otherwise, do the opposite return !include; } // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) // Later Safari and IE10 are supposed to support error.stack as well // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset === undefined ? 3 : offset; var stack, include, i; if ( e.stacktrace ) { // Opera return e.stacktrace.split( "\n" )[ offset + 3 ]; } else if ( e.stack ) { // Firefox, Chrome stack = e.stack.split( "\n" ); if (/^error$/i.test( stack[0] ) ) { stack.shift(); } if ( fileName ) { include = []; for ( i = offset; i < stack.length; i++ ) { if ( stack[ i ].indexOf( fileName ) !== -1 ) { break; } include.push( stack[ i ] ); } if ( include.length ) { return include.join( "\n" ); } } return stack[ offset ]; } else if ( e.sourceURL ) { // Safari, PhantomJS // hopefully one day Safari provides actual stacktraces // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } // for actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } function sourceFromStacktrace( offset ) { try { throw new Error(); } catch ( e ) { return extractStacktrace( e, offset ); } } /** * Escape text for attribute or text content. */ function escapeText( s ) { if ( !s ) { return ""; } s = s + ""; // Both single quotes and double quotes (for attributes) return s.replace( /['"<>&]/g, function( s ) { switch( s ) { case "'": return "'"; case "\"": return """; case "<": return "<"; case ">": return ">"; case "&": return "&"; } }); } function synchronize( callback, last ) { config.queue.push( callback ); if ( config.autorun && !config.blocking ) { process( last ); } } function process( last ) { function next() { process( last ); } var start = new Date().getTime(); config.depth = config.depth ? config.depth + 1 : 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { config.queue.shift()(); } else { setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function saveGlobal() { config.pollution = []; if ( config.noglobals ) { for ( var key in window ) { if ( hasOwn.call( window, key ) ) { // in Opera sometimes DOM element ids show up here, ignore them if ( /^qunit-test-output/.test( key ) ) { continue; } config.pollution.push( key ); } } } } function checkPollution() { var newGlobals, deletedGlobals, old = config.pollution; saveGlobal(); newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); } deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); } } // returns a new Array with the elements that are in a but not in b function diff( a, b ) { var i, j, result = a.slice(); for ( i = 0; i < result.length; i++ ) { for ( j = 0; j < b.length; j++ ) { if ( result[i] === b[j] ) { result.splice( i, 1 ); i--; break; } } } return result; } function extend( a, b ) { for ( var prop in b ) { if ( hasOwn.call( b, prop ) ) { // Avoid "Member not found" error in IE8 caused by messing with window.constructor if ( !( prop === "constructor" && a === window ) ) { if ( b[ prop ] === undefined ) { delete a[ prop ]; } else { a[ prop ] = b[ prop ]; } } } } return a; } /** * @param {HTMLElement} elem * @param {string} type * @param {Function} fn */ function addEvent( elem, type, fn ) { // Standards-based browsers if ( elem.addEventListener ) { elem.addEventListener( type, fn, false ); // IE } else { elem.attachEvent( "on" + type, fn ); } } /** * @param {Array|NodeList} elems * @param {string} type * @param {Function} fn */ function addEvents( elems, type, fn ) { var i = elems.length; while ( i-- ) { addEvent( elems[i], type, fn ); } } function hasClass( elem, name ) { return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; } function addClass( elem, name ) { if ( !hasClass( elem, name ) ) { elem.className += (elem.className ? " " : "") + name; } } function removeClass( elem, name ) { var set = " " + elem.className + " "; // Class name may appear multiple times while ( set.indexOf(" " + name + " ") > -1 ) { set = set.replace(" " + name + " " , " "); } // If possible, trim it for prettiness, but not necessarily elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); } function id( name ) { return !!( typeof document !== "undefined" && document && document.getElementById ) && document.getElementById( name ); } function registerLoggingCallback( key ) { return function( callback ) { config[key].push( callback ); }; } // Supports deprecated method of completely overwriting logging callbacks function runLoggingCallbacks( key, scope, args ) { var i, callbacks; if ( QUnit.hasOwnProperty( key ) ) { QUnit[ key ].call(scope, args ); } else { callbacks = config[ key ]; for ( i = 0; i < callbacks.length; i++ ) { callbacks[ i ].call( scope, args ); } } } // Test for equality any JavaScript type. // Author: Philippe Rathé QUnit.equiv = (function() { // Call the o related callback with the given arguments. function bindCallbacks( o, callbacks, args ) { var prop = QUnit.objectType( o ); if ( prop ) { if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { return callbacks[ prop ].apply( callbacks, args ); } else { return callbacks[ prop ]; // or undefined } } } // the real equiv function var innerEquiv, // stack to decide between skip/abort functions callers = [], // stack to avoiding loops from circular referencing parents = [], parentsB = [], getProto = Object.getPrototypeOf || function ( obj ) { /*jshint camelcase:false */ return obj.__proto__; }, callbacks = (function () { // for string, boolean, number and null function useStrictEquality( b, a ) { /*jshint eqeqeq:false */ if ( b instanceof a.constructor || a instanceof b.constructor ) { // to catch short annotation VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); return a == b; } else { return a === b; } } return { "string": useStrictEquality, "boolean": useStrictEquality, "number": useStrictEquality, "null": useStrictEquality, "undefined": useStrictEquality, "nan": function( b ) { return isNaN( b ); }, "date": function( b, a ) { return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); }, "regexp": function( b, a ) { return QUnit.objectType( b ) === "regexp" && // the regex itself a.source === b.source && // and its modifiers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky; }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function": function() { var caller = callers[callers.length - 1]; return caller !== Object && typeof caller !== "undefined"; }, "array": function( b, a ) { var i, j, len, loop, aCircular, bCircular; // b could be an object literal here if ( QUnit.objectType( b ) !== "array" ) { return false; } len = a.length; if ( len !== b.length ) { // safe and faster return false; } // track reference to avoid circular references parents.push( a ); parentsB.push( b ); for ( i = 0; i < len; i++ ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[j] === a[i]; bCircular = parentsB[j] === b[i]; if ( aCircular || bCircular ) { if ( a[i] === b[i] || aCircular && bCircular ) { loop = true; } else { parents.pop(); parentsB.pop(); return false; } } } if ( !loop && !innerEquiv(a[i], b[i]) ) { parents.pop(); parentsB.pop(); return false; } } parents.pop(); parentsB.pop(); return true; }, "object": function( b, a ) { /*jshint forin:false */ var i, j, loop, aCircular, bCircular, // Default to true eq = true, aProperties = [], bProperties = []; // comparing constructors is more strict than using // instanceof if ( a.constructor !== b.constructor ) { // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { return false; } } // stack constructor before traversing properties callers.push( a.constructor ); // track reference to avoid circular references parents.push( a ); parentsB.push( b ); // be strict: don't ensure hasOwnProperty and go deep for ( i in a ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[j] === a[i]; bCircular = parentsB[j] === b[i]; if ( aCircular || bCircular ) { if ( a[i] === b[i] || aCircular && bCircular ) { loop = true; } else { eq = false; break; } } } aProperties.push(i); if ( !loop && !innerEquiv(a[i], b[i]) ) { eq = false; break; } } parents.pop(); parentsB.pop(); callers.pop(); // unstack, we are done for ( i in b ) { bProperties.push( i ); // collect b's properties } // Ensures identical properties name return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); } }; }()); innerEquiv = function() { // can take multiple arguments var args = [].slice.apply( arguments ); if ( args.length < 2 ) { return true; // end transition } return (function( a, b ) { if ( a === b ) { return true; // catch the most you can } else if ( a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b) ) { return false; // don't lose time with error prone cases } else { return bindCallbacks(a, callbacks, [ b, a ]); } // apply transition with (1..n) arguments }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) ); }; return innerEquiv; }()); /** * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | * http://flesler.blogspot.com Licensed under BSD * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 * * @projectDescription Advanced and extensible data dumping for Javascript. * @version 1.0.0 * @author Ariel Flesler * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} */ QUnit.jsDump = (function() { function quote( str ) { return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; } function literal( o ) { return o + ""; } function join( pre, arr, post ) { var s = jsDump.separator(), base = jsDump.indent(), inner = jsDump.indent(1); if ( arr.join ) { arr = arr.join( "," + s + inner ); } if ( !arr ) { return pre + post; } return [ pre, inner + arr, base + post ].join(s); } function array( arr, stack ) { var i = arr.length, ret = new Array(i); this.up(); while ( i-- ) { ret[i] = this.parse( arr[i] , undefined , stack); } this.down(); return join( "[", ret, "]" ); } var reName = /^function (\w+)/, jsDump = { // type is used mostly internally, you can fix a (custom)type in advance parse: function( obj, type, stack ) { stack = stack || [ ]; var inStack, res, parser = this.parsers[ type || this.typeOf(obj) ]; type = typeof parser; inStack = inArray( obj, stack ); if ( inStack !== -1 ) { return "recursion(" + (inStack - stack.length) + ")"; } if ( type === "function" ) { stack.push( obj ); res = parser.call( this, obj, stack ); stack.pop(); return res; } return ( type === "string" ) ? parser : this.parsers.error; }, typeOf: function( obj ) { var type; if ( obj === null ) { type = "null"; } else if ( typeof obj === "undefined" ) { type = "undefined"; } else if ( QUnit.is( "regexp", obj) ) { type = "regexp"; } else if ( QUnit.is( "date", obj) ) { type = "date"; } else if ( QUnit.is( "function", obj) ) { type = "function"; } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { type = "window"; } else if ( obj.nodeType === 9 ) { type = "document"; } else if ( obj.nodeType ) { type = "node"; } else if ( // native arrays toString.call( obj ) === "[object Array]" || // NodeList objects ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) ) { type = "array"; } else if ( obj.constructor === Error.prototype.constructor ) { type = "error"; } else { type = typeof obj; } return type; }, separator: function() { return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; }, // extra can be a number, shortcut for increasing-calling-decreasing indent: function( extra ) { if ( !this.multiline ) { return ""; } var chr = this.indentChar; if ( this.HTML ) { chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); } return new Array( this.depth + ( extra || 0 ) ).join(chr); }, up: function( a ) { this.depth += a || 1; }, down: function( a ) { this.depth -= a || 1; }, setParser: function( name, parser ) { this.parsers[name] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, // depth: 1, // This is the list of parsers, to modify them, use jsDump.setParser parsers: { window: "[Window]", document: "[Document]", error: function(error) { return "Error(\"" + error.message + "\")"; }, unknown: "[Unknown]", "null": "null", "undefined": "undefined", "function": function( fn ) { var ret = "function", // functions never have name in IE name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; if ( name ) { ret += " " + name; } ret += "( "; ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); }, array: array, nodelist: array, "arguments": array, object: function( map, stack ) { /*jshint forin:false */ var ret = [ ], keys, key, val, i; QUnit.jsDump.up(); keys = []; for ( key in map ) { keys.push( key ); } keys.sort(); for ( i = 0; i < keys.length; i++ ) { key = keys[ i ]; val = map[ key ]; ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); } QUnit.jsDump.down(); return join( "{", ret, "}" ); }, node: function( node ) { var len, i, val, open = QUnit.jsDump.HTML ? "<" : "<", close = QUnit.jsDump.HTML ? ">" : ">", tag = node.nodeName.toLowerCase(), ret = open + tag, attrs = node.attributes; if ( attrs ) { for ( i = 0, len = attrs.length; i < len; i++ ) { val = attrs[i].nodeValue; // IE6 includes all attributes in .attributes, even ones not explicitly set. // Those have values like undefined, null, 0, false, "" or "inherit". if ( val && val !== "inherit" ) { ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); } } } ret += close; // Show content of TextNode or CDATASection if ( node.nodeType === 3 || node.nodeType === 4 ) { ret += node.nodeValue; } return ret + open + "/" + tag + close; }, // function calls it internally, it's the arguments part of the function functionArgs: function( fn ) { var args, l = fn.length; if ( !l ) { return ""; } args = new Array(l); while ( l-- ) { // 97 is 'a' args[l] = String.fromCharCode(97+l); } return " " + args.join( ", " ) + " "; }, // object calls it internally, the key part of an item in a map key: quote, // function calls it internally, it's the content of the function functionCode: "[code]", // node calls it internally, it's an html attribute value attribute: quote, string: quote, date: quote, regexp: literal, number: literal, "boolean": literal }, // if true, entities are escaped ( <, >, \t, space and \n ) HTML: false, // indentation unit indentChar: " ", // if true, items in a collection, are separated by a \n, else just a space. multiline: true }; return jsDump; }()); // from jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; } /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) * Modified by Chu Alan "sprite" * * Released under the MIT license. * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ * * Usage: QUnit.diff(expected, actual) * * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" */ QUnit.diff = (function() { /*jshint eqeqeq:false, eqnull:true */ function diff( o, n ) { var i, ns = {}, os = {}; for ( i = 0; i < n.length; i++ ) { if ( !hasOwn.call( ns, n[i] ) ) { ns[ n[i] ] = { rows: [], o: null }; } ns[ n[i] ].rows.push( i ); } for ( i = 0; i < o.length; i++ ) { if ( !hasOwn.call( os, o[i] ) ) { os[ o[i] ] = { rows: [], n: null }; } os[ o[i] ].rows.push( i ); } for ( i in ns ) { if ( hasOwn.call( ns, i ) ) { if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] }; o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] }; } } } for ( i = 0; i < n.length - 1; i++ ) { if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && n[ i + 1 ] == o[ n[i].row + 1 ] ) { n[ i + 1 ] = { text: n[ i + 1 ], row: n[i].row + 1 }; o[ n[i].row + 1 ] = { text: o[ n[i].row + 1 ], row: i + 1 }; } } for ( i = n.length - 1; i > 0; i-- ) { if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && n[ i - 1 ] == o[ n[i].row - 1 ]) { n[ i - 1 ] = { text: n[ i - 1 ], row: n[i].row - 1 }; o[ n[i].row - 1 ] = { text: o[ n[i].row - 1 ], row: i - 1 }; } } return { o: o, n: n }; } return function( o, n ) { o = o.replace( /\s+$/, "" ); n = n.replace( /\s+$/, "" ); var i, pre, str = "", out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), oSpace = o.match(/\s+/g), nSpace = n.match(/\s+/g); if ( oSpace == null ) { oSpace = [ " " ]; } else { oSpace.push( " " ); } if ( nSpace == null ) { nSpace = [ " " ]; } else { nSpace.push( " " ); } if ( out.n.length === 0 ) { for ( i = 0; i < out.o.length; i++ ) { str += "" + out.o[i] + oSpace[i] + ""; } } else { if ( out.n[0].text == null ) { for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { str += "" + out.o[n] + oSpace[n] + ""; } } for ( i = 0; i < out.n.length; i++ ) { if (out.n[i].text == null) { str += "" + out.n[i] + nSpace[i] + ""; } else { // `pre` initialized at top of scope pre = ""; for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { pre += "" + out.o[n] + oSpace[n] + ""; } str += " " + out.n[i].text + nSpace[i] + pre; } } } return str; }; }()); // for CommonJS environments, export everything if ( typeof exports !== "undefined" ) { extend( exports, QUnit.constructor.prototype ); } // get at whatever the global object is, like window in browsers }( (function() {return this;}.call()) )); Stupid-Table-Plugin-1.1.3/tests/test-min.html000066400000000000000000000226161316766721000210550ustar00rootroot00000000000000 Stupid-Table Tests

    Basic Table

    int float string
    15 -.18 banana
    95 36 coke
    2 -152.5 apple
    -53 88.5 zebra
    195 -858 orange

    Basic Onload Table

    int float string
    15 -.18 banana
    95 36 coke
    2 -152.5 apple
    -53 88.5 zebra
    195 -858 orange

    Complex Table

    int float case Can't sort me! date Letter frequency
    15 -.18 Homer arbitrary Sep 15, 2002 E
    95 36 purple pointless Aug 07, 2004 T
    2 -152.5 is silly Mar 15, 1986 A
    -53 88.5 a eccentric Feb 27, 2086 O
    195 -858 fruit garbage Mar 15, 1986 I

    Basic Colspan Table

    Letter colspan=2 Number
    def X 9 1
    abc Z 8 2
    bcd Y 7 0

    Complex Colspan Table

    The Big Table Header
    Letter colspan=2 Number
    def X 9 1
    abc Z 8 2
    bcd Y 7 0

    Stability Testing Table

    (Unsortable) Index Key
    0A
    1A
    2A
    3A
    4A
    5A
    6A
    7A
    8A
    9A
    10A

    Multicolumn sort

    int float string
    1 10.0 a
    1 10.0 a
    2 10.0 b
    0 20.0 c
    1 30.0 b
    2 30.0 a
    0 10.0 b
    0 20.0 a
    0 10.0 c
    1 20.0 a
    2 10.0 b
    3 30.0 a
    2 30.0 b
    Stupid-Table-Plugin-1.1.3/tests/test.html000066400000000000000000000226111316766721000202670ustar00rootroot00000000000000 Stupid-Table Tests

    Basic Table

    int float string
    15 -.18 banana
    95 36 coke
    2 -152.5 apple
    -53 88.5 zebra
    195 -858 orange

    Basic Onload Table

    int float string
    15 -.18 banana
    95 36 coke
    2 -152.5 apple
    -53 88.5 zebra
    195 -858 orange

    Complex Table

    int float case Can't sort me! date Letter frequency
    15 -.18 Homer arbitrary Sep 15, 2002 E
    95 36 purple pointless Aug 07, 2004 T
    2 -152.5 is silly Mar 15, 1986 A
    -53 88.5 a eccentric Feb 27, 2086 O
    195 -858 fruit garbage Mar 15, 1986 I

    Basic Colspan Table

    Letter colspan=2 Number
    def X 9 1
    abc Z 8 2
    bcd Y 7 0

    Complex Colspan Table

    The Big Table Header
    Letter colspan=2 Number
    def X 9 1
    abc Z 8 2
    bcd Y 7 0

    Stability Testing Table

    (Unsortable) Index Key
    0A
    1A
    2A
    3A
    4A
    5A
    6A
    7A
    8A
    9A
    10A

    Multicolumn sort

    int float string
    1 10.0 a
    1 10.0 a
    2 10.0 b
    0 20.0 c
    1 30.0 b
    2 30.0 a
    0 10.0 b
    0 20.0 a
    0 10.0 c
    1 20.0 a
    2 10.0 b
    3 30.0 a
    2 30.0 b
    Stupid-Table-Plugin-1.1.3/tests/tests.js000066400000000000000000000653551316766721000201360ustar00rootroot00000000000000/* * IMPORTANT NOTE: Because testing DOM manipulation is really annoying, my * tests will be created using many setTimeouts. This means if your computer * is substantially slower than mine, you may get inconsistent results. */ $(function(){ // =========================================================================== // Test helpers & QUnit callbacks // =========================================================================== window.WAIT_TIME_MS = 200; var get_column_elements = function($table, col_index){ var vals = []; $table.find("tbody tr").each(function(){ var val = $(this).children("td").eq(col_index).html(); vals.push(val); }); return vals; }; var test_table_state = function(fn){ setTimeout(function(){ fn(); QUnit.start(); }, WAIT_TIME_MS); }; var date_from_string = function(str){ var months = ["jan","feb","mar","apr","may","jun","jul", "aug","sep","oct","nov","dec"]; var pattern = "^([a-zA-Z]{3})\\s*(\\d{2}),\\s*(\\d{4})$"; var re = new RegExp(pattern); var DateParts = re.exec(str).slice(1); var Year = DateParts[2]; var Month = $.inArray(DateParts[0].toLowerCase(), months); var Day = DateParts[1]; return new Date(Year, Month, Day); }; /* * In order to accurately simulate a double click, we have to use a slight pause * between clicks. During unittests, calling .click() on a column header twice * without delay causes the sort to get out of order. I have not been able to * reproduce this manually. Maybe some sort of lock is needed...UNTIL THEN!... */ $.fn.doubleclick = function(){ var $this = $(this); $this.click(); setTimeout(function(){ $this.click(); }, 10); return this; }; /* * Enable stupid tables at the end for manual testing and experiments */ QUnit.done(function(){ $("#complex").stupidtable({ "date":function(a,b){ // Get these into date objects for comparison. var aDate = date_from_string(a); var bDate = date_from_string(b); return aDate - bDate; } }); $("#basic").stupidtable(); $("#basic-colspan").stupidtable(); $("#complex-colspan").stupidtable(); $("#stability-test").stupidtable(); $("#multicolumn-sort-test").stupidtable(); $("#qunit-fixture").removeClass("test-hidden"); }); /* * Begin tests * NOTE: when to use test vs asyncTest: When you plan on sorting the table and * examining the results, you must use the test_table_state function and have * your test wrapped in asyncTest(). If you wish to only make assertions * regarding the initial state of the html, just use test(). */ // ============================================================================= // basic table // ============================================================================= test("Basic table initial order", function(){ var INT_COLUMN = 0; var FLOAT_COLUMN = 1; var STRING_COLUMN = 2; var expected; var vals; var $table = $("#basic"); expected = ["15", "95", "2", "-53", "195"]; vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["-.18", "36", "-152.5", "88.5", "-858"]; vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["banana", "coke", "apple", "zebra", "orange"]; vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); asyncTest("Basic int sort", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(INT_COLUMN).click(); test_table_state(function(){ var expected = ["-53", "2", "15", "95", "195"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic float sort", function(){ var FLOAT_COLUMN = 1; var $table = $("#basic"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(FLOAT_COLUMN).click(); test_table_state(function(){ var expected = ["-858", "-152.5", "-.18", "36", "88.5"]; var vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic string sort", function(){ var STRING_COLUMN = 2; var $table = $("#basic"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(STRING_COLUMN).click(); test_table_state(function(){ var expected = ["apple", "banana", "coke", "orange", "zebra"]; var vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic alternating sort", function(){ // A double click should cause the sort to reverse var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(INT_COLUMN).doubleclick(); test_table_state(function(){ var expected = ["195", "95", "15", "2", "-53"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); // ============================================================================= // complex table // ============================================================================= test("Complex table initial order", function(){ var INT_COLUMN = 0; var FLOAT_COLUMN = 1; var STRING_COLUMN = 2; var NOSORT_COLUMN = 3; var DATE_COLUMN = 4; var LETTER_FREQ_COLUMN = 5; var expected; var vals; var $table = $("#complex"); expected = ["15", "95", "2", "-53", "195"]; vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["-.18", "36", "-152.5", "88.5", "-858"]; vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["Homer", "purple", "is", "a", "fruit"]; vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); expected = ["arbitrary", "pointless", "silly", "eccentric", "garbage"]; vals = get_column_elements($table, NOSORT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["Sep 15, 2002", "Aug 07, 2004", "Mar 15, 1986", "Feb 27, 2086", "Mar 15, 1986"]; vals = get_column_elements($table, DATE_COLUMN); ok(_.isEqual(vals, expected)); expected = ["E", "T", "A", "O", "I"]; vals = get_column_elements($table, LETTER_FREQ_COLUMN); ok(_.isEqual(vals, expected)); }); asyncTest("No data-sort means no sort", function(){ var NOSORT_COLUMN = 3; var $table = $("#complex"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(NOSORT_COLUMN).click(); test_table_state(function(){ var expected = ["arbitrary", "pointless", "silly", "eccentric", "garbage"]; var vals = get_column_elements($table, NOSORT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("data-sort-by values should be used over text values", function(){ var LETTER_FREQ_COLUMN = 5; var $table = $("#complex"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(LETTER_FREQ_COLUMN).click(); test_table_state(function(){ var expected = ["E", "T", "A", "O", "I"]; var vals = get_column_elements($table, LETTER_FREQ_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("case insensitive string sort", function(){ var STRING_COLUMN = 2; var $table = $("#complex"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(STRING_COLUMN).click(); test_table_state(function(){ var expected = ["a", "fruit", "Homer", "is", "purple"]; var vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("custom sort functions", function(){ var DATE_COLUMN = 4; var $table = $("#complex"); var $table_cols = $table.find("th"); $table.stupidtable({ "date":function(a,b){ // Get these into date objects for comparison. var aDate = date_from_string(a); var bDate = date_from_string(b); return aDate - bDate; } }); $table_cols.eq(DATE_COLUMN).click(); test_table_state(function(){ var expected = ["Mar 15, 1986", "Mar 15, 1986", "Sep 15, 2002", "Aug 07, 2004", "Feb 27, 2086"]; var vals = get_column_elements($table, DATE_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("default sort direction - DESC", function(){ var FLOAT_COLUMN = 1; var $table = $("#complex"); var $table_cols = $table.find("th"); $table_cols.eq(FLOAT_COLUMN).data('sort-default', 'desc'); $table.stupidtable(); $table_cols.eq(FLOAT_COLUMN).click(); test_table_state(function(){ var expected = ["88.5", "36", "-.18", "-152.5", "-858"]; var vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("default sort direction - ASC", function(){ var FLOAT_COLUMN = 1; var $table = $("#complex"); var $table_cols = $table.find("th"); $table_cols.eq(FLOAT_COLUMN).data('sort-default', 'asc'); $table.stupidtable(); $table_cols.eq(FLOAT_COLUMN).click(); test_table_state(function(){ var expected = ["-858", "-152.5", "-.18", "36", "88.5"]; var vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("sorting should preserve tbody classes", function(){ var FLOAT_COLUMN = 1; var $table = $("#complex"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); var tbodyStyleBefore = $tbody.attr("style"); $table.stupidtable(); // These are initial values hardcoded in the html. We need to make sure they // aren't changed once we click a column. ok($tbody.hasClass('some-tbody-class')); ok(_.isEqual(tbodyStyleBefore, $tbody.attr("style"))); $table_cols.eq(FLOAT_COLUMN).click(); test_table_state(function(){ var $table = $("#complex"); var $tbody = $table.find("tbody"); ok($tbody.hasClass('some-tbody-class')); ok(_.isEqual(tbodyStyleBefore, $tbody.attr("style"))); }); }); asyncTest("Basic colspan table sort column before colspan column", function(){ var LETTER_COLUMN = 0; var $table = $("#basic-colspan"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); $table.stupidtable(); $table_cols.eq(LETTER_COLUMN).click(); test_table_state(function(){ var expected = ["abc", "bcd", "def"]; var vals = get_column_elements($table, LETTER_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic colspan table sort column after colspan column", function(){ var NUMBER_COLUMN_TH = 2; var NUMBER_COLUMN = 3; var $table = $("#basic-colspan"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); $table.stupidtable(); $table_cols.eq(NUMBER_COLUMN_TH).click(); test_table_state(function(){ var expected = ["0", "1", "2"]; var vals = get_column_elements($table, NUMBER_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic colspan table sort column on colspan column", function(){ var COLSPAN_COLUMN = 1; var $table = $("#basic-colspan"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); $table.stupidtable(); $table_cols.eq(COLSPAN_COLUMN).click(); test_table_state(function(){ var expected = ["X", "Y", "Z"]; var vals = get_column_elements($table, COLSPAN_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Complex colspan table sort - single click", function(){ var NUMBER_COLUMN_TH = 3; var NUMBER_COLUMN = 3; var $table = $("#complex-colspan"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); $table.stupidtable(); $table_cols.eq(NUMBER_COLUMN_TH).click(); test_table_state(function(){ var expected = ["0", "1", "2"]; var vals = get_column_elements($table, NUMBER_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Complex colspan table sort - double click", function(){ var NUMBER_COLUMN_TH = 3; var NUMBER_COLUMN = 3; var $table = $("#complex-colspan"); var $table_cols = $table.find("th"); var $tbody = $table.find("tbody"); $table.stupidtable(); $table_cols.eq(NUMBER_COLUMN_TH).doubleclick(); test_table_state(function(){ var expected = ["2", "1", "0"]; var vals = get_column_elements($table, NUMBER_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Update sort value - same display and sort values - single click", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); $int_column.click(); test_table_state(function(){ var expected = ["-53", "2", "95", "195", "200"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Update sort value - same display and sort values - double click", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); $int_column.doubleclick(); test_table_state(function(){ var expected = ["200", "195", "95", "2", "-53"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Update sort value - different display and sort value - single click", function(){ var LETTER_FREQ_COLUMN = 5; var $table = $("#complex"); var $table_cols = $table.find("th"); var $letter_freq_col = $table_cols.eq(LETTER_FREQ_COLUMN); var $e_td = $table.find("[data-sort-value=0]"); $table.stupidtable(); $letter_freq_col.click(); ok(_.isEqual($e_td.text(), "E")); ok(_.isEqual($e_td.data('sort-value'), 0)); $e_td.updateSortVal(10); $e_td.html("YO"); test_table_state(function(){ var expected = ["T", "A", "O", "I", "YO"]; var vals = get_column_elements($table, LETTER_FREQ_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Update sort value - different display and sort value - double click", function(){ var LETTER_FREQ_COLUMN = 5; var $table = $("#complex"); var $table_cols = $table.find("th"); var $letter_freq_col = $table_cols.eq(LETTER_FREQ_COLUMN); var $e_td = $table.find("[data-sort-value=0]"); $table.stupidtable(); $letter_freq_col.doubleclick(); ok(_.isEqual($e_td.text(), "E")); ok(_.isEqual($e_td.data('sort-value'), 0)); $e_td.updateSortVal(10); $e_td.html("YO"); test_table_state(function(){ var expected = ["YO", "I", "O", "A", "T"]; var vals = get_column_elements($table, LETTER_FREQ_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Update sort value - also updates data-sort-value attribute", function(){ var LETTER_FREQ_COLUMN = 5; var $table = $("#complex"); var $table_cols = $table.find("th"); var $letter_freq_col = $table_cols.eq(LETTER_FREQ_COLUMN); var $e_td = $table.find("[data-sort-value=0]"); $table.stupidtable(); $letter_freq_col.doubleclick(); ok(_.isEqual($e_td.text(), "E")); ok(_.isEqual($e_td.data('sort-value'), 0)); $e_td.updateSortVal(10); $e_td.html("YO"); test_table_state(function(){ var expected = ["YO", "I", "O", "A", "T"]; var vals = get_column_elements($table, LETTER_FREQ_COLUMN); ok(_.isEqual(vals, expected)); ok(_.isEqual($e_td.attr('data-sort-value'), "10")); }); }); asyncTest("Update sort value - display value only doesn't add data-sort-value attribute", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); $int_column.click(); test_table_state(function(){ var $first_int_td = $table.find("tbody tr td").first(); var expected = ["-53", "2", "95", "195", "200"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); ok(!$first_int_td.attr('data-sort-value')); }); }); asyncTest("Basic individual column sort - no force direction", function(){ var FLOAT_COLUMN = 1; var $table = $("#complex"); var $table_cols = $table.find("th"); // Specify a sorting direction $table_cols.eq(FLOAT_COLUMN).data('sort-default', 'desc'); $table.stupidtable(); $table_cols.eq(FLOAT_COLUMN).stupidsort(); test_table_state(function(){ var expected = ["88.5", "36", "-.18", "-152.5", "-858"]; var vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Basic individual column sort - force direction", function(){ var FLOAT_COLUMN = 1; var $table = $("#complex"); var $table_cols = $table.find("th"); // Specify a sorting direction $table_cols.eq(FLOAT_COLUMN).data('sort-default', 'desc'); $table.stupidtable(); $table_cols.eq(FLOAT_COLUMN).stupidsort('asc'); test_table_state(function(){ var expected = ["-858", "-152.5", "-.18", "36", "88.5"]; var vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Sort Stability Testing - 1", function(){ // Not all browsers implement stable sorting. View the following for more // information: // http://ofb.net/~sethml/is-sort-stable.html // http://codecoding.com/beware-chrome-array-sort-implementation-is-unstable/ var INDEX_COLUMN = 0; var LETTER_COLUMN = 1; var $table = $("#stability-test"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(LETTER_COLUMN).click(); test_table_state(function(){ var expected = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; var vals = get_column_elements($table, INDEX_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("Sort Stability Testing - 2", function(){ // Not all browsers implement stable sorting. View the following for more // information: // http://ofb.net/~sethml/is-sort-stable.html // http://codecoding.com/beware-chrome-array-sort-implementation-is-unstable/ var INDEX_COLUMN = 0; var LETTER_COLUMN = 1; var $table = $("#stability-test"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(LETTER_COLUMN).doubleclick(); test_table_state(function(){ var expected = ["10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "0"]; var vals = get_column_elements($table, INDEX_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("$th passed to after/before tablesort event handlers", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $th_objs = []; $table.stupidtable(); var $int_header = $table_cols.eq(INT_COLUMN) $table.bind('beforetablesort', function(e, data){ $th_objs.push(data.$th); }); var afterCalls = 0; $table.bind('aftertablesort', function(e, data){ $th_objs.push(data.$th); }); $int_header.click(); var get_raw_elements = function(arr){ return _.map(arr, function(el){ return el[0]; }); }; test_table_state(function(){ var expected = get_raw_elements([$int_header, $int_header]); var raw_th_objs = get_raw_elements($th_objs); ok(_.isEqual(raw_th_objs, expected)); }); }); asyncTest("consective calls to stupidsort in same direction should work (issue #183) ", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_col = $table_cols.eq(INT_COLUMN); var $e_td = $table.find("[data-sort-value=2]"); $table.stupidtable(); $table_cols.eq(INT_COLUMN).stupidsort($.fn.stupidtable.dir.ASC); // Verify we have td with the value 2 in the INT column. ok(_.isEqual($e_td.text(), "2")); setTimeout(function(){ var newval = -100; $e_td.updateSortVal(newval); $e_td.text(newval); $table_cols.eq(INT_COLUMN).stupidsort($.fn.stupidtable.dir.ASC); test_table_state(function(){ var expected = ["-100", "-53", "15", "95", "195"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }, window.WAIT_TIME_MS); }); asyncTest("table sorts column onload when specified (issue #180) ", function(){ var STRING_COLUMN = 2; var $table = $("#basic-onload"); var $table_cols = $table.find("th"); var $str_col = $table_cols.eq(STRING_COLUMN); $table.stupidtable(); test_table_state(function(){ var expected = ["apple", "banana", "coke", "orange", "zebra"]; var vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("test should_redraw setting", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); $table.stupidtable_settings({ should_redraw: function(sort_info){ return false; } }); $table.stupidtable(); $table_cols.eq(INT_COLUMN).click(); test_table_state(function(){ // Redrawing will never occur so we should expect the initial order to // be the current column order. var expected = ["15", "95", "2", "-53", "195"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("test will_manually_build_table setting - 1", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable_settings({ will_manually_build_table: true }); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); $int_column.click(); test_table_state(function(){ // Since we didn't manually build the table after updating the value, we // shouldn't expect the table to sort correctly. 200 will still function // as 15 var expected = ["-53", "2", "200", "95", "195"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("test will_manually_build_table setting - 2", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable_settings({ will_manually_build_table: true }); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); // Rebuild the table $table.stupidtable_build(); $int_column.click(); test_table_state(function(){ // Since we didn't manually build the table after updating the value, we // shouldn't expect the table to sort correctly. 200 will still function // as 15 var expected = ["-53", "2", "95", "195", "200"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); asyncTest("test will_manually_build_table setting - 3", function(){ var INT_COLUMN = 0; var $table = $("#basic"); var $table_cols = $table.find("th"); var $int_column = $table_cols.eq(INT_COLUMN); var $first_int_td = $table.find("tbody tr td").first(); $table.stupidtable_settings({ will_manually_build_table: false }); $table.stupidtable(); ok(_.isEqual($first_int_td.text(), "15")); $first_int_td.updateSortVal(200); $first_int_td.text("200"); $int_column.click(); test_table_state(function(){ // Since we didn't manually build the table after updating the value, we // shouldn't expect the table to sort correctly. 200 will still function // as 15 var expected = ["-53", "2", "95", "195", "200"]; var vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); }); }); test("Multicolumn table initial order", function(){ var INT_COLUMN = 0; var FLOAT_COLUMN = 1; var STRING_COLUMN = 2; var expected; var vals; var $table = $("#multicolumn-sort-test"); expected = ["1", "1", "2", "0", "1", "2", "0", "0", "0", "1", "2", "3", "2"]; vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["10.0", "10.0", "10.0", "20.0", "30.0", "30.0", "10.0", "20.0", "10.0", "20.0", "10.0", "30.0", "30.0"]; vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["a", "a", "b", "c", "b", "a", "b", "a", "c", "a", "b", "a", "b"]; vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); asyncTest("Basic multicolumn sort", function(){ var INT_COLUMN = 0; var FLOAT_COLUMN = 1; var STRING_COLUMN = 2; var $table = $("#multicolumn-sort-test"); var $table_cols = $table.find("th"); $table.stupidtable(); $table_cols.eq(INT_COLUMN).click(); test_table_state(function(){ var expected; var vals; expected = ["0", "0", "0", "0", "1", "1", "1", "1", "2", "2", "2", "2", "3"]; vals = get_column_elements($table, INT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["10.0", "10.0", "20.0", "20.0", "10.0", "10.0", "20.0", "30.0", "10.0", "10.0", "30.0", "30.0", "30.0"]; vals = get_column_elements($table, FLOAT_COLUMN); ok(_.isEqual(vals, expected)); expected = ["b", "c", "a", "c", "a", "a", "a", "b", "b", "b", "a", "b", "a"]; vals = get_column_elements($table, STRING_COLUMN); ok(_.isEqual(vals, expected)); }); }); }); //jQuery