26 |
reference height
27 |
one line test dom
28 |
two line test dom
29 |
one line test dom, change char
30 |
two line test dom, change char
31 |
32 |
mulitple test dom1
33 |
mulitple test dom2
34 |
mulitple test dom2
35 |
36 |
no ellipsis
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # THIS PLUGIN IS NO LONGER BEING MAINTAINED
2 |
3 |
4 | # jQuery ellipsis [](https://travis-ci.org/STAR-ZERO/jquery-ellipsis) [](https://coveralls.io/r/STAR-ZERO/jquery-ellipsis?branch=master) [](https://gemnasium.com/STAR-ZERO/jquery-ellipsis)
5 |
6 | Support multiple lines ellipsis
7 |
8 | [http://plugins.jquery.com/ellipsis/](http://plugins.jquery.com/ellipsis/)
9 |
10 | ## Getting Started
11 | Download the [production version][min] or the [development version][max].
12 |
13 | [min]: https://raw.github.com/STAR-ZERO/jquery-ellipsis/master/dist/jquery.ellipsis.min.js
14 | [max]: https://raw.github.com/STAR-ZERO/jquery-ellipsis/master/dist/jquery.ellipsis.js
15 |
16 |
17 | ## Usage
18 |
19 | Fit one line
20 |
21 | ```
22 | $('#target').ellipsis();
23 | ```
24 |
25 | Fit on two lines in the case of two or more lines
26 |
27 | ```
28 | $('#target').ellipsis({
29 | row: 2
30 | });
31 | ```
32 |
33 | Change ellipsis character
34 |
35 | ```
36 | $('#target').ellipsis({
37 | row: 2,
38 | char: '**'
39 | });
40 | ```
41 |
42 | Only include full words (remove word fragments at the end)
43 |
44 | ```
45 | $('#target').ellipsis({
46 | row: 2,
47 | onlyFullWords: true
48 | });
49 | ```
50 |
51 | Callback function
52 |
53 | ```
54 | $('#target').ellipsis({
55 | callback: function() {
56 | console.log($(this).text());
57 | }
58 | });
59 | ```
60 |
61 | Ellipsis for middle position
62 |
63 | ```
64 | $('#target').ellipsis({
65 | position: 'middle'
66 | });
67 | ```
68 |
69 | Ellipsis for tail position
70 |
71 | ```
72 | $('#target').ellipsis({
73 | position: 'tail'
74 | });
75 | ```
76 |
77 | ## License
78 | jquery-ellipsis is available under the terms of the [MIT License](https://github.com/STAR-ZERO/jquery-ellipsis/blob/master/LICENSE-MIT).
79 |
80 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Important notes
4 | Please don't edit files in the `dist` subdirectory as they are generated via grunt. You'll find source code in the `src` subdirectory!
5 |
6 | ### Code style
7 | Regarding code style like indentation and whitespace, **follow the conventions you see used in the source already.**
8 |
9 | ### PhantomJS
10 | While grunt can run the included unit tests via [PhantomJS](http://phantomjs.org/), this shouldn't be considered a substitute for the real thing. Please be sure to test the `test/*.html` unit test file(s) in _actual_ browsers.
11 |
12 | See the [Why does grunt complain that PhantomJS isn't installed?](https://github.com/gruntjs/grunt/blob/master/docs/faq.md#why-does-grunt-complain-that-phantomjs-isnt-installed) guide in the [Grunt FAQ](https://github.com/gruntjs/grunt/blob/master/docs/faq.md) for help with installing or troubleshooting PhantomJS.
13 |
14 | ## Modifying the code
15 | First, ensure that you have the latest [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/) installed.
16 |
17 | Test that grunt is installed globally by running `grunt --version` at the command-line. If grunt isn't installed globally, run `npm install -g grunt` to install the latest version. _You may need to run `sudo npm install -g grunt`._
18 |
19 | _Note that in Windows, you may have to run `grunt.cmd` instead of `grunt`._
20 |
21 | 1. Fork and clone the repo.
22 | 1. Run `npm install` to install all dependencies (including grunt).
23 | 1. Run `grunt` to grunt this project.
24 |
25 | Assuming that you don't see any red, you're ready to go. Just be sure to run `grunt` after making any changes, to ensure that nothing is broken.
26 |
27 | ## Submitting pull requests
28 |
29 | 1. Create a new branch, please don't work in your `master` branch directly.
30 | 1. Add failing tests for the change you want to make. Run `grunt` to see the tests fail.
31 | 1. Fix stuff.
32 | 1. Run `grunt` to see if the tests pass. Repeat steps 2-4 until done.
33 | 1. Open `test/*.html` unit test file(s) in actual browser to ensure tests pass everywhere.
34 | 1. Update the documentation to reflect any changes.
35 | 1. Push to your fork and submit a pull request.
36 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(grunt) {
4 |
5 | // Project configuration.
6 | grunt.initConfig({
7 | // Metadata.
8 | pkg: grunt.file.readJSON('ellipsis.jquery.json'),
9 | name: 'jquery.ellipsis',
10 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
11 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
12 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
13 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
14 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
15 | // Task configuration.
16 | clean: {
17 | files: ['dist']
18 | },
19 | concat: {
20 | options: {
21 | banner: '<%= banner %>',
22 | stripBanners: true
23 | },
24 | dist: {
25 | src: ['src/<%= name %>.js'],
26 | dest: 'dist/<%= name %>.js'
27 | },
28 | },
29 | uglify: {
30 | options: {
31 | banner: '<%= banner %>'
32 | },
33 | dist: {
34 | src: '<%= concat.dist.dest %>',
35 | dest: 'dist/<%= name %>.min.js'
36 | },
37 | },
38 | qunit: {
39 | files: ['test/**/*.html'],
40 | options: {
41 | coverage: {
42 | src: ['src/**/*.js'],
43 | instrumentedFiles: "temp/",
44 | lcovReport: "report/coverage"
45 | }
46 | }
47 | },
48 | jshint: {
49 | gruntfile: {
50 | options: {
51 | jshintrc: '.jshintrc'
52 | },
53 | src: 'Gruntfile.js'
54 | },
55 | src: {
56 | options: {
57 | jshintrc: 'src/.jshintrc'
58 | },
59 | src: ['src/**/*.js']
60 | },
61 | test: {
62 | options: {
63 | jshintrc: 'test/.jshintrc'
64 | },
65 | src: ['test/**/*.js']
66 | },
67 | },
68 | shell: {
69 | 'coverall': {
70 | command: 'node_modules/coveralls/bin/coveralls.js < report/coverage/lcov.info'
71 | }
72 | },
73 | watch: {
74 | gruntfile: {
75 | files: '<%= jshint.gruntfile.src %>',
76 | tasks: ['jshint:gruntfile']
77 | },
78 | src: {
79 | files: '<%= jshint.src.src %>',
80 | tasks: ['jshint:src', 'qunit']
81 | },
82 | test: {
83 | files: '<%= jshint.test.src %>',
84 | tasks: ['jshint:test', 'qunit']
85 | },
86 | },
87 | });
88 |
89 | // These plugins provide necessary tasks.
90 | grunt.loadNpmTasks('grunt-contrib-clean');
91 | grunt.loadNpmTasks('grunt-contrib-concat');
92 | grunt.loadNpmTasks('grunt-contrib-uglify');
93 | grunt.loadNpmTasks('grunt-contrib-qunit');
94 | grunt.loadNpmTasks('grunt-contrib-jshint');
95 | grunt.loadNpmTasks('grunt-contrib-watch');
96 | grunt.loadNpmTasks('grunt-shell');
97 | grunt.loadNpmTasks('grunt-qunit-istanbul');
98 |
99 | // Default task.
100 | grunt.registerTask('default', ['jshint', 'qunit', 'clean', 'concat', 'uglify']);
101 |
102 | // Travis CI
103 | grunt.registerTask('travis', ['jshint', 'qunit', 'shell:coverall']);
104 | };
105 |
--------------------------------------------------------------------------------
/src/jquery.ellipsis.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | $.fn.ellipsis = function(options) {
3 |
4 | // default option
5 | var defaults = {
6 | 'row' : 1, // show rows
7 | 'onlyFullWords': false, // set to true to avoid cutting the text in the middle of a word
8 | 'char' : '...', // ellipsis
9 | 'callback': function() {},
10 | 'position': 'tail' // middle, tail
11 | };
12 |
13 | options = $.extend(defaults, options);
14 |
15 | this.each(function() {
16 | // get element text
17 | var $this = $(this);
18 | var text = $this.text();
19 | var origText = text;
20 | var origLength = origText.length;
21 | var origHeight = $this.height();
22 |
23 | // get height
24 | $this.text('a');
25 | var lineHeight = parseFloat($this.css("lineHeight"), 10);
26 | var rowHeight = $this.height();
27 | var gapHeight = lineHeight > rowHeight ? (lineHeight - rowHeight) : 0;
28 | var targetHeight = gapHeight * (options.row - 1) + rowHeight * options.row;
29 |
30 | if (origHeight <= targetHeight) {
31 | $this.text(text);
32 | options.callback.call(this);
33 | return;
34 | }
35 |
36 | var start = 1, length = 0;
37 | var end = text.length;
38 |
39 | if(options.position === 'tail') {
40 | while (start < end) { // Binary search for max length
41 | length = Math.ceil((start + end) / 2);
42 |
43 | $this.text(text.slice(0, length) + options['char']);
44 |
45 | if ($this.height() <= targetHeight) {
46 | start = length;
47 | } else {
48 | end = length - 1;
49 | }
50 | }
51 |
52 | text = text.slice(0, start);
53 |
54 | if (options.onlyFullWords) {
55 | text = text.replace(/[\u00AD\w\uac00-\ud7af]+$/, ''); // remove fragment of the last word together with possible soft-hyphen characters
56 | }
57 | text += options['char'];
58 |
59 | }else if(options.position === 'middle') {
60 |
61 | var sliceLength = 0;
62 | while (start < end) { // Binary search for max length
63 | length = Math.ceil((start + end) / 2);
64 | sliceLength = Math.max(origLength - length, 0);
65 |
66 | $this.text(
67 | origText.slice(0, Math.floor((origLength - sliceLength) / 2)) +
68 | options['char'] +
69 | origText.slice(Math.floor((origLength + sliceLength) / 2), origLength)
70 | );
71 |
72 | if ($this.height() <= targetHeight) {
73 | start = length;
74 | } else {
75 | end = length - 1;
76 | }
77 | }
78 |
79 | sliceLength = Math.max(origLength - start, 0);
80 | var head = origText.slice(0, Math.floor((origLength - sliceLength) / 2));
81 | var tail = origText.slice(Math.floor((origLength + sliceLength) / 2), origLength);
82 |
83 | if (options.onlyFullWords) {
84 | // remove fragment of the last or first word together with possible soft-hyphen characters
85 | head = head.replace(/[\u00AD\w\uac00-\ud7af]+$/, '');
86 | }
87 |
88 | text = head + options['char'] + tail;
89 | }
90 |
91 | $this.text(text);
92 |
93 | options.callback.call(this);
94 | });
95 |
96 | return this;
97 | };
98 | }) (jQuery);
99 |
--------------------------------------------------------------------------------
/dist/jquery.ellipsis.js:
--------------------------------------------------------------------------------
1 | /*! jQuery ellipsis - v1.1.1 - 2014-02-23
2 | * https://github.com/STAR-ZERO/jquery-ellipsis
3 | * Copyright (c) 2014 Kenji Abe; Licensed MIT */
4 | (function($) {
5 | $.fn.ellipsis = function(options) {
6 |
7 | // default option
8 | var defaults = {
9 | 'row' : 1, // show rows
10 | 'onlyFullWords': false, // set to true to avoid cutting the text in the middle of a word
11 | 'char' : '...', // ellipsis
12 | 'callback': function() {},
13 | 'position': 'tail' // middle, tail
14 | };
15 |
16 | options = $.extend(defaults, options);
17 |
18 | this.each(function() {
19 | // get element text
20 | var $this = $(this);
21 | var text = $this.text();
22 | var origText = text;
23 | var origLength = origText.length;
24 | var origHeight = $this.height();
25 |
26 | // get height
27 | $this.text('a');
28 | var lineHeight = parseFloat($this.css("lineHeight"), 10);
29 | var rowHeight = $this.height();
30 | var gapHeight = lineHeight > rowHeight ? (lineHeight - rowHeight) : 0;
31 | var targetHeight = gapHeight * (options.row - 1) + rowHeight * options.row;
32 |
33 | if (origHeight <= targetHeight) {
34 | $this.text(text);
35 | options.callback.call(this);
36 | return;
37 | }
38 |
39 | var start = 1, length = 0;
40 | var end = text.length;
41 |
42 | if(options.position === 'tail') {
43 | while (start < end) { // Binary search for max length
44 | length = Math.ceil((start + end) / 2);
45 |
46 | $this.text(text.slice(0, length) + options['char']);
47 |
48 | if ($this.height() <= targetHeight) {
49 | start = length;
50 | } else {
51 | end = length - 1;
52 | }
53 | }
54 |
55 | text = text.slice(0, start);
56 |
57 | if (options.onlyFullWords) {
58 | text = text.replace(/[\u00AD\w\uac00-\ud7af]+$/, ''); // remove fragment of the last word together with possible soft-hyphen characters
59 | }
60 | text += options['char'];
61 |
62 | }else if(options.position === 'middle') {
63 |
64 | var sliceLength = 0;
65 | while (start < end) { // Binary search for max length
66 | length = Math.ceil((start + end) / 2);
67 | sliceLength = Math.max(origLength - length, 0);
68 |
69 | $this.text(
70 | origText.slice(0, Math.floor((origLength - sliceLength) / 2)) +
71 | options['char'] +
72 | origText.slice(Math.floor((origLength + sliceLength) / 2), origLength)
73 | );
74 |
75 | if ($this.height() <= targetHeight) {
76 | start = length;
77 | } else {
78 | end = length - 1;
79 | }
80 | }
81 |
82 | sliceLength = Math.max(origLength - start, 0);
83 | var head = origText.slice(0, Math.floor((origLength - sliceLength) / 2));
84 | var tail = origText.slice(Math.floor((origLength + sliceLength) / 2), origLength);
85 |
86 | if (options.onlyFullWords) {
87 | // remove fragment of the last or first word together with possible soft-hyphen characters
88 | head = head.replace(/[\u00AD\w\uac00-\ud7af]+$/, '');
89 | }
90 |
91 | text = head + options['char'] + tail;
92 | }
93 |
94 | $this.text(text);
95 |
96 | options.callback.call(this);
97 | });
98 |
99 | return this;
100 | };
101 | }) (jQuery);
102 |
--------------------------------------------------------------------------------
/test/jquery.ellipsis_test.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 |
3 | test('one line ellipsis', function() {
4 | $('#one').ellipsis();
5 | var text = $('#one').text();
6 | equal(text.lastIndexOf('...'), text.length - 3);
7 | equal($('#one').height(), $('#ref-height').height());
8 | });
9 |
10 | test('two line ellipsis', function() {
11 | $('#two').ellipsis({
12 | row: 2
13 | });
14 | var text = $('#two').text();
15 | equal(text.lastIndexOf('...'), text.length - 3);
16 | equal($('#two').height(), $('#ref-height').height() * 2);
17 | });
18 |
19 | test('one line ellipsis, change char', function() {
20 | $('#one-char').ellipsis({
21 | char: '**'
22 | });
23 | var text = $('#one-char').text();
24 | equal(text.lastIndexOf('**'), text.length - 2);
25 | equal($('#one-char').height(), $('#ref-height').height());
26 | });
27 |
28 | test('two line ellipsis, change char', function() {
29 | $('#two-char').ellipsis({
30 | row: 2,
31 | char: '**'
32 | });
33 | var text = $('#two-char').text();
34 | equal(text.lastIndexOf('**'), text.length - 2);
35 | equal($('#two-char').height(), $('#ref-height').height() * 2);
36 | });
37 |
38 | test('mulitple element', function() {
39 | expect(6);
40 | $('#multi p').ellipsis();
41 | $('#multi p').each(function() {
42 | var text = $(this).text();
43 | equal(text.lastIndexOf('...'), text.length - 3);
44 | equal($(this).height(), $('#ref-height').height());
45 | });
46 | });
47 |
48 | test('two line ellipsis with full word setting', function() {
49 | $('#two-char').ellipsis({
50 | row: 2,
51 | onlyFullWords: true
52 | });
53 | var text = $('#two-char').text();
54 | equal(text.lastIndexOf(' ...'), text.length - 4);
55 | equal($('#two-char').height(), $('#ref-height').height() * 2);
56 | });
57 |
58 | test('no ellipsis', function() {
59 | var expected = $('#no-ellipsis').text();
60 | $('#no-ellipsis').ellipsis();
61 | var actual = $('#no-ellipsis').text();
62 | equal(actual, expected);
63 | });
64 |
65 | test('call callback function', function() {
66 | $('#one').ellipsis({
67 | callback: function() {
68 | equal(this.id, 'one');
69 | }
70 | });
71 | });
72 |
73 | test('call callback function', function() {
74 | $('#no-ellipsis').ellipsis({
75 | callback: function() {
76 | equal(this.id, 'no-ellipsis');
77 | }
78 | });
79 | });
80 |
81 | test('one line ellipsis for middle position', function() {
82 | $('#one').ellipsis({
83 | position: 'middle'
84 | });
85 | var text = $('#one').text();
86 | equal(text.lastIndexOf('...'), text.length - 6);
87 | equal($('#one').height(), $('#ref-height').height());
88 | });
89 |
90 | test('two line ellipsis for middle position', function() {
91 | $('#two').ellipsis({
92 | row: 2,
93 | position: 'middle'
94 | });
95 | var text = $('#two').text();
96 | equal(text.lastIndexOf('...'), text.length - 7);
97 | equal($('#two').height(), $('#ref-height').height() * 2);
98 | });
99 |
100 | test('one line ellipsis, change char for middle position', function() {
101 | $('#one-char').ellipsis({
102 | char: '**',
103 | position: 'middle'
104 | });
105 | var text = $('#one-char').text();
106 | equal(text.lastIndexOf('**'), text.length - 6);
107 | equal($('#one-char').height(), $('#ref-height').height());
108 | });
109 |
110 | test('two line ellipsis, change char for middle position', function() {
111 | $('#two-char').ellipsis({
112 | row: 2,
113 | char: '**',
114 | position: 'middle'
115 | });
116 | var text = $('#two-char').text();
117 | equal(text.lastIndexOf('**'), text.length - 6);
118 | equal($('#two-char').height(), $('#ref-height').height() * 2);
119 | });
120 |
121 | test('mulitple element for middle position', function() {
122 | expect(6);
123 | $('#multi p').ellipsis({ position: 'middle' });
124 | $('#multi p').each(function() {
125 | var text = $(this).text();
126 | equal(text.lastIndexOf('...'), text.length - 7);
127 | equal($(this).height(), $('#ref-height').height());
128 | });
129 | });
130 |
131 | test('two line ellipsis with full word setting for middle position', function() {
132 | $('#two-char').ellipsis({
133 | row: 2,
134 | onlyFullWords: true,
135 | position: 'middle'
136 | });
137 | var text = $('#two-char').text();
138 | equal(text.lastIndexOf(' ...'), text.length - 8);
139 | equal($('#two-char').height(), $('#ref-height').height() * 2);
140 | });
141 |
142 | }(jQuery));
143 |
--------------------------------------------------------------------------------
/libs/qunit/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit v1.4.0 - A JavaScript Unit Testing Framework
3 | *
4 | * http://docs.jquery.com/QUnit
5 | *
6 | * Copyright (c) 2012 John Resig, Jörn Zaefferer
7 | * Dual licensed under the MIT (MIT-LICENSE.txt)
8 | * or GPL (GPL-LICENSE.txt) licenses.
9 | */
10 |
11 | /** Font Family and Sizes */
12 |
13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15 | }
16 |
17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18 | #qunit-tests { font-size: smaller; }
19 |
20 |
21 | /** Resets */
22 |
23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 |
29 | /** Header */
30 |
31 | #qunit-header {
32 | padding: 0.5em 0 0.5em 1em;
33 |
34 | color: #8699a4;
35 | background-color: #0d3349;
36 |
37 | font-size: 1.5em;
38 | line-height: 1em;
39 | font-weight: normal;
40 |
41 | border-radius: 15px 15px 0 0;
42 | -moz-border-radius: 15px 15px 0 0;
43 | -webkit-border-top-right-radius: 15px;
44 | -webkit-border-top-left-radius: 15px;
45 | }
46 |
47 | #qunit-header a {
48 | text-decoration: none;
49 | color: #c2ccd1;
50 | }
51 |
52 | #qunit-header a:hover,
53 | #qunit-header a:focus {
54 | color: #fff;
55 | }
56 |
57 | #qunit-header label {
58 | display: inline-block;
59 | }
60 |
61 | #qunit-banner {
62 | height: 5px;
63 | }
64 |
65 | #qunit-testrunner-toolbar {
66 | padding: 0.5em 0 0.5em 2em;
67 | color: #5E740B;
68 | background-color: #eee;
69 | }
70 |
71 | #qunit-userAgent {
72 | padding: 0.5em 0 0.5em 2.5em;
73 | background-color: #2b81af;
74 | color: #fff;
75 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
76 | }
77 |
78 |
79 | /** Tests: Pass/Fail */
80 |
81 | #qunit-tests {
82 | list-style-position: inside;
83 | }
84 |
85 | #qunit-tests li {
86 | padding: 0.4em 0.5em 0.4em 2.5em;
87 | border-bottom: 1px solid #fff;
88 | list-style-position: inside;
89 | }
90 |
91 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
92 | display: none;
93 | }
94 |
95 | #qunit-tests li strong {
96 | cursor: pointer;
97 | }
98 |
99 | #qunit-tests li a {
100 | padding: 0.5em;
101 | color: #c2ccd1;
102 | text-decoration: none;
103 | }
104 | #qunit-tests li a:hover,
105 | #qunit-tests li a:focus {
106 | color: #000;
107 | }
108 |
109 | #qunit-tests ol {
110 | margin-top: 0.5em;
111 | padding: 0.5em;
112 |
113 | background-color: #fff;
114 |
115 | border-radius: 15px;
116 | -moz-border-radius: 15px;
117 | -webkit-border-radius: 15px;
118 |
119 | box-shadow: inset 0px 2px 13px #999;
120 | -moz-box-shadow: inset 0px 2px 13px #999;
121 | -webkit-box-shadow: inset 0px 2px 13px #999;
122 | }
123 |
124 | #qunit-tests table {
125 | border-collapse: collapse;
126 | margin-top: .2em;
127 | }
128 |
129 | #qunit-tests th {
130 | text-align: right;
131 | vertical-align: top;
132 | padding: 0 .5em 0 0;
133 | }
134 |
135 | #qunit-tests td {
136 | vertical-align: top;
137 | }
138 |
139 | #qunit-tests pre {
140 | margin: 0;
141 | white-space: pre-wrap;
142 | word-wrap: break-word;
143 | }
144 |
145 | #qunit-tests del {
146 | background-color: #e0f2be;
147 | color: #374e0c;
148 | text-decoration: none;
149 | }
150 |
151 | #qunit-tests ins {
152 | background-color: #ffcaca;
153 | color: #500;
154 | text-decoration: none;
155 | }
156 |
157 | /*** Test Counts */
158 |
159 | #qunit-tests b.counts { color: black; }
160 | #qunit-tests b.passed { color: #5E740B; }
161 | #qunit-tests b.failed { color: #710909; }
162 |
163 | #qunit-tests li li {
164 | margin: 0.5em;
165 | padding: 0.4em 0.5em 0.4em 0.5em;
166 | background-color: #fff;
167 | border-bottom: none;
168 | list-style-position: inside;
169 | }
170 |
171 | /*** Passing Styles */
172 |
173 | #qunit-tests li li.pass {
174 | color: #5E740B;
175 | background-color: #fff;
176 | border-left: 26px solid #C6E746;
177 | }
178 |
179 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
180 | #qunit-tests .pass .test-name { color: #366097; }
181 |
182 | #qunit-tests .pass .test-actual,
183 | #qunit-tests .pass .test-expected { color: #999999; }
184 |
185 | #qunit-banner.qunit-pass { background-color: #C6E746; }
186 |
187 | /*** Failing Styles */
188 |
189 | #qunit-tests li li.fail {
190 | color: #710909;
191 | background-color: #fff;
192 | border-left: 26px solid #EE5757;
193 | white-space: pre;
194 | }
195 |
196 | #qunit-tests > li:last-child {
197 | border-radius: 0 0 15px 15px;
198 | -moz-border-radius: 0 0 15px 15px;
199 | -webkit-border-bottom-right-radius: 15px;
200 | -webkit-border-bottom-left-radius: 15px;
201 | }
202 |
203 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
204 | #qunit-tests .fail .test-name,
205 | #qunit-tests .fail .module-name { color: #000000; }
206 |
207 | #qunit-tests .fail .test-actual { color: #EE5757; }
208 | #qunit-tests .fail .test-expected { color: green; }
209 |
210 | #qunit-banner.qunit-fail { background-color: #EE5757; }
211 |
212 |
213 | /** Result */
214 |
215 | #qunit-testresult {
216 | padding: 0.5em 0.5em 0.5em 2.5em;
217 |
218 | color: #2b81af;
219 | background-color: #D2E0E6;
220 |
221 | border-bottom: 1px solid white;
222 | }
223 |
224 | /** Fixture */
225 |
226 | #qunit-fixture {
227 | position: absolute;
228 | top: -10000px;
229 | left: -10000px;
230 | width: 1000px;
231 | height: 1000px;
232 | }
233 |
--------------------------------------------------------------------------------
/libs/qunit/qunit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit v1.4.0 - A JavaScript Unit Testing Framework
3 | *
4 | * http://docs.jquery.com/QUnit
5 | *
6 | * Copyright (c) 2012 John Resig, Jörn Zaefferer
7 | * Dual licensed under the MIT (MIT-LICENSE.txt)
8 | * or GPL (GPL-LICENSE.txt) licenses.
9 | */
10 |
11 | (function(window) {
12 |
13 | var defined = {
14 | setTimeout: typeof window.setTimeout !== "undefined",
15 | sessionStorage: (function() {
16 | var x = "qunit-test-string";
17 | try {
18 | sessionStorage.setItem(x, x);
19 | sessionStorage.removeItem(x);
20 | return true;
21 | } catch(e) {
22 | return false;
23 | }
24 | }())
25 | };
26 |
27 | var testId = 0,
28 | toString = Object.prototype.toString,
29 | hasOwn = Object.prototype.hasOwnProperty;
30 |
31 | var Test = function(name, testName, expected, async, callback) {
32 | this.name = name;
33 | this.testName = testName;
34 | this.expected = expected;
35 | this.async = async;
36 | this.callback = callback;
37 | this.assertions = [];
38 | };
39 | Test.prototype = {
40 | init: function() {
41 | var tests = id("qunit-tests");
42 | if (tests) {
43 | var b = document.createElement("strong");
44 | b.innerHTML = "Running " + this.name;
45 | var li = document.createElement("li");
46 | li.appendChild( b );
47 | li.className = "running";
48 | li.id = this.id = "test-output" + testId++;
49 | tests.appendChild( li );
50 | }
51 | },
52 | setup: function() {
53 | if (this.module != config.previousModule) {
54 | if ( config.previousModule ) {
55 | runLoggingCallbacks('moduleDone', QUnit, {
56 | name: config.previousModule,
57 | failed: config.moduleStats.bad,
58 | passed: config.moduleStats.all - config.moduleStats.bad,
59 | total: config.moduleStats.all
60 | } );
61 | }
62 | config.previousModule = this.module;
63 | config.moduleStats = { all: 0, bad: 0 };
64 | runLoggingCallbacks( 'moduleStart', QUnit, {
65 | name: this.module
66 | } );
67 | } else if (config.autorun) {
68 | runLoggingCallbacks( 'moduleStart', QUnit, {
69 | name: this.module
70 | } );
71 | }
72 |
73 | config.current = this;
74 | this.testEnvironment = extend({
75 | setup: function() {},
76 | teardown: function() {}
77 | }, this.moduleTestEnvironment);
78 |
79 | runLoggingCallbacks( 'testStart', QUnit, {
80 | name: this.testName,
81 | module: this.module
82 | });
83 |
84 | // allow utility functions to access the current test environment
85 | // TODO why??
86 | QUnit.current_testEnvironment = this.testEnvironment;
87 |
88 | if ( !config.pollution ) {
89 | saveGlobal();
90 | }
91 | if ( config.notrycatch ) {
92 | this.testEnvironment.setup.call(this.testEnvironment);
93 | return;
94 | }
95 | try {
96 | this.testEnvironment.setup.call(this.testEnvironment);
97 | } catch(e) {
98 | QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
99 | }
100 | },
101 | run: function() {
102 | config.current = this;
103 | if ( this.async ) {
104 | QUnit.stop();
105 | }
106 |
107 | if ( config.notrycatch ) {
108 | this.callback.call(this.testEnvironment);
109 | return;
110 | }
111 | try {
112 | this.callback.call(this.testEnvironment);
113 | } catch(e) {
114 | QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) );
115 | // else next test will carry the responsibility
116 | saveGlobal();
117 |
118 | // Restart the tests if they're blocking
119 | if ( config.blocking ) {
120 | QUnit.start();
121 | }
122 | }
123 | },
124 | teardown: function() {
125 | config.current = this;
126 | if ( config.notrycatch ) {
127 | this.testEnvironment.teardown.call(this.testEnvironment);
128 | return;
129 | } else {
130 | try {
131 | this.testEnvironment.teardown.call(this.testEnvironment);
132 | } catch(e) {
133 | QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
134 | }
135 | }
136 | checkPollution();
137 | },
138 | finish: function() {
139 | config.current = this;
140 | if ( this.expected != null && this.expected != this.assertions.length ) {
141 | QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
142 | } else if ( this.expected == null && !this.assertions.length ) {
143 | QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions." );
144 | }
145 |
146 | var good = 0, bad = 0,
147 | li, i,
148 | tests = id("qunit-tests");
149 |
150 | config.stats.all += this.assertions.length;
151 | config.moduleStats.all += this.assertions.length;
152 |
153 | if ( tests ) {
154 | var ol = document.createElement("ol");
155 |
156 | for ( i = 0; i < this.assertions.length; i++ ) {
157 | var assertion = this.assertions[i];
158 |
159 | li = document.createElement("li");
160 | li.className = assertion.result ? "pass" : "fail";
161 | li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
162 | ol.appendChild( li );
163 |
164 | if ( assertion.result ) {
165 | good++;
166 | } else {
167 | bad++;
168 | config.stats.bad++;
169 | config.moduleStats.bad++;
170 | }
171 | }
172 |
173 | // store result when possible
174 | if ( QUnit.config.reorder && defined.sessionStorage ) {
175 | if (bad) {
176 | sessionStorage.setItem("qunit-test-" + this.module + "-" + this.testName, bad);
177 | } else {
178 | sessionStorage.removeItem("qunit-test-" + this.module + "-" + this.testName);
179 | }
180 | }
181 |
182 | if (bad === 0) {
183 | ol.style.display = "none";
184 | }
185 |
186 | var b = document.createElement("strong");
187 | b.innerHTML = this.name + "