├── .gitignore ├── LICENSE-GPL3.txt ├── LICENSE-MIT.txt ├── changelog.txt ├── dist ├── test │ ├── arrayToCsv.js │ ├── csvToArray.js │ ├── csvToObject.js │ ├── lib │ │ ├── qunit-1.13.0.css │ │ └── qunit-1.13.0.js │ ├── objectToCsv.js │ └── tests.html └── ucsv-1.2.0.min.js ├── docs ├── api.js ├── assets │ ├── css │ │ ├── external-small.png │ │ ├── logo.png │ │ └── main.css │ ├── favicon.png │ ├── img │ │ └── spinner.gif │ ├── index.html │ ├── js │ │ ├── api-filter.js │ │ ├── api-list.js │ │ ├── api-search.js │ │ ├── apidocs.js │ │ └── yui-prettify.js │ └── vendor │ │ └── prettify │ │ ├── CHANGES.html │ │ ├── COPYING │ │ ├── README.html │ │ ├── prettify-min.css │ │ └── prettify-min.js ├── classes │ ├── CSV.html │ └── index.html ├── data.json ├── files │ ├── index.html │ ├── source_core.js.html │ └── source_intro.js.html ├── index.html └── modules │ └── index.html ├── gruntfile.js ├── package.json ├── readme.md ├── source ├── core.js ├── intro.js └── outro.js └── test ├── arrayToCsv.js ├── csvToArray.js ├── csvToObject.js ├── internal.js ├── lib ├── qunit-1.13.0.css └── qunit-1.13.0.js ├── objectToCsv.js └── tests.html /.gitignore: -------------------------------------------------------------------------------- 1 | junk 2 | node_modules -------------------------------------------------------------------------------- /LICENSE-GPL3.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uselesscode/ucsv/d7c653add0832633a08134e79634459a0b8bfcc3/LICENSE-GPL3.txt -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2014 Peter Johnson, http://www.UselessCode.org 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | 1.2.0 2 | --- 3 | New features and changes 4 | * New csvToObject and objectToCsv methods to read and write CSV data as an 5 | array of objects. 6 | * Converted build system from Apache Ant to Grunt. 7 | * Converted documentation from JSDoc to YUIDoc. 8 | * csvToArray now takes a configuration object as it's second parameter instead 9 | of a boolean. In this version the old semantic is still supported but 10 | deprecated and will likely be removed in the next version due to upcoming 11 | backwards compatibility breaking changes in the library. 12 | 13 | Bug fixes 14 | * If an undefined value is in the input to arrayToCsv it will now be considered 15 | an empty field. 16 | * When reading CSV files unquoted numbers are treated as numbers even with 17 | leading or trailing whitespace. 18 | 19 | 1.1.0 20 | --- 21 | * Added support for use as a CommonJS module. This enables using UCSV as a 22 | library in Mozilla (Jetpack) Add-ons. It should also allow use in Node.js 23 | environments. Moved the strict mode declaration into the closure and cleaned 24 | up some other formatting to make JSLint happy. 25 | 26 | 1.0.3 27 | --- 28 | * Bug fix in arrayToCsv. arrayToCsv now wraps lines containing newline 29 | characters with double-quotes as was originally intended. Thanks goes to Colin 30 | Keenan for discovering and reporting this bug. (http://code.google.com/p/rentap/) 31 | 32 | 1.0.2 33 | --- 34 | * csvToArray now returns empty fields as nulls instead of empty strings as 35 | suggested by Leon Bambrick (http://secretGeek.net). 36 | * csvToArray now converts non-quoted integers and floats to the appropriate type 37 | instead of assuming they are strings. 38 | 39 | * Minor spelling fix. 40 | 41 | 1.0.1 42 | --- 43 | * A couple of tweaks to get JSLint passing again. 44 | * Removed the global flag from the trim function's RegExps to improve the performance. 45 | -------------------------------------------------------------------------------- /dist/test/arrayToCsv.js: -------------------------------------------------------------------------------- 1 | /*global strictEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('arrayToCsv'); 5 | 6 | test('arrayToCsv strings', function () { 7 | var csvArray = [ 8 | ['XBOX "XBONE" One', 2013], 9 | ['Nintendo 64, AKA Nintendo Ultra 64', 1996], 10 | ['Playstation\n4', 2013] 11 | ], 12 | expected = '"XBOX ""XBONE"" One",2013\n' + 13 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 14 | '"Playstation\n4",2013\n', 15 | csv = CSV.arrayToCsv(csvArray); 16 | strictEqual(csv, expected, 'Outputted correct CSV'); 17 | }); 18 | 19 | test('arrayToCsv integers', function () { 20 | var csvArray = [[1, 2, 3], [4, 5, 6]], 21 | csv = CSV.arrayToCsv(csvArray), 22 | expected = '1,2,3\n4,5,6\n'; 23 | strictEqual(csv, expected, 'Outputted correct CSV'); 24 | }); 25 | 26 | test('arrayToCsv no trim', function () { 27 | var csvArray = [['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 ']], 28 | csv = CSV.arrayToCsv(csvArray), 29 | expected = 'no need to trim," should not trim 1","should not trim 2 "," should not trim 3 "\n'; 30 | strictEqual(csv, expected); 31 | }); 32 | 33 | test('arrayToCsv nulls are empty fields', function () { 34 | var csvArray = [["Tom", null, "Harry"]], 35 | csv = CSV.arrayToCsv(csvArray), 36 | expected = 'Tom,,Harry\n'; 37 | strictEqual(csv, expected); 38 | }); 39 | 40 | test('arrayToCsv undefined values are empty fields', function () { 41 | var csvArray = [["Tom", undefined, "Harry"]], 42 | csv = CSV.arrayToCsv(csvArray), 43 | expected = 'Tom,,Harry\n'; 44 | strictEqual(csv, expected); 45 | }); 46 | 47 | test('arrayToCsv integers and quoted integers', function () { 48 | var csvArray = [[1, 2, "3"]], 49 | csv = CSV.arrayToCsv(csvArray), 50 | expected = '1,2,"3"\n'; 51 | strictEqual(csv, expected); 52 | }); 53 | 54 | test('arrayToCsv floats and quoted floats', function () { 55 | var csvArray = [[1.5, 2.2, "3.14"]], 56 | csv = CSV.arrayToCsv(csvArray), 57 | expected = '1.5,2.2,"3.14"\n'; 58 | strictEqual(csv, expected); 59 | }); 60 | 61 | test('arrayToCsv empty strings are empty strings', function () { 62 | var csvArray = [["a", "", "b"]], 63 | csv = CSV.arrayToCsv(csvArray), 64 | expected = 'a,"",b\n'; 65 | strictEqual(csv, expected); 66 | }); 67 | 68 | test('arrayToCsv newline in string', function () { 69 | var csvArray = [["a", "b\nc", "d"]], 70 | csv = CSV.arrayToCsv(csvArray), 71 | expected = 'a,"b\nc",d\n'; 72 | strictEqual(csv, expected); 73 | }); 74 | }()); 75 | -------------------------------------------------------------------------------- /dist/test/csvToArray.js: -------------------------------------------------------------------------------- 1 | /*global deepEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('csvToArray'); 5 | 6 | test('csvToArray strings', function () { 7 | var csv = '"XBOX ""XBONE"" One",2013\n' + 8 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 9 | '"Playstation\n4",2013\n', 10 | expected = [ 11 | ['XBOX "XBONE" One', 2013], 12 | ['Nintendo 64, AKA Nintendo Ultra 64', 1996], 13 | ['Playstation\n4', 2013] 14 | ], 15 | result = CSV.csvToArray(csv); 16 | deepEqual(result, expected); 17 | }); 18 | 19 | test('csvToArray integers', function () { 20 | var csv = '1,2,3\n4,5,6', 21 | expected = [ 22 | [1, 2, 3], 23 | [4, 5, 6] 24 | ], 25 | result = CSV.csvToArray(csv); 26 | 27 | deepEqual(result, expected); 28 | }); 29 | 30 | test('csvToArray no config', function () { 31 | var csv = 'no need to trim, should not trim 1,should not trim 2 , should not trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 32 | expected = [ 33 | ['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 '], 34 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 35 | ], 36 | result = CSV.csvToArray(csv); 37 | 38 | deepEqual(result, expected); 39 | }); 40 | 41 | test('csvToArray integers', function () { 42 | var csv = '1,2,3\n4,5,6', 43 | expected = [ 44 | [1, 2, 3], 45 | [4, 5, 6] 46 | ], 47 | result = CSV.csvToArray(csv); 48 | 49 | deepEqual(result, expected); 50 | }); 51 | 52 | test('csvToArray integers with trailing newline', function () { 53 | var csv = '1,2,3\n4,5,6\n', 54 | expected = [ 55 | [1, 2, 3], 56 | [4, 5, 6] 57 | ], 58 | result = CSV.csvToArray(csv); 59 | 60 | deepEqual(result, expected); 61 | }); 62 | 63 | test('csvToArray config === false', function () { 64 | var csv = 'no need to trim, should not trim 1,should not trim 2 , should not trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 65 | expected = [ 66 | ['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 '], 67 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 68 | ], 69 | result = CSV.csvToArray(csv, false); 70 | deepEqual(result, expected); 71 | }); 72 | 73 | test('csvToArray config === true (legacy trim)', function () { 74 | var csv = 'no need to trim, should trim 1,should trim 2 , should trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 75 | expected = [ 76 | ['no need to trim', 'should trim 1', 'should trim 2', 'should trim 3'], 77 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 78 | ], 79 | result = CSV.csvToArray(csv, true); 80 | deepEqual(result, expected); 81 | }); 82 | 83 | test('csvToArray config trim', function () { 84 | var csv = 'no need to trim, should trim 1,should trim 2 , should trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 85 | expected = [ 86 | ['no need to trim', 'should trim 1', 'should trim 2', 'should trim 3'], 87 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 88 | ], 89 | result = CSV.csvToArray(csv, {trim: true}); 90 | deepEqual(result, expected); 91 | }); 92 | 93 | test('csvToArray empty fields are null', function () { 94 | var csv = 'Billy West, Fry\nDavid X. Cohen,\nJohn Di Maggio,Bender', 95 | expected = [ 96 | ['Billy West', 'Fry'], 97 | ['David X. Cohen', null], 98 | ['John Di Maggio', 'Bender'] 99 | ], 100 | result = CSV.csvToArray(csv, true); 101 | 102 | deepEqual(result, expected); 103 | }); 104 | 105 | test('csvToArray integers and quoted integers', function () { 106 | var csv = '1,2,"3"', 107 | expected = [ 108 | [1, 2, '3'] 109 | ], 110 | result = CSV.csvToArray(csv, true); 111 | deepEqual(result, expected); 112 | }); 113 | 114 | test('csvToArray floats and quoted floats', function () { 115 | var csv = '1.5,2.2,"3.14"', 116 | expected = [ 117 | [1.5, 2.2, '3.14'] 118 | ], 119 | result = CSV.csvToArray(csv, true); 120 | 121 | deepEqual(result, expected); 122 | }); 123 | 124 | test('csvToArray numbers are interpreted as numbers even when not trimming fields', function () { 125 | var csv = ' 1 , 2, 3.14', 126 | expected = [ 127 | [1, 2, 3.14] 128 | ], 129 | result = CSV.csvToArray(csv, true); 130 | ok(Array.isArray(result), 'Result is an array'); 131 | deepEqual(result, expected); 132 | }); 133 | 134 | test('csvToArray newline in string', function () { 135 | var csv = 'a,"b\nc",d', 136 | expected = [ 137 | ['a', 'b\nc', 'd'] 138 | ], 139 | result = CSV.csvToArray(csv, true); 140 | deepEqual(result, expected); 141 | }); 142 | }()); 143 | -------------------------------------------------------------------------------- /dist/test/csvToObject.js: -------------------------------------------------------------------------------- 1 | /*global deepEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('csvToObject'); 5 | // All the actual parsing is done by csvToArray, so these tests do not thoroughly cover all aspects 6 | // of the parsing, only things particular to csvToObject since the other details of parsing are already 7 | // tested in the tests for csvToArray. 8 | 9 | test('csvToObject explicit headings, no trim', function () { 10 | var headings = [' console ', 'introduced'], 11 | csv = 'XBOX , 2001\n' + 12 | 'Nintendo 64,1996\n' + 13 | ' Playstation,1994\n', 14 | expected = [ 15 | { 16 | ' console ': 'XBOX ', 17 | 'introduced': 2001, 18 | }, 19 | { 20 | ' console ': 'Nintendo 64', 21 | 'introduced': 1996 22 | }, 23 | { 24 | ' console ': ' Playstation', 25 | 'introduced': 1994 26 | } 27 | ], 28 | result = CSV.csvToObject(csv, {columns: headings}); 29 | 30 | deepEqual(result, expected); 31 | }); 32 | 33 | test('csvToObject implicit headings, no trim', function () { 34 | var csv = ' console ,introduced\n' + 35 | 'XBOX , 2001\n' + 36 | 'Nintendo 64,1996\n' + 37 | ' Playstation,1994\n', 38 | expected = [ 39 | { 40 | ' console ': 'XBOX ', 41 | 'introduced': 2001, 42 | }, 43 | { 44 | ' console ': 'Nintendo 64', 45 | 'introduced': 1996 46 | }, 47 | { 48 | ' console ': ' Playstation', 49 | 'introduced': 1994 50 | } 51 | ], 52 | result = CSV.csvToObject(csv); 53 | 54 | deepEqual(result, expected); 55 | }); 56 | 57 | test('csvToObject explicit headings with trim', function () { 58 | var headings = [' console ', 'introduced'], 59 | csv = 'XBOX , 2001\n' + 60 | 'Nintendo 64,1996\n' + 61 | ' Playstation,1994\n', 62 | expected = [ 63 | { 64 | ' console ': 'XBOX', 65 | 'introduced': 2001, 66 | }, 67 | { 68 | ' console ': 'Nintendo 64', 69 | 'introduced': 1996 70 | }, 71 | { 72 | ' console ': 'Playstation', 73 | 'introduced': 1994 74 | } 75 | ], 76 | result = CSV.csvToObject(csv, {columns: headings, trim: true}); 77 | 78 | deepEqual(result, expected); 79 | }); 80 | 81 | test('csvToObject implicit headings', function () { 82 | var csv = ' console , introduced\n' + 83 | 'XBOX , 2001\n' + 84 | 'Nintendo 64,1996\n' + 85 | ' Playstation,1994\n', 86 | expected = [ 87 | { 88 | 'console': 'XBOX', 89 | 'introduced': 2001, 90 | }, 91 | { 92 | 'console': 'Nintendo 64', 93 | 'introduced': 1996 94 | }, 95 | { 96 | 'console': 'Playstation', 97 | 'introduced': 1994 98 | } 99 | ], 100 | result = CSV.csvToObject(csv, {trim: true}); 101 | 102 | deepEqual(result, expected); 103 | }); 104 | }()); 105 | -------------------------------------------------------------------------------- /dist/test/lib/qunit-1.13.0.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * QUnit 1.13.0 3 | * http://qunitjs.com/ 4 | * 5 | * Copyright 2013 jQuery Foundation and other contributors 6 | * Released under the MIT license 7 | * http://jquery.org/license 8 | * 9 | * Date: 2014-01-04T17:09Z 10 | */ 11 | 12 | /** Font Family and Sizes */ 13 | 14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 16 | } 17 | 18 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 19 | #qunit-tests { font-size: smaller; } 20 | 21 | 22 | /** Resets */ 23 | 24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | 30 | /** Header */ 31 | 32 | #qunit-header { 33 | padding: 0.5em 0 0.5em 1em; 34 | 35 | color: #8699a4; 36 | background-color: #0d3349; 37 | 38 | font-size: 1.5em; 39 | line-height: 1em; 40 | font-weight: normal; 41 | 42 | border-radius: 5px 5px 0 0; 43 | -moz-border-radius: 5px 5px 0 0; 44 | -webkit-border-top-right-radius: 5px; 45 | -webkit-border-top-left-radius: 5px; 46 | } 47 | 48 | #qunit-header a { 49 | text-decoration: none; 50 | color: #c2ccd1; 51 | } 52 | 53 | #qunit-header a:hover, 54 | #qunit-header a:focus { 55 | color: #fff; 56 | } 57 | 58 | #qunit-testrunner-toolbar label { 59 | display: inline-block; 60 | padding: 0 .5em 0 .1em; 61 | } 62 | 63 | #qunit-banner { 64 | height: 5px; 65 | } 66 | 67 | #qunit-testrunner-toolbar { 68 | padding: 0.5em 0 0.5em 2em; 69 | color: #5E740B; 70 | background-color: #eee; 71 | overflow: hidden; 72 | } 73 | 74 | #qunit-userAgent { 75 | padding: 0.5em 0 0.5em 2.5em; 76 | background-color: #2b81af; 77 | color: #fff; 78 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 79 | } 80 | 81 | #qunit-modulefilter-container { 82 | float: right; 83 | } 84 | 85 | /** Tests: Pass/Fail */ 86 | 87 | #qunit-tests { 88 | list-style-position: inside; 89 | } 90 | 91 | #qunit-tests li { 92 | padding: 0.4em 0.5em 0.4em 2.5em; 93 | border-bottom: 1px solid #fff; 94 | list-style-position: inside; 95 | } 96 | 97 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 98 | display: none; 99 | } 100 | 101 | #qunit-tests li strong { 102 | cursor: pointer; 103 | } 104 | 105 | #qunit-tests li a { 106 | padding: 0.5em; 107 | color: #c2ccd1; 108 | text-decoration: none; 109 | } 110 | #qunit-tests li a:hover, 111 | #qunit-tests li a:focus { 112 | color: #000; 113 | } 114 | 115 | #qunit-tests li .runtime { 116 | float: right; 117 | font-size: smaller; 118 | } 119 | 120 | .qunit-assert-list { 121 | margin-top: 0.5em; 122 | padding: 0.5em; 123 | 124 | background-color: #fff; 125 | 126 | border-radius: 5px; 127 | -moz-border-radius: 5px; 128 | -webkit-border-radius: 5px; 129 | } 130 | 131 | .qunit-collapsed { 132 | display: none; 133 | } 134 | 135 | #qunit-tests table { 136 | border-collapse: collapse; 137 | margin-top: .2em; 138 | } 139 | 140 | #qunit-tests th { 141 | text-align: right; 142 | vertical-align: top; 143 | padding: 0 .5em 0 0; 144 | } 145 | 146 | #qunit-tests td { 147 | vertical-align: top; 148 | } 149 | 150 | #qunit-tests pre { 151 | margin: 0; 152 | white-space: pre-wrap; 153 | word-wrap: break-word; 154 | } 155 | 156 | #qunit-tests del { 157 | background-color: #e0f2be; 158 | color: #374e0c; 159 | text-decoration: none; 160 | } 161 | 162 | #qunit-tests ins { 163 | background-color: #ffcaca; 164 | color: #500; 165 | text-decoration: none; 166 | } 167 | 168 | /*** Test Counts */ 169 | 170 | #qunit-tests b.counts { color: black; } 171 | #qunit-tests b.passed { color: #5E740B; } 172 | #qunit-tests b.failed { color: #710909; } 173 | 174 | #qunit-tests li li { 175 | padding: 5px; 176 | background-color: #fff; 177 | border-bottom: none; 178 | list-style-position: inside; 179 | } 180 | 181 | /*** Passing Styles */ 182 | 183 | #qunit-tests li li.pass { 184 | color: #3c510c; 185 | background-color: #fff; 186 | border-left: 10px solid #C6E746; 187 | } 188 | 189 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 190 | #qunit-tests .pass .test-name { color: #366097; } 191 | 192 | #qunit-tests .pass .test-actual, 193 | #qunit-tests .pass .test-expected { color: #999999; } 194 | 195 | #qunit-banner.qunit-pass { background-color: #C6E746; } 196 | 197 | /*** Failing Styles */ 198 | 199 | #qunit-tests li li.fail { 200 | color: #710909; 201 | background-color: #fff; 202 | border-left: 10px solid #EE5757; 203 | white-space: pre; 204 | } 205 | 206 | #qunit-tests > li:last-child { 207 | border-radius: 0 0 5px 5px; 208 | -moz-border-radius: 0 0 5px 5px; 209 | -webkit-border-bottom-right-radius: 5px; 210 | -webkit-border-bottom-left-radius: 5px; 211 | } 212 | 213 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 214 | #qunit-tests .fail .test-name, 215 | #qunit-tests .fail .module-name { color: #000000; } 216 | 217 | #qunit-tests .fail .test-actual { color: #EE5757; } 218 | #qunit-tests .fail .test-expected { color: green; } 219 | 220 | #qunit-banner.qunit-fail { background-color: #EE5757; } 221 | 222 | 223 | /** Result */ 224 | 225 | #qunit-testresult { 226 | padding: 0.5em 0.5em 0.5em 2.5em; 227 | 228 | color: #2b81af; 229 | background-color: #D2E0E6; 230 | 231 | border-bottom: 1px solid white; 232 | } 233 | #qunit-testresult .module-name { 234 | font-weight: bold; 235 | } 236 | 237 | /** Fixture */ 238 | 239 | #qunit-fixture { 240 | position: absolute; 241 | top: -10000px; 242 | left: -10000px; 243 | width: 1000px; 244 | height: 1000px; 245 | } 246 | -------------------------------------------------------------------------------- /dist/test/objectToCsv.js: -------------------------------------------------------------------------------- 1 | /*global strictEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('objectToCsv'); 5 | 6 | test('objectToCsv explicit headings', function () { 7 | var headings = ['console', 'introduced'], 8 | objs = [ 9 | { 10 | 'console': 'XBOX', 11 | 'introduced': 2001, 12 | }, 13 | { 14 | 'console': 'Nintendo 64', 15 | 'introduced': 1996 16 | }, 17 | { 18 | 'console': 'Playstation', 19 | 'introduced': 1994 20 | } 21 | ], 22 | expected = 'console,introduced\n' + 23 | 'XBOX,2001\n' + 24 | 'Nintendo 64,1996\n' + 25 | 'Playstation,1994\n', 26 | result = CSV.objectToCsv(objs, {columns: headings}); 27 | 28 | strictEqual(result, expected); 29 | }); 30 | 31 | test('objectToCsv implicit headings', function () { 32 | var objs = [ 33 | { 34 | 'console': 'XBOX', 35 | 'introduced': 2001, 36 | }, 37 | { 38 | 'console': 'Nintendo 64', 39 | 'introduced': 1996 40 | }, 41 | { 42 | 'console': 'Playstation', 43 | 'introduced': 1994 44 | } 45 | ], 46 | expected = 'console,introduced\n' + 47 | 'XBOX,2001\n' + 48 | 'Nintendo 64,1996\n' + 49 | 'Playstation,1994\n', 50 | result = CSV.objectToCsv(objs); 51 | 52 | strictEqual(result, expected); 53 | }); 54 | 55 | test('objectToCsv implicit headings, missing and extra fields', function () { 56 | var objs = [ 57 | { 58 | 'console': 'XBOX', 59 | 'introduced': 2001, 60 | }, 61 | { 62 | 'console': 'Nintendo 64', 63 | 'discontinued': 2003 64 | }, 65 | { 66 | 'console': 'Playstation', 67 | 'introduced': 1994 68 | } 69 | ], 70 | expected = 'console,introduced,discontinued\n' + 71 | 'XBOX,2001,\n' + 72 | 'Nintendo 64,,2003\n' + 73 | 'Playstation,1994,\n', 74 | result = CSV.objectToCsv(objs); 75 | 76 | strictEqual(result, expected); 77 | }); 78 | 79 | test('objectToCsv explicit headings, missing and extra fields', function () { 80 | var headings = ['console', 'introduced'], 81 | objs = [ 82 | { 83 | 'console': 'XBOX', 84 | 'introduced': 2001, 85 | }, 86 | { 87 | 'console': 'Nintendo 64', 88 | 'discontinued': 2003 89 | }, 90 | { 91 | 'console': 'Playstation', 92 | 'introduced': 1994 93 | } 94 | ], 95 | expected = 'console,introduced\n' + 96 | 'XBOX,2001\n' + 97 | 'Nintendo 64,\n' + 98 | 'Playstation,1994\n', 99 | result = CSV.objectToCsv(objs, {columns: headings}); 100 | 101 | strictEqual(result, expected); 102 | }); 103 | 104 | test('objectToCsv with includeColumns = true', function () { 105 | var headings = ['console', 'introduced'], 106 | objs = [ 107 | { 108 | 'console': 'XBOX', 109 | 'introduced': 2001, 110 | }, 111 | { 112 | 'console': 'Nintendo 64', 113 | 'introduced': 1996 114 | }, 115 | { 116 | 'console': 'Playstation', 117 | 'introduced': 1994 118 | } 119 | ], 120 | expected = 'console,introduced\n' + 121 | 'XBOX,2001\n' + 122 | 'Nintendo 64,1996\n' + 123 | 'Playstation,1994\n', 124 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: true}); 125 | 126 | strictEqual(result, expected); 127 | }); 128 | 129 | test('objectToCsv with includeColumns = false', function () { 130 | var headings = ['console', 'introduced'], 131 | objs = [ 132 | { 133 | 'console': 'XBOX', 134 | 'introduced': 2001, 135 | }, 136 | { 137 | 'console': 'Nintendo 64', 138 | 'introduced': 1996 139 | }, 140 | { 141 | 'console': 'Playstation', 142 | 'introduced': 1994 143 | } 144 | ], 145 | expected = 'XBOX,2001\n' + 146 | 'Nintendo 64,1996\n' + 147 | 'Playstation,1994\n', 148 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: false}); 149 | 150 | strictEqual(result, expected); 151 | }); 152 | 153 | test('objectToCsv with commas double quotes and newlines', function () { 154 | var headings = ['console', 'introduced'], 155 | objs = [ 156 | { 157 | 'console': 'XBOX "XBONE" One', 158 | 'introduced': 2013, 159 | }, 160 | { 161 | 'console': 'Nintendo 64, AKA Nintendo Ultra 64', 162 | 'introduced': 1996 163 | }, 164 | { 165 | 'console': 'Playstation\n4', 166 | 'introduced': 2013 167 | } 168 | ], 169 | expected = '"XBOX ""XBONE"" One",2013\n' + 170 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 171 | '"Playstation\n4",2013\n', 172 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: false}); 173 | 174 | strictEqual(result, expected); 175 | }); 176 | }()); 177 | -------------------------------------------------------------------------------- /dist/test/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Example 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /dist/ucsv-1.2.0.min.js: -------------------------------------------------------------------------------- 1 | /*! ucsv v1.2.0 2014-04-09 2 | * Copyright 2014 Peter Johnson 3 | * Licensed MIT, GPL-3.0 4 | * https://github.com/uselesscode/ucsv 5 | */ 6 | var CSV=function(){"use strict";var a=/^\d+$/,b=/^\d*\.\d+$|^\d+\.\d*$/,c=/^\s|\s$|,|"|\n/,d=function(){return String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^\s*/,"").replace(/\s*$/,"")}}(),e=function(a){return"[object Number]"===Object.prototype.toString.apply(a)},f=function(a){return"[object String]"===Object.prototype.toString.apply(a)},g=function(a){return"\n"!==a.charAt(a.length-1)?a:a.substring(0,a.length-1)},h=function(d){return f(d)?(d=d.replace(/"/g,'""'),c.test(d)||a.test(d)||b.test(d)?d='"'+d+'"':""===d&&(d='""')):d=e(d)?d.toString(10):null===d||void 0===d?"":d.toString(),d},i={arrayToCsv:function(a){var b,c,d,e,f="";for(d=0;dd;d+=1)b[c[d]]=a[d];return b})},objectToCsv:function(a,b){b=void 0!==b?b:{};var c=b.columns,d=b.includeColumns,e="",f="",g=function(b){var d,e,f,g="",i=a.length,j=c.length;for(e=0;i>e;e+=1){for(b=a[e],f=0;j>f;f+=1)d=c[f],g+=h(b[d]),g+=j-1>f?",":"";g+="\n"}return g},i=function(){var b,d,e,f,g,i,j,k=[],l=a.length,m=[];for(g=0;l>g;g+=1){e=a[g],j=[];for(f in e)e.hasOwnProperty(f)&&(i=k.indexOf(f),-1===i&&(i=k.push(f),i-=1),j[i]=h(e[f]));0===g&&(b=j.length),m.push(j)}return d=k.length,b!==d&&m.forEach(function(a){a.length=d}),c=k,m.map(function(a){return a.join(",")}).join("\n")+"\n"};return d=void 0===d?!0:!!d,e=void 0!==c?g():i(),d&&(c.forEach(function(a){f+=h(a)+","}),f=f.substring(0,f.length-1),e=f+"\n"+e),e}};return"object"==typeof exports&&(exports.arrayToCsv=i.arrayToCsv,exports.csvToArray=i.csvToArray,exports.objectToCsv=i.objectToCsv,exports.csvToObject=i.csvToObject),i}(); 7 | -------------------------------------------------------------------------------- /docs/api.js: -------------------------------------------------------------------------------- 1 | YUI.add("yuidoc-meta", function(Y) { 2 | Y.YUIDoc = { meta: { 3 | "classes": [ 4 | "CSV" 5 | ], 6 | "modules": [], 7 | "allModules": [] 8 | } }; 9 | }); -------------------------------------------------------------------------------- /docs/assets/css/external-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uselesscode/ucsv/d7c653add0832633a08134e79634459a0b8bfcc3/docs/assets/css/external-small.png -------------------------------------------------------------------------------- /docs/assets/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uselesscode/ucsv/d7c653add0832633a08134e79634459a0b8bfcc3/docs/assets/css/logo.png -------------------------------------------------------------------------------- /docs/assets/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | Font sizes for all selectors other than the body are given in percentages, 3 | with 100% equal to 13px. To calculate a font size percentage, multiply the 4 | desired size in pixels by 7.6923076923. 5 | 6 | Here's a quick lookup table: 7 | 8 | 10px - 76.923% 9 | 11px - 84.615% 10 | 12px - 92.308% 11 | 13px - 100% 12 | 14px - 107.692% 13 | 15px - 115.385% 14 | 16px - 123.077% 15 | 17px - 130.769% 16 | 18px - 138.462% 17 | 19px - 146.154% 18 | 20px - 153.846% 19 | */ 20 | 21 | html { 22 | background: #fff; 23 | color: #333; 24 | overflow-y: scroll; 25 | } 26 | 27 | body { 28 | /*font: 13px/1.4 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', 'Bitstream Vera Sans', 'Helvetica', 'Arial', sans-serif;*/ 29 | font: 13px/1.4 'Helvetica', 'Arial', sans-serif; 30 | margin: 0; 31 | padding: 0; 32 | } 33 | 34 | /* -- Links ----------------------------------------------------------------- */ 35 | a { 36 | color: #356de4; 37 | text-decoration: none; 38 | } 39 | 40 | .hidden { 41 | display: none; 42 | } 43 | 44 | a:hover { text-decoration: underline; } 45 | 46 | /* "Jump to Table of Contents" link is shown to assistive tools, but hidden from 47 | sight until it's focused. */ 48 | .jump { 49 | position: absolute; 50 | padding: 3px 6px; 51 | left: -99999px; 52 | top: 0; 53 | } 54 | 55 | .jump:focus { left: 40%; } 56 | 57 | /* -- Paragraphs ------------------------------------------------------------ */ 58 | p { margin: 1.3em 0; } 59 | dd p, td p { margin-bottom: 0; } 60 | dd p:first-child, td p:first-child { margin-top: 0; } 61 | 62 | /* -- Headings -------------------------------------------------------------- */ 63 | h1, h2, h3, h4, h5, h6 { 64 | color: #D98527;/*was #f80*/ 65 | font-family: 'Trebuchet MS', sans-serif; 66 | font-weight: bold; 67 | line-height: 1.1; 68 | margin: 1.1em 0 0.5em; 69 | } 70 | 71 | h1 { 72 | font-size: 184.6%; 73 | color: #30418C; 74 | margin: 0.75em 0 0.5em; 75 | } 76 | 77 | h2 { 78 | font-size: 153.846%; 79 | color: #E48A2B; 80 | } 81 | 82 | h3 { font-size: 138.462%; } 83 | 84 | h4 { 85 | border-bottom: 1px solid #DBDFEA; 86 | color: #E48A2B; 87 | font-size: 115.385%; 88 | font-weight: normal; 89 | padding-bottom: 2px; 90 | } 91 | 92 | h5, h6 { font-size: 107.692%; } 93 | 94 | /* -- Code and examples ----------------------------------------------------- */ 95 | code, kbd, pre, samp { 96 | font-family: Menlo, Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; 97 | font-size: 92.308%; 98 | line-height: 1.35; 99 | } 100 | 101 | p code, p kbd, p samp, li code { 102 | background: #FCFBFA; 103 | border: 1px solid #EFEEED; 104 | padding: 0 3px; 105 | } 106 | 107 | a code, a kbd, a samp, 108 | pre code, pre kbd, pre samp, 109 | table code, table kbd, table samp, 110 | .intro code, .intro kbd, .intro samp, 111 | .toc code, .toc kbd, .toc samp { 112 | background: none; 113 | border: none; 114 | padding: 0; 115 | } 116 | 117 | pre.code, pre.terminal, pre.cmd { 118 | overflow-x: auto; 119 | *overflow-x: scroll; 120 | padding: 0.3em 0.6em; 121 | } 122 | 123 | pre.code { 124 | background: #FCFBFA; 125 | border: 1px solid #EFEEED; 126 | border-left-width: 5px; 127 | } 128 | 129 | pre.terminal, pre.cmd { 130 | background: #F0EFFC; 131 | border: 1px solid #D0CBFB; 132 | border-left: 5px solid #D0CBFB; 133 | } 134 | 135 | /* Don't reduce the font size of // elements inside
136 |    blocks. */
137 | pre code, pre kbd, pre samp { font-size: 100%; }
138 | 
139 | /* Used to denote text that shouldn't be selectable, such as line numbers or
140 |    shell prompts. Guess which browser this doesn't work in. */
141 | .noselect {
142 |     -moz-user-select: -moz-none;
143 |     -khtml-user-select: none;
144 |     -webkit-user-select: none;
145 |     -o-user-select: none;
146 |     user-select: none;
147 | }
148 | 
149 | /* -- Lists ----------------------------------------------------------------- */
150 | dd { margin: 0.2em 0 0.7em 1em; }
151 | dl { margin: 1em 0; }
152 | dt { font-weight: bold; }
153 | 
154 | /* -- Tables ---------------------------------------------------------------- */
155 | caption, th { text-align: left; }
156 | 
157 | table {
158 |     border-collapse: collapse;
159 |     width: 100%;
160 | }
161 | 
162 | td, th {
163 |     border: 1px solid #fff;
164 |     padding: 5px 12px;
165 |     vertical-align: top;
166 | }
167 | 
168 | td { background: #E6E9F5; }
169 | td dl { margin: 0; }
170 | td dl dl { margin: 1em 0; }
171 | td pre:first-child { margin-top: 0; }
172 | 
173 | th {
174 |     background: #D2D7E6;/*#97A0BF*/
175 |     border-bottom: none;
176 |     border-top: none;
177 |     color: #000;/*#FFF1D5*/
178 |     font-family: 'Trebuchet MS', sans-serif;
179 |     font-weight: bold;
180 |     line-height: 1.3;
181 |     white-space: nowrap;
182 | }
183 | 
184 | 
185 | /* -- Layout and Content ---------------------------------------------------- */
186 | #doc {
187 |     margin: auto;
188 |     min-width: 1024px;
189 | }
190 | 
191 | .content { padding: 0 20px 0 25px; }
192 | 
193 | .sidebar {
194 |     padding: 0 15px 0 10px;
195 | }
196 | #bd {
197 |     padding: 7px 0 130px;
198 |     position: relative;
199 |     width: 99%;
200 | }
201 | 
202 | /* -- Table of Contents ----------------------------------------------------- */
203 | 
204 | /* The #toc id refers to the single global table of contents, while the .toc
205 |    class refers to generic TOC lists that could be used throughout the page. */
206 | 
207 | .toc code, .toc kbd, .toc samp { font-size: 100%; }
208 | .toc li { font-weight: bold; }
209 | .toc li li { font-weight: normal; }
210 | 
211 | /* -- Intro and Example Boxes ----------------------------------------------- */
212 | /*
213 | .intro, .example { margin-bottom: 2em; }
214 | .example {
215 |     -moz-border-radius: 4px;
216 |     -webkit-border-radius: 4px;
217 |     border-radius: 4px;
218 |     -moz-box-shadow: 0 0 5px #bfbfbf;
219 |     -webkit-box-shadow: 0 0 5px #bfbfbf;
220 |     box-shadow: 0 0 5px #bfbfbf;
221 |     padding: 1em;
222 | }
223 | .intro {
224 |     background: none repeat scroll 0 0 #F0F1F8; border: 1px solid #D4D8EB; padding: 0 1em;
225 | }
226 | */
227 | 
228 | /* -- Other Styles ---------------------------------------------------------- */
229 | 
230 | /* These are probably YUI-specific, and should be moved out of Selleck's default
231 |    theme. */
232 | 
233 | .button {
234 |     border: 1px solid #dadada;
235 |     -moz-border-radius: 3px;
236 |     -webkit-border-radius: 3px;
237 |     border-radius: 3px;
238 |     color: #444;
239 |     display: inline-block;
240 |     font-family: Helvetica, Arial, sans-serif;
241 |     font-size: 92.308%;
242 |     font-weight: bold;
243 |     padding: 4px 13px 3px;
244 |     -moz-text-shadow: 1px 1px 0 #fff;
245 |     -webkit-text-shadow: 1px 1px 0 #fff;
246 |     text-shadow: 1px 1px 0 #fff;
247 |     white-space: nowrap;
248 | 
249 |     background: #EFEFEF; /* old browsers */
250 |     background: -moz-linear-gradient(top, #f5f5f5 0%, #efefef 50%, #e5e5e5 51%, #dfdfdf 100%); /* firefox */
251 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f5f5f5), color-stop(50%,#efefef), color-stop(51%,#e5e5e5), color-stop(100%,#dfdfdf)); /* webkit */
252 |     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#dfdfdf',GradientType=0 ); /* ie */
253 | }
254 | 
255 | .button:hover {
256 |     border-color: #466899;
257 |     color: #fff;
258 |     text-decoration: none;
259 |     -moz-text-shadow: 1px 1px 0 #222;
260 |     -webkit-text-shadow: 1px 1px 0 #222;
261 |     text-shadow: 1px 1px 0 #222;
262 | 
263 |     background: #6396D8; /* old browsers */
264 |     background: -moz-linear-gradient(top, #6396D8 0%, #5A83BC 50%, #547AB7 51%, #466899 100%); /* firefox */
265 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#6396D8), color-stop(50%,#5A83BC), color-stop(51%,#547AB7), color-stop(100%,#466899)); /* webkit */
266 |     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6396D8', endColorstr='#466899',GradientType=0 ); /* ie */
267 | }
268 | 
269 | .newwindow { text-align: center; }
270 | 
271 | .header .version em {
272 |     display: block;
273 |     text-align: right;
274 | }
275 | 
276 | 
277 | #classdocs .item {
278 |     border-bottom: 1px solid #466899;
279 |     margin: 1em 0;
280 |     padding: 1.5em;
281 | }
282 | 
283 | #classdocs .item .params p,
284 |     #classdocs .item .returns p,{
285 |     display: inline;
286 | }
287 | 
288 | #classdocs .item em code, #classdocs .item em.comment {
289 |     color: green;
290 | }
291 | 
292 | #classdocs .item em.comment a {
293 |     color: green;
294 |     text-decoration: underline;
295 | }
296 | 
297 | #classdocs .foundat {
298 |     font-size: 11px;
299 |     font-style: normal;
300 | }
301 | 
302 | .attrs .emits {
303 |     margin-left: 2em;
304 |     padding: .5em;
305 |     border-left: 1px dashed #ccc;
306 | }
307 | 
308 | abbr {
309 |     border-bottom: 1px dashed #ccc;
310 |     font-size: 80%;
311 |     cursor: help;
312 | }
313 | 
314 | .prettyprint li.L0, 
315 | .prettyprint li.L1, 
316 | .prettyprint li.L2, 
317 | .prettyprint li.L3, 
318 | .prettyprint li.L5, 
319 | .prettyprint li.L6, 
320 | .prettyprint li.L7, 
321 | .prettyprint li.L8 {
322 |     list-style: decimal;
323 | }
324 | 
325 | ul li p {
326 |     margin-top: 0;
327 | }
328 | 
329 | .method .name {
330 |     font-size: 110%;
331 | }
332 | 
333 | .apidocs .methods .extends .method,
334 | .apidocs .properties .extends .property,
335 | .apidocs .attrs .extends .attr,
336 | .apidocs .events .extends .event {
337 |     font-weight: bold;
338 | }
339 | 
340 | .apidocs .methods .extends .inherited,
341 | .apidocs .properties .extends .inherited,
342 | .apidocs .attrs .extends .inherited,
343 | .apidocs .events .extends .inherited {
344 |     font-weight: normal;
345 | }
346 | 
347 | #hd {
348 |     background: whiteSmoke;
349 |     background: -moz-linear-gradient(top,#DCDBD9 0,#F6F5F3 100%);
350 |     background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#DCDBD9),color-stop(100%,#F6F5F3));
351 |     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dcdbd9',endColorstr='#F6F5F3',GradientType=0);
352 |     border-bottom: 1px solid #DFDFDF;
353 |     padding: 0 15px 1px 20px;
354 |     margin-bottom: 15px;
355 | }
356 | 
357 | #hd img {
358 |     margin-right: 10px;
359 |     vertical-align: middle;
360 | }
361 | 
362 | 
363 | /* -- API Docs CSS ---------------------------------------------------------- */
364 | 
365 | /*
366 | This file is organized so that more generic styles are nearer the top, and more
367 | specific styles are nearer the bottom of the file. This allows us to take full
368 | advantage of the cascade to avoid redundant style rules. Please respect this
369 | convention when making changes.
370 | */
371 | 
372 | /* -- Generic TabView styles ------------------------------------------------ */
373 | 
374 | /*
375 | These styles apply to all API doc tabviews. To change styles only for a
376 | specific tabview, see the other sections below.
377 | */
378 | 
379 | .yui3-js-enabled .apidocs .tabview {
380 |     visibility: hidden; /* Hide until the TabView finishes rendering. */
381 |     _visibility: visible;
382 | }
383 | 
384 | .apidocs .tabview.yui3-tabview-content { visibility: visible; }
385 | .apidocs .tabview .yui3-tabview-panel { background: #fff; }
386 | 
387 | /* -- Generic Content Styles ------------------------------------------------ */
388 | 
389 | /* Headings */
390 | h2, h3, h4, h5, h6 {
391 |     border: none;
392 |     color: #30418C;
393 |     font-weight: bold;
394 |     text-decoration: none;
395 | }
396 | 
397 | .link-docs {
398 |     float: right;
399 |     font-size: 15px;
400 |     margin: 4px 4px 6px;
401 |     padding: 6px 30px 5px;
402 | }
403 | 
404 | .apidocs { zoom: 1; }
405 | 
406 | /* Generic box styles. */
407 | .apidocs .box {
408 |     border: 1px solid;
409 |     border-radius: 3px;
410 |     margin: 1em 0;
411 |     padding: 0 1em;
412 | }
413 | 
414 | /* A flag is a compact, capsule-like indicator of some kind. It's used to
415 |    indicate private and protected items, item return types, etc. in an
416 |    attractive and unobtrusive way. */
417 | .apidocs .flag {
418 |     background: #bababa;
419 |     border-radius: 3px;
420 |     color: #fff;
421 |     font-size: 11px;
422 |     margin: 0 0.5em;
423 |     padding: 2px 4px 1px;
424 | }
425 | 
426 | /* Class/module metadata such as "Uses", "Extends", "Defined in", etc. */
427 | .apidocs .meta {
428 |     background: #f9f9f9;
429 |     border-color: #efefef;
430 |     color: #555;
431 |     font-size: 11px;
432 |     padding: 3px 6px;
433 | }
434 | 
435 | .apidocs .meta p { margin: 0; }
436 | 
437 | /* Deprecation warning. */
438 | .apidocs .box.deprecated,
439 | .apidocs .flag.deprecated {
440 |     background: #fdac9f;
441 |     border: 1px solid #fd7775;
442 | }
443 | 
444 | .apidocs .box.deprecated p { margin: 0.5em 0; }
445 | .apidocs .flag.deprecated { color: #333; }
446 | 
447 | /* Module/Class intro description. */
448 | .apidocs .intro {
449 |     background: #f0f1f8;
450 |     border-color: #d4d8eb;
451 | }
452 | 
453 | /* Loading spinners. */
454 | #bd.loading .apidocs,
455 | #api-list.loading .yui3-tabview-panel {
456 |     background: #fff url(../img/spinner.gif) no-repeat center 70px;
457 |     min-height: 150px;
458 | }
459 | 
460 | #bd.loading .apidocs .content,
461 | #api-list.loading .yui3-tabview-panel .apis {
462 |     display: none;
463 | }
464 | 
465 | .apidocs .no-visible-items { color: #666; }
466 | 
467 | /* Generic inline list. */
468 | .apidocs ul.inline {
469 |     display: inline;
470 |     list-style: none;
471 |     margin: 0;
472 |     padding: 0;
473 | }
474 | 
475 | .apidocs ul.inline li { display: inline; }
476 | 
477 | /* Comma-separated list. */
478 | .apidocs ul.commas li:after { content: ','; }
479 | .apidocs ul.commas li:last-child:after { content: ''; }
480 | 
481 | /* Keyboard shortcuts. */
482 | kbd .cmd { font-family: Monaco, Helvetica; }
483 | 
484 | /* -- Generic Access Level styles ------------------------------------------- */
485 | .apidocs .item.protected,
486 | .apidocs .item.private,
487 | .apidocs .index-item.protected,
488 | .apidocs .index-item.deprecated,
489 | .apidocs .index-item.private {
490 |     display: none;
491 | }
492 | 
493 | .show-deprecated .item.deprecated,
494 | .show-deprecated .index-item.deprecated,
495 | .show-protected .item.protected,
496 | .show-protected .index-item.protected,
497 | .show-private .item.private,
498 | .show-private .index-item.private {
499 |     display: block;
500 | }
501 | 
502 | .hide-inherited .item.inherited,
503 | .hide-inherited .index-item.inherited {
504 |     display: none;
505 | }
506 | 
507 | /* -- Generic Item Index styles --------------------------------------------- */
508 | .apidocs .index { margin: 1.5em 0 3em; }
509 | 
510 | .apidocs .index h3 {
511 |     border-bottom: 1px solid #efefef;
512 |     color: #333;
513 |     font-size: 13px;
514 |     margin: 2em 0 0.6em;
515 |     padding-bottom: 2px;
516 | }
517 | 
518 | .apidocs .index .no-visible-items { margin-top: 2em; }
519 | 
520 | .apidocs .index-list {
521 |     border-color: #efefef;
522 |     font-size: 12px;
523 |     list-style: none;
524 |     margin: 0;
525 |     padding: 0;
526 |     -moz-column-count: 4;
527 |     -moz-column-gap: 10px;
528 |     -moz-column-width: 170px;
529 |     -ms-column-count: 4;
530 |     -ms-column-gap: 10px;
531 |     -ms-column-width: 170px;
532 |     -o-column-count: 4;
533 |     -o-column-gap: 10px;
534 |     -o-column-width: 170px;
535 |     -webkit-column-count: 4;
536 |     -webkit-column-gap: 10px;
537 |     -webkit-column-width: 170px;
538 |     column-count: 4;
539 |     column-gap: 10px;
540 |     column-width: 170px;
541 | }
542 | 
543 | .apidocs .no-columns .index-list {
544 |     -moz-column-count: 1;
545 |     -ms-column-count: 1;
546 |     -o-column-count: 1;
547 |     -webkit-column-count: 1;
548 |     column-count: 1;
549 | }
550 | 
551 | .apidocs .index-item { white-space: nowrap; }
552 | 
553 | .apidocs .index-item .flag {
554 |     background: none;
555 |     border: none;
556 |     color: #afafaf;
557 |     display: inline;
558 |     margin: 0 0 0 0.2em;
559 |     padding: 0;
560 | }
561 | 
562 | /* -- Generic API item styles ----------------------------------------------- */
563 | .apidocs .args {
564 |     display: inline;
565 |     margin: 0 0.5em;
566 | }
567 | 
568 | .apidocs .flag.chainable { background: #46ca3b; }
569 | .apidocs .flag.protected { background: #9b86fc; }
570 | .apidocs .flag.private { background: #fd6b1b; }
571 | .apidocs .flag.async { background: #356de4; }
572 | .apidocs .flag.required { background: #e60923; }
573 | 
574 | .apidocs .item {
575 |     border-bottom: 1px solid #efefef;
576 |     margin: 1.5em 0 2em;
577 |     padding-bottom: 2em;
578 | }
579 | 
580 | .apidocs .item h4,
581 | .apidocs .item h5,
582 | .apidocs .item h6 {
583 |     color: #333;
584 |     font-family: inherit;
585 |     font-size: 100%;
586 | }
587 | 
588 | .apidocs .item .description p,
589 | .apidocs .item pre.code {
590 |     margin: 1em 0 0;
591 | }
592 | 
593 | .apidocs .item .meta {
594 |     background: none;
595 |     border: none;
596 |     padding: 0;
597 | }
598 | 
599 | .apidocs .item .name {
600 |     display: inline;
601 |     font-size: 14px;
602 | }
603 | 
604 | .apidocs .item .type,
605 | .apidocs .item .type a,
606 | .apidocs .returns-inline {
607 |     color: #555;
608 | }
609 | 
610 | .apidocs .item .type,
611 | .apidocs .returns-inline {
612 |     font-size: 11px;
613 |     margin: 0 0 0 0;
614 | }
615 | 
616 | .apidocs .item .type a { border-bottom: 1px dotted #afafaf; }
617 | .apidocs .item .type a:hover { border: none; }
618 | 
619 | /* -- Item Parameter List --------------------------------------------------- */
620 | .apidocs .params-list {
621 |     list-style: square;
622 |     margin: 1em 0 0 2em;
623 |     padding: 0;
624 | }
625 | 
626 | .apidocs .param { margin-bottom: 1em; }
627 | 
628 | .apidocs .param .type,
629 | .apidocs .param .type a {
630 |     color: #666;
631 | }
632 | 
633 | .apidocs .param .type {
634 |     margin: 0 0 0 0.5em;
635 |     *margin-left: 0.5em;
636 | }
637 | 
638 | .apidocs .param-name { font-weight: bold; }
639 | 
640 | /* -- Item "Emits" block ---------------------------------------------------- */
641 | .apidocs .item .emits {
642 |     background: #f9f9f9;
643 |     border-color: #eaeaea;
644 | }
645 | 
646 | /* -- Item "Returns" block -------------------------------------------------- */
647 | .apidocs .item .returns .type,
648 | .apidocs .item .returns .type a {
649 |     font-size: 100%;
650 |     margin: 0;
651 | }
652 | 
653 | /* -- Class Constructor block ----------------------------------------------- */
654 | .apidocs .constructor .item {
655 |     border: none;
656 |     padding-bottom: 0;
657 | }
658 | 
659 | /* -- File Source View ------------------------------------------------------ */
660 | .apidocs .file pre.code,
661 | #doc .apidocs .file pre.prettyprint {
662 |     background: inherit;
663 |     border: none;
664 |     overflow: visible;
665 |     padding: 0;
666 | }
667 | 
668 | .apidocs .L0,
669 | .apidocs .L1,
670 | .apidocs .L2,
671 | .apidocs .L3,
672 | .apidocs .L4,
673 | .apidocs .L5,
674 | .apidocs .L6,
675 | .apidocs .L7,
676 | .apidocs .L8,
677 | .apidocs .L9 {
678 |     background: inherit;
679 | }
680 | 
681 | /* -- Submodule List -------------------------------------------------------- */
682 | .apidocs .module-submodule-description {
683 |     font-size: 12px;
684 |     margin: 0.3em 0 1em;
685 | }
686 | 
687 | .apidocs .module-submodule-description p:first-child { margin-top: 0; }
688 | 
689 | /* -- Sidebar TabView ------------------------------------------------------- */
690 | #api-tabview { margin-top: 0.6em; }
691 | 
692 | #api-tabview-filter,
693 | #api-tabview-panel {
694 |     border: 1px solid #dfdfdf;
695 | }
696 | 
697 | #api-tabview-filter {
698 |     border-bottom: none;
699 |     border-top: none;
700 |     padding: 0.6em 10px 0 10px;
701 | }
702 | 
703 | #api-tabview-panel { border-top: none; }
704 | #api-filter { width: 97%; }
705 | 
706 | /* -- Content TabView ------------------------------------------------------- */
707 | #classdocs .yui3-tabview-panel { border: none; }
708 | 
709 | /* -- Source File Contents -------------------------------------------------- */
710 | .prettyprint li.L0,
711 | .prettyprint li.L1,
712 | .prettyprint li.L2,
713 | .prettyprint li.L3,
714 | .prettyprint li.L5,
715 | .prettyprint li.L6,
716 | .prettyprint li.L7,
717 | .prettyprint li.L8 {
718 |     list-style: decimal;
719 | }
720 | 
721 | /* -- API options ----------------------------------------------------------- */
722 | #api-options {
723 |     font-size: 11px;
724 |     margin-top: 2.2em;
725 |     position: absolute;
726 |     right: 1.5em;
727 | }
728 | 
729 | /*#api-options label { margin-right: 0.6em; }*/
730 | 
731 | /* -- API list -------------------------------------------------------------- */
732 | #api-list {
733 |     margin-top: 1.5em;
734 |     *zoom: 1;
735 | }
736 | 
737 | .apis {
738 |     font-size: 12px;
739 |     line-height: 1.4;
740 |     list-style: none;
741 |     margin: 0;
742 |     padding: 0.5em 0 0.5em 0.4em;
743 | }
744 | 
745 | .apis a {
746 |     border: 1px solid transparent;
747 |     display: block;
748 |     margin: 0 0 0 -4px;
749 |     padding: 1px 4px 0;
750 |     text-decoration: none;
751 |     _border: none;
752 |     _display: inline;
753 | }
754 | 
755 | .apis a:hover,
756 | .apis a:focus {
757 |     background: #E8EDFC;
758 |     background: -moz-linear-gradient(top, #e8edfc 0%, #becef7 100%);
759 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#E8EDFC), color-stop(100%,#BECEF7));
760 |     border-color: #AAC0FA;
761 |     border-radius: 3px;
762 |     color: #333;
763 |     outline: none;
764 | }
765 | 
766 | .api-list-item a:hover,
767 | .api-list-item a:focus {
768 |     font-weight: bold;
769 |     text-shadow: 1px 1px 1px #fff;
770 | }
771 | 
772 | .apis .message { color: #888; }
773 | .apis .result a { padding: 3px 5px 2px; }
774 | 
775 | .apis .result .type {
776 |     right: 4px;
777 |     top: 7px;
778 | }
779 | 
780 | .api-list-item .yui3-highlight {
781 |     font-weight: bold;
782 | }
783 | 
784 | 


--------------------------------------------------------------------------------
/docs/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uselesscode/ucsv/d7c653add0832633a08134e79634459a0b8bfcc3/docs/assets/favicon.png


--------------------------------------------------------------------------------
/docs/assets/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uselesscode/ucsv/d7c653add0832633a08134e79634459a0b8bfcc3/docs/assets/img/spinner.gif


--------------------------------------------------------------------------------
/docs/assets/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Redirector
 5 |         
 6 |     
 7 |     
 8 |         Click here to redirect
 9 |     
10 | 
11 | 


--------------------------------------------------------------------------------
/docs/assets/js/api-filter.js:
--------------------------------------------------------------------------------
 1 | YUI.add('api-filter', function (Y) {
 2 | 
 3 | Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], {
 4 |     // -- Initializer ----------------------------------------------------------
 5 |     initializer: function () {
 6 |         this._bindUIACBase();
 7 |         this._syncUIACBase();
 8 |     },
 9 |     getDisplayName: function(name) {
10 | 
11 |         Y.each(Y.YUIDoc.meta.allModules, function(i) {
12 |             if (i.name === name && i.displayName) {
13 |                 name = i.displayName;
14 |             }
15 |         });
16 | 
17 |         return name;
18 |     }
19 | 
20 | }, {
21 |     // -- Attributes -----------------------------------------------------------
22 |     ATTRS: {
23 |         resultHighlighter: {
24 |             value: 'phraseMatch'
25 |         },
26 | 
27 |         // May be set to "classes" or "modules".
28 |         queryType: {
29 |             value: 'classes'
30 |         },
31 | 
32 |         source: {
33 |             valueFn: function() {
34 |                 var self = this;
35 |                 return function(q) {
36 |                     var data = Y.YUIDoc.meta[self.get('queryType')],
37 |                         out = [];
38 |                     Y.each(data, function(v) {
39 |                         if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) {
40 |                             out.push(v);
41 |                         }
42 |                     });
43 |                     return out;
44 |                 };
45 |             }
46 |         }
47 |     }
48 | });
49 | 
50 | }, '3.4.0', {requires: [
51 |     'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources'
52 | ]});
53 | 


--------------------------------------------------------------------------------
/docs/assets/js/api-list.js:
--------------------------------------------------------------------------------
  1 | YUI.add('api-list', function (Y) {
  2 | 
  3 | var Lang   = Y.Lang,
  4 |     YArray = Y.Array,
  5 | 
  6 |     APIList = Y.namespace('APIList'),
  7 | 
  8 |     classesNode    = Y.one('#api-classes'),
  9 |     inputNode      = Y.one('#api-filter'),
 10 |     modulesNode    = Y.one('#api-modules'),
 11 |     tabviewNode    = Y.one('#api-tabview'),
 12 | 
 13 |     tabs = APIList.tabs = {},
 14 | 
 15 |     filter = APIList.filter = new Y.APIFilter({
 16 |         inputNode : inputNode,
 17 |         maxResults: 1000,
 18 | 
 19 |         on: {
 20 |             results: onFilterResults
 21 |         }
 22 |     }),
 23 | 
 24 |     search = APIList.search = new Y.APISearch({
 25 |         inputNode : inputNode,
 26 |         maxResults: 100,
 27 | 
 28 |         on: {
 29 |             clear  : onSearchClear,
 30 |             results: onSearchResults
 31 |         }
 32 |     }),
 33 | 
 34 |     tabview = APIList.tabview = new Y.TabView({
 35 |         srcNode  : tabviewNode,
 36 |         panelNode: '#api-tabview-panel',
 37 |         render   : true,
 38 | 
 39 |         on: {
 40 |             selectionChange: onTabSelectionChange
 41 |         }
 42 |     }),
 43 | 
 44 |     focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, {
 45 |         circular   : true,
 46 |         descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a',
 47 |         keys       : {next: 'down:40', previous: 'down:38'}
 48 |     }).focusManager,
 49 | 
 50 |     LIST_ITEM_TEMPLATE =
 51 |         '
  • ' + 52 | '{displayName}' + 53 | '
  • '; 54 | 55 | // -- Init --------------------------------------------------------------------- 56 | 57 | // Duckpunch FocusManager's key event handling to prevent it from handling key 58 | // events when a modifier is pressed. 59 | Y.before(function (e, activeDescendant) { 60 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 61 | return new Y.Do.Prevent(); 62 | } 63 | }, focusManager, '_focusPrevious', focusManager); 64 | 65 | Y.before(function (e, activeDescendant) { 66 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 67 | return new Y.Do.Prevent(); 68 | } 69 | }, focusManager, '_focusNext', focusManager); 70 | 71 | // Create a mapping of tabs in the tabview so we can refer to them easily later. 72 | tabview.each(function (tab, index) { 73 | var name = tab.get('label').toLowerCase(); 74 | 75 | tabs[name] = { 76 | index: index, 77 | name : name, 78 | tab : tab 79 | }; 80 | }); 81 | 82 | // Switch tabs on Ctrl/Cmd-Left/Right arrows. 83 | tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); 84 | 85 | // Focus the filter input when the `/` key is pressed. 86 | Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); 87 | 88 | // Keep the Focus Manager up to date. 89 | inputNode.on('focus', function () { 90 | focusManager.set('activeDescendant', inputNode); 91 | }); 92 | 93 | // Update all tabview links to resolved URLs. 94 | tabview.get('panelNode').all('a').each(function (link) { 95 | link.setAttribute('href', link.get('href')); 96 | }); 97 | 98 | // -- Private Functions -------------------------------------------------------- 99 | function getFilterResultNode() { 100 | return filter.get('queryType') === 'classes' ? classesNode : modulesNode; 101 | } 102 | 103 | // -- Event Handlers ----------------------------------------------------------- 104 | function onFilterResults(e) { 105 | var frag = Y.one(Y.config.doc.createDocumentFragment()), 106 | resultNode = getFilterResultNode(), 107 | typePlural = filter.get('queryType'), 108 | typeSingular = typePlural === 'classes' ? 'class' : 'module'; 109 | 110 | if (e.results.length) { 111 | YArray.each(e.results, function (result) { 112 | frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { 113 | rootPath : APIList.rootPath, 114 | displayName : filter.getDisplayName(result.highlighted), 115 | name : result.text, 116 | typePlural : typePlural, 117 | typeSingular: typeSingular 118 | })); 119 | }); 120 | } else { 121 | frag.append( 122 | '
  • ' + 123 | 'No ' + typePlural + ' found.' + 124 | '
  • ' 125 | ); 126 | } 127 | 128 | resultNode.empty(true); 129 | resultNode.append(frag); 130 | 131 | focusManager.refresh(); 132 | } 133 | 134 | function onSearchClear(e) { 135 | 136 | focusManager.refresh(); 137 | } 138 | 139 | function onSearchKey(e) { 140 | var target = e.target; 141 | 142 | if (target.test('input,select,textarea') 143 | || target.get('isContentEditable')) { 144 | return; 145 | } 146 | 147 | e.preventDefault(); 148 | 149 | inputNode.focus(); 150 | focusManager.refresh(); 151 | } 152 | 153 | function onSearchResults(e) { 154 | var frag = Y.one(Y.config.doc.createDocumentFragment()); 155 | 156 | if (e.results.length) { 157 | YArray.each(e.results, function (result) { 158 | frag.append(result.display); 159 | }); 160 | } else { 161 | frag.append( 162 | '
  • ' + 163 | 'No results found. Maybe you\'ll have better luck with a ' + 164 | 'different query?' + 165 | '
  • ' 166 | ); 167 | } 168 | 169 | 170 | focusManager.refresh(); 171 | } 172 | 173 | function onTabSelectionChange(e) { 174 | var tab = e.newVal, 175 | name = tab.get('label').toLowerCase(); 176 | 177 | tabs.selected = { 178 | index: tab.get('index'), 179 | name : name, 180 | tab : tab 181 | }; 182 | 183 | switch (name) { 184 | case 'classes': // fallthru 185 | case 'modules': 186 | filter.setAttrs({ 187 | minQueryLength: 0, 188 | queryType : name 189 | }); 190 | 191 | search.set('minQueryLength', -1); 192 | 193 | // Only send a request if this isn't the initially-selected tab. 194 | if (e.prevVal) { 195 | filter.sendRequest(filter.get('value')); 196 | } 197 | break; 198 | 199 | case 'everything': 200 | filter.set('minQueryLength', -1); 201 | search.set('minQueryLength', 1); 202 | 203 | if (search.get('value')) { 204 | search.sendRequest(search.get('value')); 205 | } else { 206 | inputNode.focus(); 207 | } 208 | break; 209 | 210 | default: 211 | // WTF? We shouldn't be here! 212 | filter.set('minQueryLength', -1); 213 | search.set('minQueryLength', -1); 214 | } 215 | 216 | if (focusManager) { 217 | setTimeout(function () { 218 | focusManager.refresh(); 219 | }, 1); 220 | } 221 | } 222 | 223 | function onTabSwitchKey(e) { 224 | var currentTabIndex = tabs.selected.index; 225 | 226 | if (!(e.ctrlKey || e.metaKey)) { 227 | return; 228 | } 229 | 230 | e.preventDefault(); 231 | 232 | switch (e.keyCode) { 233 | case 37: // left arrow 234 | if (currentTabIndex > 0) { 235 | tabview.selectChild(currentTabIndex - 1); 236 | inputNode.focus(); 237 | } 238 | break; 239 | 240 | case 39: // right arrow 241 | if (currentTabIndex < (Y.Object.size(tabs) - 2)) { 242 | tabview.selectChild(currentTabIndex + 1); 243 | inputNode.focus(); 244 | } 245 | break; 246 | } 247 | } 248 | 249 | }, '3.4.0', {requires: [ 250 | 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' 251 | ]}); 252 | -------------------------------------------------------------------------------- /docs/assets/js/api-search.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-search', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | Node = Y.Node, 5 | YArray = Y.Array; 6 | 7 | Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], { 8 | // -- Public Properties ---------------------------------------------------- 9 | RESULT_TEMPLATE: 10 | '
  • ' + 11 | '' + 12 | '

    {name}

    ' + 13 | '{resultType}' + 14 | '
    {description}
    ' + 15 | '{class}' + 16 | '
    ' + 17 | '
  • ', 18 | 19 | // -- Initializer ---------------------------------------------------------- 20 | initializer: function () { 21 | this._bindUIACBase(); 22 | this._syncUIACBase(); 23 | }, 24 | 25 | // -- Protected Methods ---------------------------------------------------- 26 | _apiResultFilter: function (query, results) { 27 | // Filter components out of the results. 28 | return YArray.filter(results, function (result) { 29 | return result.raw.resultType === 'component' ? false : result; 30 | }); 31 | }, 32 | 33 | _apiResultFormatter: function (query, results) { 34 | return YArray.map(results, function (result) { 35 | var raw = Y.merge(result.raw), // create a copy 36 | desc = raw.description || ''; 37 | 38 | // Convert description to text and truncate it if necessary. 39 | desc = Node.create('
    ' + desc + '
    ').get('text'); 40 | 41 | if (desc.length > 65) { 42 | desc = Y.Escape.html(desc.substr(0, 65)) + ' …'; 43 | } else { 44 | desc = Y.Escape.html(desc); 45 | } 46 | 47 | raw['class'] || (raw['class'] = ''); 48 | raw.description = desc; 49 | 50 | // Use the highlighted result name. 51 | raw.name = result.highlighted; 52 | 53 | return Lang.sub(this.RESULT_TEMPLATE, raw); 54 | }, this); 55 | }, 56 | 57 | _apiTextLocator: function (result) { 58 | return result.displayName || result.name; 59 | } 60 | }, { 61 | // -- Attributes ----------------------------------------------------------- 62 | ATTRS: { 63 | resultFormatter: { 64 | valueFn: function () { 65 | return this._apiResultFormatter; 66 | } 67 | }, 68 | 69 | resultFilters: { 70 | valueFn: function () { 71 | return this._apiResultFilter; 72 | } 73 | }, 74 | 75 | resultHighlighter: { 76 | value: 'phraseMatch' 77 | }, 78 | 79 | resultListLocator: { 80 | value: 'data.results' 81 | }, 82 | 83 | resultTextLocator: { 84 | valueFn: function () { 85 | return this._apiTextLocator; 86 | } 87 | }, 88 | 89 | source: { 90 | value: '/api/v1/search?q={query}&count={maxResults}' 91 | } 92 | } 93 | }); 94 | 95 | }, '3.4.0', {requires: [ 96 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources', 97 | 'escape' 98 | ]}); 99 | -------------------------------------------------------------------------------- /docs/assets/js/apidocs.js: -------------------------------------------------------------------------------- 1 | YUI().use( 2 | 'yuidoc-meta', 3 | 'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax', 4 | function (Y) { 5 | 6 | var win = Y.config.win, 7 | localStorage = win.localStorage, 8 | 9 | bdNode = Y.one('#bd'), 10 | 11 | pjax, 12 | defaultRoute, 13 | 14 | classTabView, 15 | selectedTab; 16 | 17 | // Kill pjax functionality unless serving over HTTP. 18 | if (!Y.getLocation().protocol.match(/^https?\:/)) { 19 | Y.Router.html5 = false; 20 | } 21 | 22 | // Create the default route with middleware which enables syntax highlighting 23 | // on the loaded content. 24 | defaultRoute = Y.Pjax.defaultRoute.concat(function (req, res, next) { 25 | prettyPrint(); 26 | bdNode.removeClass('loading'); 27 | 28 | next(); 29 | }); 30 | 31 | pjax = new Y.Pjax({ 32 | container : '#docs-main', 33 | contentSelector: '#docs-main > .content', 34 | linkSelector : '#bd a', 35 | titleSelector : '#xhr-title', 36 | 37 | navigateOnHash: true, 38 | root : '/', 39 | routes : [ 40 | // -- / ---------------------------------------------------------------- 41 | { 42 | path : '/(index.html)?', 43 | callbacks: defaultRoute 44 | }, 45 | 46 | // -- /classes/* ------------------------------------------------------- 47 | { 48 | path : '/classes/:class.html*', 49 | callbacks: [defaultRoute, 'handleClasses'] 50 | }, 51 | 52 | // -- /files/* --------------------------------------------------------- 53 | { 54 | path : '/files/*file', 55 | callbacks: [defaultRoute, 'handleFiles'] 56 | }, 57 | 58 | // -- /modules/* ------------------------------------------------------- 59 | { 60 | path : '/modules/:module.html*', 61 | callbacks: defaultRoute 62 | } 63 | ] 64 | }); 65 | 66 | // -- Utility Functions -------------------------------------------------------- 67 | 68 | pjax.checkVisibility = function (tab) { 69 | tab || (tab = selectedTab); 70 | 71 | if (!tab) { return; } 72 | 73 | var panelNode = tab.get('panelNode'), 74 | visibleItems; 75 | 76 | // If no items are visible in the tab panel due to the current visibility 77 | // settings, display a message to that effect. 78 | visibleItems = panelNode.all('.item,.index-item').some(function (itemNode) { 79 | if (itemNode.getComputedStyle('display') !== 'none') { 80 | return true; 81 | } 82 | }); 83 | 84 | panelNode.all('.no-visible-items').remove(); 85 | 86 | if (!visibleItems) { 87 | if (Y.one('#index .index-item')) { 88 | panelNode.append( 89 | '
    ' + 90 | '

    ' + 91 | 'Some items are not shown due to the current visibility ' + 92 | 'settings. Use the checkboxes at the upper right of this ' + 93 | 'page to change the visibility settings.' + 94 | '

    ' + 95 | '
    ' 96 | ); 97 | } else { 98 | panelNode.append( 99 | '
    ' + 100 | '

    ' + 101 | 'This class doesn\'t provide any methods, properties, ' + 102 | 'attributes, or events.' + 103 | '

    ' + 104 | '
    ' 105 | ); 106 | } 107 | } 108 | 109 | // Hide index sections without any visible items. 110 | Y.all('.index-section').each(function (section) { 111 | var items = 0, 112 | visibleItems = 0; 113 | 114 | section.all('.index-item').each(function (itemNode) { 115 | items += 1; 116 | 117 | if (itemNode.getComputedStyle('display') !== 'none') { 118 | visibleItems += 1; 119 | } 120 | }); 121 | 122 | section.toggleClass('hidden', !visibleItems); 123 | section.toggleClass('no-columns', visibleItems < 4); 124 | }); 125 | }; 126 | 127 | pjax.initClassTabView = function () { 128 | if (!Y.all('#classdocs .api-class-tab').size()) { 129 | return; 130 | } 131 | 132 | if (classTabView) { 133 | classTabView.destroy(); 134 | selectedTab = null; 135 | } 136 | 137 | classTabView = new Y.TabView({ 138 | srcNode: '#classdocs', 139 | 140 | on: { 141 | selectionChange: pjax.onTabSelectionChange 142 | } 143 | }); 144 | 145 | pjax.updateTabState(); 146 | classTabView.render(); 147 | }; 148 | 149 | pjax.initLineNumbers = function () { 150 | var hash = win.location.hash.substring(1), 151 | container = pjax.get('container'), 152 | hasLines, node; 153 | 154 | // Add ids for each line number in the file source view. 155 | container.all('.linenums>li').each(function (lineNode, index) { 156 | lineNode.set('id', 'l' + (index + 1)); 157 | lineNode.addClass('file-line'); 158 | hasLines = true; 159 | }); 160 | 161 | // Scroll to the desired line. 162 | if (hasLines && /^l\d+$/.test(hash)) { 163 | if ((node = container.getById(hash))) { 164 | win.scroll(0, node.getY()); 165 | } 166 | } 167 | }; 168 | 169 | pjax.initRoot = function () { 170 | var terminators = /^(?:classes|files|modules)$/, 171 | parts = pjax._getPathRoot().split('/'), 172 | root = [], 173 | i, len, part; 174 | 175 | for (i = 0, len = parts.length; i < len; i += 1) { 176 | part = parts[i]; 177 | 178 | if (part.match(terminators)) { 179 | // Makes sure the path will end with a "/". 180 | root.push(''); 181 | break; 182 | } 183 | 184 | root.push(part); 185 | } 186 | 187 | pjax.set('root', root.join('/')); 188 | }; 189 | 190 | pjax.updateTabState = function (src) { 191 | var hash = win.location.hash.substring(1), 192 | defaultTab, node, tab, tabPanel; 193 | 194 | function scrollToNode() { 195 | if (node.hasClass('protected')) { 196 | Y.one('#api-show-protected').set('checked', true); 197 | pjax.updateVisibility(); 198 | } 199 | 200 | if (node.hasClass('private')) { 201 | Y.one('#api-show-private').set('checked', true); 202 | pjax.updateVisibility(); 203 | } 204 | 205 | setTimeout(function () { 206 | // For some reason, unless we re-get the node instance here, 207 | // getY() always returns 0. 208 | var node = Y.one('#classdocs').getById(hash); 209 | win.scrollTo(0, node.getY() - 70); 210 | }, 1); 211 | } 212 | 213 | if (!classTabView) { 214 | return; 215 | } 216 | 217 | if (src === 'hashchange' && !hash) { 218 | defaultTab = 'index'; 219 | } else { 220 | if (localStorage) { 221 | defaultTab = localStorage.getItem('tab_' + pjax.getPath()) || 222 | 'index'; 223 | } else { 224 | defaultTab = 'index'; 225 | } 226 | } 227 | 228 | if (hash && (node = Y.one('#classdocs').getById(hash))) { 229 | if ((tabPanel = node.ancestor('.api-class-tabpanel', true))) { 230 | if ((tab = Y.one('#classdocs .api-class-tab.' + tabPanel.get('id')))) { 231 | if (classTabView.get('rendered')) { 232 | Y.Widget.getByNode(tab).set('selected', 1); 233 | } else { 234 | tab.addClass('yui3-tab-selected'); 235 | } 236 | } 237 | } 238 | 239 | // Scroll to the desired element if this is a hash URL. 240 | if (node) { 241 | if (classTabView.get('rendered')) { 242 | scrollToNode(); 243 | } else { 244 | classTabView.once('renderedChange', scrollToNode); 245 | } 246 | } 247 | } else { 248 | tab = Y.one('#classdocs .api-class-tab.' + defaultTab); 249 | 250 | // When the `defaultTab` node isn't found, `localStorage` is stale. 251 | if (!tab && defaultTab !== 'index') { 252 | tab = Y.one('#classdocs .api-class-tab.index'); 253 | } 254 | 255 | if (classTabView.get('rendered')) { 256 | Y.Widget.getByNode(tab).set('selected', 1); 257 | } else { 258 | tab.addClass('yui3-tab-selected'); 259 | } 260 | } 261 | }; 262 | 263 | pjax.updateVisibility = function () { 264 | var container = pjax.get('container'); 265 | 266 | container.toggleClass('hide-inherited', 267 | !Y.one('#api-show-inherited').get('checked')); 268 | 269 | container.toggleClass('show-deprecated', 270 | Y.one('#api-show-deprecated').get('checked')); 271 | 272 | container.toggleClass('show-protected', 273 | Y.one('#api-show-protected').get('checked')); 274 | 275 | container.toggleClass('show-private', 276 | Y.one('#api-show-private').get('checked')); 277 | 278 | pjax.checkVisibility(); 279 | }; 280 | 281 | // -- Route Handlers ----------------------------------------------------------- 282 | 283 | pjax.handleClasses = function (req, res, next) { 284 | var status = res.ioResponse.status; 285 | 286 | // Handles success and local filesystem XHRs. 287 | if (!status || (status >= 200 && status < 300)) { 288 | pjax.initClassTabView(); 289 | } 290 | 291 | next(); 292 | }; 293 | 294 | pjax.handleFiles = function (req, res, next) { 295 | var status = res.ioResponse.status; 296 | 297 | // Handles success and local filesystem XHRs. 298 | if (!status || (status >= 200 && status < 300)) { 299 | pjax.initLineNumbers(); 300 | } 301 | 302 | next(); 303 | }; 304 | 305 | // -- Event Handlers ----------------------------------------------------------- 306 | 307 | pjax.onNavigate = function (e) { 308 | var hash = e.hash, 309 | originTarget = e.originEvent && e.originEvent.target, 310 | tab; 311 | 312 | if (hash) { 313 | tab = originTarget && originTarget.ancestor('.yui3-tab', true); 314 | 315 | if (hash === win.location.hash) { 316 | pjax.updateTabState('hashchange'); 317 | } else if (!tab) { 318 | win.location.hash = hash; 319 | } 320 | 321 | e.preventDefault(); 322 | return; 323 | } 324 | 325 | // Only scroll to the top of the page when the URL doesn't have a hash. 326 | this.set('scrollToTop', !e.url.match(/#.+$/)); 327 | 328 | bdNode.addClass('loading'); 329 | }; 330 | 331 | pjax.onOptionClick = function (e) { 332 | pjax.updateVisibility(); 333 | }; 334 | 335 | pjax.onTabSelectionChange = function (e) { 336 | var tab = e.newVal, 337 | tabId = tab.get('contentBox').getAttribute('href').substring(1); 338 | 339 | selectedTab = tab; 340 | 341 | // If switching from a previous tab (i.e., this is not the default tab), 342 | // replace the history entry with a hash URL that will cause this tab to 343 | // be selected if the user navigates away and then returns using the back 344 | // or forward buttons. 345 | if (e.prevVal && localStorage) { 346 | localStorage.setItem('tab_' + pjax.getPath(), tabId); 347 | } 348 | 349 | pjax.checkVisibility(tab); 350 | }; 351 | 352 | // -- Init --------------------------------------------------------------------- 353 | 354 | pjax.on('navigate', pjax.onNavigate); 355 | 356 | pjax.initRoot(); 357 | pjax.upgrade(); 358 | pjax.initClassTabView(); 359 | pjax.initLineNumbers(); 360 | pjax.updateVisibility(); 361 | 362 | Y.APIList.rootPath = pjax.get('root'); 363 | 364 | Y.one('#api-options').delegate('click', pjax.onOptionClick, 'input'); 365 | 366 | Y.on('hashchange', function (e) { 367 | pjax.updateTabState('hashchange'); 368 | }, win); 369 | 370 | }); 371 | -------------------------------------------------------------------------------- /docs/assets/js/yui-prettify.js: -------------------------------------------------------------------------------- 1 | YUI().use('node', function(Y) { 2 | var code = Y.all('.prettyprint.linenums'); 3 | if (code.size()) { 4 | code.each(function(c) { 5 | var lis = c.all('ol li'), 6 | l = 1; 7 | lis.each(function(n) { 8 | n.prepend(''); 9 | l++; 10 | }); 11 | }); 12 | var h = location.hash; 13 | location.hash = ''; 14 | h = h.replace('LINE_', 'LINENUM_'); 15 | location.hash = h; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/CHANGES.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Change Log 5 | 6 | 7 | README 8 | 9 |

    Known Issues

    10 |
      11 |
    • Perl formatting is really crappy. Partly because the author is lazy and 12 | partly because Perl is 13 | hard to parse. 14 |
    • On some browsers, <code> elements with newlines in the text 15 | which use CSS to specify white-space:pre will have the newlines 16 | improperly stripped if the element is not attached to the document at the time 17 | the stripping is done. Also, on IE 6, all newlines will be stripped from 18 | <code> elements because of the way IE6 produces 19 | innerHTML. Workaround: use <pre> for code with 20 | newlines. 21 |
    22 | 23 |

    Change Log

    24 |

    29 March 2007

    25 |
      26 |
    • Added tests for PHP support 27 | to address 28 | issue 3. 30 |
    • Fixed 31 | bug: prettyPrintOne was not halting. This was not 33 | reachable through the normal entry point. 34 |
    • Fixed 35 | bug: recursing into a script block or PHP tag that was not properly 37 | closed would not silently drop the content. 38 | (test) 39 |
    • Fixed 40 | bug: was eating tabs 42 | (test) 43 |
    • Fixed entity handling so that the caveat 44 |
      45 |

      Caveats: please properly escape less-thans. x&lt;y 46 | instead of x<y, and use " instead of 47 | &quot; for string delimiters.

      48 |
      49 | is no longer applicable. 50 |
    • Added noisefree's C# 51 | patch 53 |
    • Added a distribution that has comments and 54 | whitespace removed to reduce download size from 45.5kB to 12.8kB. 55 |
    56 |

    4 Jul 2008

    57 |
      58 |
    • Added language specific formatters that are triggered by the presence 59 | of a lang-<language-file-extension>
    • 60 |
    • Fixed bug: python handling of '''string''' 61 |
    • Fixed bug: / in regex [charsets] should not end regex 62 |
    63 |

    5 Jul 2008

    64 |
    67 |

    14 Jul 2008

    68 | 76 |

    6 Jan 2009

    77 | 93 |

    21 May 2009

    94 | 101 |

    14 August 2009

    102 | 105 |

    3 October 2009

    106 | 109 |

    19 July 2010

    110 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/README.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Javascript code prettifier 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | Languages : CH 20 |

    Javascript code prettifier

    21 | 22 |

    Setup

    23 |
      24 |
    1. Download a distribution 25 |
    2. Include the script and stylesheets in your document 26 | (you will need to make sure the css and js file are on your server, and 27 | adjust the paths in the script and link tag) 28 |
       29 | <link href="prettify.css" type="text/css" rel="stylesheet" />
       30 | <script type="text/javascript" src="prettify.js"></script>
      31 |
    3. Add onload="prettyPrint()" to your 32 | document's body tag. 33 |
    4. Modify the stylesheet to get the coloring you prefer
    5. 34 |
    35 | 36 |

    Usage

    37 |

    Put code snippets in 38 | <pre class="prettyprint">...</pre> 39 | or <code class="prettyprint">...</code> 40 | and it will automatically be pretty printed. 41 | 42 | 43 | 44 | 47 |
    The original 45 | Prettier 46 |
    class Voila {
     49 | public:
     50 |   // Voila
     51 |   static const string VOILA = "Voila";
     52 | 
     53 |   // will not interfere with embedded tags.
     54 | }
    55 | 56 |
    class Voila {
     57 | public:
     58 |   // Voila
     59 |   static const string VOILA = "Voila";
     60 | 
     61 |   // will not interfere with embedded tags.
     62 | }
    63 |
    64 | 65 |

    FAQ

    66 |

    Which languages does it work for?

    67 |

    The comments in prettify.js are authoritative but the lexer 68 | should work on a number of languages including C and friends, 69 | Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles. 70 | It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl 71 | and Ruby, but, because of commenting conventions, doesn't work on 72 | Smalltalk, or CAML-like languages.

    73 | 74 |

    LISPy languages are supported via an extension: 75 | lang-lisp.js.

    77 |

    And similarly for 78 | CSS, 80 | Haskell, 82 | Lua, 84 | OCAML, SML, F#, 86 | Visual Basic, 88 | SQL, 90 | Protocol Buffers, and 92 | WikiText.. 94 | 95 |

    If you'd like to add an extension for your favorite language, please 96 | look at src/lang-lisp.js and file an 97 | issue including your language extension, and a testcase.

    99 | 100 |

    How do I specify which language my code is in?

    101 |

    You don't need to specify the language since prettyprint() 102 | will guess. You can specify a language by specifying the language extension 103 | along with the prettyprint class like so:

    104 |
    <pre class="prettyprint lang-html">
    106 |   The lang-* class specifies the language file extensions.
    107 |   File extensions supported by default include
    108 |     "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
    109 |     "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
    110 |     "xhtml", "xml", "xsl".
    111 | </pre>
    112 | 113 |

    It doesn't work on <obfuscated code sample>?

    114 |

    Yes. Prettifying obfuscated code is like putting lipstick on a pig 115 | — i.e. outside the scope of this tool.

    116 | 117 |

    Which browsers does it work with?

    118 |

    It's been tested with IE 6, Firefox 1.5 & 2, and Safari 2.0.4. 119 | Look at the test page to see if it 120 | works in your browser.

    121 | 122 |

    What's changed?

    123 |

    See the change log

    124 | 125 |

    Why doesn't Prettyprinting of strings work on WordPress?

    126 |

    Apparently wordpress does "smart quoting" which changes close quotes. 127 | This causes end quotes to not match up with open quotes. 128 |

    This breaks prettifying as well as copying and pasting of code samples. 129 | See 130 | WordPress's help center for info on how to stop smart quoting of code 132 | snippets.

    133 | 134 |

    How do I put line numbers in my code?

    135 |

    You can use the linenums class to turn on line 136 | numbering. If your code doesn't start at line number 1, you can 137 | add a colon and a line number to the end of that class as in 138 | linenums:52. 139 | 140 |

    For example 141 |

    <pre class="prettyprint linenums:4"
    142 | >// This is line 4.
    143 | foo();
    144 | bar();
    145 | baz();
    146 | boo();
    147 | far();
    148 | faz();
    149 | <pre>
    150 | produces 151 |
    // This is line 4.
    153 | foo();
    154 | bar();
    155 | baz();
    156 | boo();
    157 | far();
    158 | faz();
    159 | 
    160 | 161 |

    How do I prevent a portion of markup from being marked as code?

    162 |

    You can use the nocode class to identify a span of markup 163 | that is not code. 164 |

    <pre class=prettyprint>
    165 | int x = foo();  /* This is a comment  <span class="nocode">This is not code</span>
    166 |   Continuation of comment */
    167 | int y = bar();
    168 | </pre>
    169 | produces 170 |
    171 | int x = foo();  /* This is a comment  This is not code
    172 |   Continuation of comment */
    173 | int y = bar();
    174 | 
    175 | 176 |

    For a more complete example see the issue22 177 | testcase.

    178 | 179 |

    I get an error message "a is not a function" or "opt_whenDone is not a function"

    180 |

    If you are calling prettyPrint via an event handler, wrap it in a function. 181 | Instead of doing 182 |

    183 | addEventListener('load', prettyPrint, false); 185 |
    186 | wrap it in a closure like 187 |
    188 | addEventListener('load', function (event) { prettyPrint() }, false); 190 |
    191 | so that the browser does not pass an event object to prettyPrint which 192 | will confuse it. 193 | 194 |


    195 | 196 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/prettify-min.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/prettify-min.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;var prettyPrintOne;var prettyPrint;(function(){var O=window;var j=["break,continue,do,else,for,if,return,while"];var v=[j,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var q=[v,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var m=[q,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var y=[q,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var T=[y,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"];var s="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes";var x=[q,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var t="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var J=[j,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var g=[j,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var I=[j,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var B=[m,T,x,t+J,g,I];var f=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var D="str";var A="kwd";var k="com";var Q="typ";var H="lit";var M="pun";var G="pln";var n="tag";var F="dec";var K="src";var R="atn";var o="atv";var P="nocode";var N="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function l(ab){var af=0;var U=false;var ae=false;for(var X=0,W=ab.length;X122)){if(!(am<65||ai>90)){ah.push([Math.max(65,ai)|32,Math.min(am,90)|32])}if(!(am<97||ai>122)){ah.push([Math.max(97,ai)&~32,Math.min(am,122)&~32])}}}}ah.sort(function(aw,av){return(aw[0]-av[0])||(av[1]-aw[1])});var ak=[];var aq=[];for(var at=0;atau[0]){if(au[1]+1>au[0]){ao.push("-")}ao.push(V(au[1]))}}ao.push("]");return ao.join("")}function Y(an){var al=an.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var aj=al.length;var ap=[];for(var am=0,ao=0;am=2&&ak==="["){al[am]=Z(ai)}else{if(ak!=="\\"){al[am]=ai.replace(/[a-zA-Z]/g,function(aq){var ar=aq.charCodeAt(0);return"["+String.fromCharCode(ar&~32,ar|32)+"]"})}}}}return al.join("")}var ac=[];for(var X=0,W=ab.length;X=0;){U[ae.charAt(ag)]=aa}}var ah=aa[1];var ac=""+ah;if(!ai.hasOwnProperty(ac)){aj.push(ah);ai[ac]=null}}aj.push(/[\0-\uffff]/);X=l(aj)})();var Z=V.length;var Y=function(aj){var ab=aj.sourceCode,aa=aj.basePos;var af=[aa,G];var ah=0;var ap=ab.match(X)||[];var al={};for(var ag=0,at=ap.length;ag=5&&"lang-"===ar.substring(0,5);if(ao&&!(ak&&typeof ak[1]==="string")){ao=false;ar=K}if(!ao){al[ai]=ar}}var ad=ah;ah+=ai.length;if(!ao){af.push(aa+ad,ar)}else{var an=ak[1];var am=ai.indexOf(an);var ae=am+an.length;if(ak[2]){ae=ai.length-ak[2].length;am=ae-an.length}var au=ar.substring(5);C(aa+ad,ai.substring(0,am),Y,af);C(aa+ad+am,an,r(au,an),af);C(aa+ad+ae,ai.substring(ae),Y,af)}}aj.decorations=af};return Y}function i(V){var Y=[],U=[];if(V.tripleQuotedStrings){Y.push([D,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(V.multiLineStrings){Y.push([D,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{Y.push([D,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(V.verbatimStrings){U.push([D,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var ab=V.hashComments;if(ab){if(V.cStyleComments){if(ab>1){Y.push([k,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{Y.push([k,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}U.push([D,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{Y.push([k,/^#[^\r\n]*/,null,"#"])}}if(V.cStyleComments){U.push([k,/^\/\/[^\r\n]*/,null]);U.push([k,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(V.regexLiterals){var aa=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");U.push(["lang-regex",new RegExp("^"+N+"("+aa+")")])}var X=V.types;if(X){U.push([Q,X])}var W=(""+V.keywords).replace(/^ | $/g,"");if(W.length){U.push([A,new RegExp("^(?:"+W.replace(/[\s,]+/g,"|")+")\\b"),null])}Y.push([G,/^\s+/,null," \r\n\t\xA0"]);var Z=/^.[^\s\w\.$@\'\"\`\/\\]*/;U.push([H,/^@[a-z_$][a-z_$@0-9]*/i,null],[Q,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[G,/^[a-z_$][a-z_$@0-9]*/i,null],[H,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[G,/^\\[\s\S]?/,null],[M,Z,null]);return h(Y,U)}var L=i({keywords:B,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function S(W,ah,aa){var V=/(?:^|\s)nocode(?:\s|$)/;var ac=/\r\n?|\n/;var ad=W.ownerDocument;var ag=ad.createElement("li");while(W.firstChild){ag.appendChild(W.firstChild)}var X=[ag];function af(am){switch(am.nodeType){case 1:if(V.test(am.className)){break}if("br"===am.nodeName){ae(am);if(am.parentNode){am.parentNode.removeChild(am)}}else{for(var ao=am.firstChild;ao;ao=ao.nextSibling){af(ao)}}break;case 3:case 4:if(aa){var an=am.nodeValue;var ak=an.match(ac);if(ak){var aj=an.substring(0,ak.index);am.nodeValue=aj;var ai=an.substring(ak.index+ak[0].length);if(ai){var al=am.parentNode;al.insertBefore(ad.createTextNode(ai),am.nextSibling)}ae(am);if(!aj){am.parentNode.removeChild(am)}}}break}}function ae(al){while(!al.nextSibling){al=al.parentNode;if(!al){return}}function aj(am,at){var ar=at?am.cloneNode(false):am;var ap=am.parentNode;if(ap){var aq=aj(ap,1);var ao=am.nextSibling;aq.appendChild(ar);for(var an=ao;an;an=ao){ao=an.nextSibling;aq.appendChild(an)}}return ar}var ai=aj(al.nextSibling,0);for(var ak;(ak=ai.parentNode)&&ak.nodeType===1;){ai=ak}X.push(ai)}for(var Z=0;Z=U){aj+=2}if(Y>=ar){ac+=2}}}finally{if(au){au.style.display=ak}}}var u={};function d(W,X){for(var U=X.length;--U>=0;){var V=X[U];if(!u.hasOwnProperty(V)){u[V]=W}else{if(O.console){console.warn("cannot override language handler %s",V)}}}}function r(V,U){if(!(V&&u.hasOwnProperty(V))){V=/^\s*]*(?:>|$)/],[k,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[M,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);d(h([[G,/^[\s]+/,null," \t\r\n"],[o,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[n,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[R,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[M,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);d(h([],[[o,/^[\s\S]+/]]),["uq.val"]);d(i({keywords:m,hashComments:true,cStyleComments:true,types:f}),["c","cc","cpp","cxx","cyc","m"]);d(i({keywords:"null,true,false"}),["json"]);d(i({keywords:T,hashComments:true,cStyleComments:true,verbatimStrings:true,types:f}),["cs"]);d(i({keywords:y,cStyleComments:true}),["java"]);d(i({keywords:I,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);d(i({keywords:J,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);d(i({keywords:t,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);d(i({keywords:g,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);d(i({keywords:x,cStyleComments:true,regexLiterals:true}),["js"]);d(i({keywords:s,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);d(h([],[[D,/^[\s\S]+/]]),["regex"]);function e(X){var W=X.langExtension;try{var U=b(X.sourceNode,X.pre);var V=U.sourceCode;X.sourceCode=V;X.spans=U.spans;X.basePos=0;r(W,V)(X);E(X)}catch(Y){if(O.console){console.log(Y&&Y.stack?Y.stack:Y)}}}function z(Y,X,W){var U=document.createElement("pre");U.innerHTML=Y;if(W){S(U,W,true)}var V={langExtension:X,numberLines:W,sourceNode:U,pre:1};e(V);return U.innerHTML}function c(aj){function ab(al){return document.getElementsByTagName(al)}var ah=[ab("pre"),ab("code"),ab("xmp")];var V=[];for(var ae=0;ae]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); -------------------------------------------------------------------------------- /docs/classes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "name": "ucsv", 4 | "description": "", 5 | "version": "1.2.0", 6 | "url": "https://github.com/uselesscode/ucsv" 7 | }, 8 | "files": { 9 | "source\\core.js": { 10 | "name": "source\\core.js", 11 | "modules": {}, 12 | "classes": {}, 13 | "fors": { 14 | "CSV": 1 15 | }, 16 | "namespaces": {} 17 | }, 18 | "source\\intro.js": { 19 | "name": "source\\intro.js", 20 | "modules": {}, 21 | "classes": {}, 22 | "fors": {}, 23 | "namespaces": {} 24 | } 25 | }, 26 | "modules": {}, 27 | "classes": { 28 | "CSV": { 29 | "name": "CSV", 30 | "shortname": "CSV", 31 | "classitems": [], 32 | "plugins": [], 33 | "extensions": [], 34 | "plugin_for": [], 35 | "extension_for": [] 36 | } 37 | }, 38 | "classitems": [ 39 | { 40 | "file": "source\\core.js", 41 | "line": 60, 42 | "description": "Converts an array into a Comma Separated Values string.\nEach item in the array should be an array that represents one row in the CSV.\nNulls and undefined values are interpreted as empty fields.", 43 | "itemtype": "method", 44 | "name": "arrayToCsv", 45 | "params": [ 46 | { 47 | "name": "a", 48 | "description": "The array to convert", 49 | "type": "String" 50 | } 51 | ], 52 | "return": { 53 | "description": "A CSV representation of the provided array.", 54 | "type": "String" 55 | }, 56 | "access": "public", 57 | "tagname": "", 58 | "static": 1, 59 | "example": [ 60 | "\n var csv,\n books = [\n ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008],\n ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008],\n ['Effective JavaScript', 'Herman, David', 2012]\n ];\n\n csv = CSV.arrayToCsv(books);\n\n // csv now contains:\n //\n // JavaScript: The Good Parts,\"Crockford, Douglas\",2008\\n\n // Object-Oriented JavaScript,\"Stefanov, Stoyan\",2008\\n\n // Effective JavaScript,\"Herman, David\",2012\\n" 61 | ], 62 | "class": "CSV" 63 | }, 64 | { 65 | "file": "source\\core.js", 66 | "line": 111, 67 | "description": "Converts a Comma Separated Values string into a multi-dimensional array.\nEach row in the CSV becomes an array.\nEmpty fields are converted to nulls and non-quoted numbers are converted to integers or floats.", 68 | "itemtype": "method", 69 | "name": "csvToArray", 70 | "return": { 71 | "description": "The CSV parsed as an array", 72 | "type": "Array" 73 | }, 74 | "params": [ 75 | { 76 | "name": "s", 77 | "description": "The string to convert", 78 | "type": "String" 79 | }, 80 | { 81 | "name": "config", 82 | "description": "Object literal with extra configuration. For historical reasons setting config to `true` is the same as passing `{trim: true}`, but this usage is deprecated and will likely be removed in the next version.", 83 | "type": "Object", 84 | "optional": true, 85 | "props": [ 86 | { 87 | "name": "trim", 88 | "description": "If set to True leading and trailing whitespace is stripped off of each non-quoted field as it is imported", 89 | "type": "Boolean", 90 | "optional": true, 91 | "optdefault": "false" 92 | } 93 | ] 94 | } 95 | ], 96 | "static": 1, 97 | "example": [ 98 | "\n var books,\n csv = 'JavaScript: The Good Parts,\"Crockford, Douglas\",2008\\n' +\n 'Object-Oriented JavaScript,\"Stefanov, Stoyan\",2008\\n' +\n 'Effective JavaScript,\"Herman, David\",2012\\n';\n\n books = CSV.csvToArray(csv);\n\n // books now equals:\n // [\n // ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008],\n // ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008],\n // ['Effective JavaScript', 'Herman, David', 2012]\n // ];" 99 | ], 100 | "class": "CSV" 101 | }, 102 | { 103 | "file": "source\\core.js", 104 | "line": 224, 105 | "description": "Converts a Comma Separated Values string into an array of objects.\nEach row in the CSV becomes an object with properties named after each column.\nEmpty fields are converted to nulls and non-quoted numbers are converted to integers or floats.", 106 | "itemtype": "method", 107 | "name": "csvToObject", 108 | "since": "1.2.0", 109 | "return": { 110 | "description": "The CSV parsed as an array of objects", 111 | "type": "Array" 112 | }, 113 | "params": [ 114 | { 115 | "name": "s", 116 | "description": "The string containing CSV data to convert", 117 | "type": "String" 118 | }, 119 | { 120 | "name": "config", 121 | "description": "Object literal with extra configuration", 122 | "type": "Object", 123 | "props": [ 124 | { 125 | "name": "columns", 126 | "description": "An array containing the name of each column in the CSV data. If not\n provided, the first row of the CSV data is assumed to contain the column names.", 127 | "type": "Array", 128 | "optional": true 129 | }, 130 | { 131 | "name": "trim", 132 | "description": "If true any field parsed from the CSV data will have leading and\n trailing whitespace trimmed", 133 | "type": "Boolean", 134 | "optional": true 135 | } 136 | ] 137 | } 138 | ], 139 | "static": 1, 140 | "example": [ 141 | "\n var books,\n csv = 'title,author,year\\n' +\n 'JavaScript: The Good Parts,\"Crockford, Douglas\",2008\\n' +\n 'Object-Oriented JavaScript,\"Stefanov, Stoyan\",2008\\n' +\n 'Effective JavaScript,\"Herman, David\",2012\\n';\n\n books = CSV.csvToObject(csv);\n\n // books now equals:\n // [\n // {\n // title: 'JavaScript: The Good Parts',\n // author: 'Crockford, Douglas',\n // year: 2008\n // },\n // {\n // title: 'Object-Oriented JavaScript',\n // author: 'Stefanov, Stoyan',\n // year: 2008\n // },\n // {\n // title: 'Effective JavaScript',\n // author: 'Herman, David',\n // year: 2012\n // }\n // ];" 142 | ], 143 | "class": "CSV" 144 | }, 145 | { 146 | "file": "source\\core.js", 147 | "line": 291, 148 | "description": "Converts an array of objects into Comma Separated Values data\nEach propery on the objects becomes a column in the CSV data.", 149 | "itemtype": "method", 150 | "name": "objectToCsv", 151 | "since": "1.2.0", 152 | "return": { 153 | "description": "CSV data, each row representing an object from the input array, each field representing a property from those objects", 154 | "type": "String" 155 | }, 156 | "params": [ 157 | { 158 | "name": "arr", 159 | "description": "An array of objects to be converted into CSV", 160 | "type": "String" 161 | }, 162 | { 163 | "name": "config", 164 | "description": "Object literal with extra configuration", 165 | "type": "Object", 166 | "props": [ 167 | { 168 | "name": "columns", 169 | "description": "An array containing the name of each column in the CSV data. If not\n provided, the column names will be inferred from the property names of the objects. Explicitly\n defining column names has several advantages:\n\n * It is faster since all column names are already known.\n * It allows you to specify a subset of the properties to use if you wish to.\n * It allows you to control what order the columns are output in, since the `for...in` statement used to infer field names does not guarantee a specific order.", 170 | "type": "Array", 171 | "optional": true 172 | }, 173 | { 174 | "name": "includeColumns", 175 | "description": "By default `objectToCsv` outputs the column names as\n the first row of the CSV data. Set to false to prevent this.", 176 | "type": "Boolean", 177 | "optional": true, 178 | "optdefault": "true" 179 | } 180 | ] 181 | } 182 | ], 183 | "static": 1, 184 | "example": [ 185 | "\n var csv,\n books = [\n {\n title: 'JavaScript: The Good Parts',\n author: 'Crockford, Douglas',\n year: 2008\n },\n {\n title: 'Object-Oriented JavaScript',\n author: 'Stefanov, Stoyan',\n year: 2008\n },\n {\n title: 'Effective JavaScript',\n author: 'Herman, David',\n year: 2012\n }\n ];\n\n csv = CSV.objectToCsv(books);\n\n // csv now contains:\n //\n // title,author,year\\n\n // JavaScript: The Good Parts,\"Crockford, Douglas\",2008\\n\n // Object-Oriented JavaScript,\"Stefanov, Stoyan\",2008\\n\n // Effective JavaScript,\"Herman, David\",2012\\n" 186 | ], 187 | "class": "CSV" 188 | }, 189 | { 190 | "file": "source\\intro.js", 191 | "line": 15, 192 | "description": "Namespace for CSV functions", 193 | "class": "" 194 | } 195 | ], 196 | "warnings": [ 197 | { 198 | "message": "replacing incorrect tag: returns with return", 199 | "line": " source\\core.js:60" 200 | }, 201 | { 202 | "message": "Missing item type\nNamespace for CSV functions", 203 | "line": " source\\intro.js:15" 204 | } 205 | ] 206 | } -------------------------------------------------------------------------------- /docs/files/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/files/source_core.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | source\core.js - ucsv 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 1.2.0 23 |
    24 |
    25 |
    26 | 27 |
    28 | 56 |
    57 |
    58 |
    59 | Show: 60 | 64 | 65 | 69 | 70 | 74 | 78 | 79 |
    80 | 81 | 82 |
    83 |
    84 |
    85 |

    File: source\core.js

    86 | 87 |
    88 |
     89 |   var rxIsInt = /^\d+$/,
     90 |     rxIsFloat = /^\d*\.\d+$|^\d+\.\d*$/,
     91 |     // If a string has leading or trailing space,
     92 |     // contains a comma double quote or a newline
     93 |     // it needs to be quoted in CSV output
     94 |     rxNeedsQuoting = /^\s|\s$|,|"|\n/,
     95 |     trim = (function () {
     96 |       // Fx 3.1 has a native trim function, it's about 10x faster, use it if it exists
     97 |       if (String.prototype.trim) {
     98 |         return function (s) {
     99 |           return s.trim();
    100 |         };
    101 |       }
    102 |       return function (s) {
    103 |         return s.replace(/^\s*/, '').replace(/\s*$/, '');
    104 |       };
    105 |     }()),
    106 | 
    107 |     isNumber = function (o) {
    108 |       return Object.prototype.toString.apply(o) === '[object Number]';
    109 |     },
    110 | 
    111 |     isString = function (o) {
    112 |       return Object.prototype.toString.apply(o) === '[object String]';
    113 |     },
    114 | 
    115 |     chomp = function (s) {
    116 |       if (s.charAt(s.length - 1) !== "\n") {
    117 |         // Does not end with \n, just return string
    118 |         return s;
    119 |       }
    120 |       // Remove the \n
    121 |       return s.substring(0, s.length - 1);
    122 |     },
    123 | 
    124 |     prepField = function (field) {
    125 |       if (isString(field)) {
    126 |         // Escape any " with double " ("")
    127 |         field = field.replace(/"/g, '""');
    128 | 
    129 |         // If the field starts or ends with whitespace, contains " or , or a newline or
    130 |         // is a string representing a number, quote it.
    131 |         if (rxNeedsQuoting.test(field) || rxIsInt.test(field) || rxIsFloat.test(field)) {
    132 |           field = '"' + field + '"';
    133 |         // quote empty strings
    134 |         } else if (field === "") {
    135 |           field = '""';
    136 |         }
    137 |       } else if (isNumber(field)) {
    138 |         field = field.toString(10);
    139 |       } else if (field === null || field === undefined) {
    140 |         field = '';
    141 |       } else {
    142 |         field = field.toString();
    143 |       }
    144 |       return field;
    145 |     },
    146 | 
    147 |     CSV = {
    148 |       /**
    149 |        Converts an array into a Comma Separated Values string.
    150 |        Each item in the array should be an array that represents one row in the CSV.
    151 |        Nulls and undefined values are interpreted as empty fields.
    152 | 
    153 |        @method arrayToCsv
    154 |        @param {String} a The array to convert
    155 | 
    156 |        @returns {String} A CSV representation of the provided array.
    157 |        @for CSV
    158 |        @public
    159 |        @static
    160 |        @example
    161 |            var csv,
    162 |              books = [
    163 |                ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008],
    164 |                ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008],
    165 |                ['Effective JavaScript', 'Herman, David', 2012]
    166 |              ];
    167 | 
    168 |            csv = CSV.arrayToCsv(books);
    169 | 
    170 |            // csv now contains:
    171 |            //
    172 |            // JavaScript: The Good Parts,"Crockford, Douglas",2008\n
    173 |            // Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n
    174 |            // Effective JavaScript,"Herman, David",2012\n
    175 |       */
    176 |       arrayToCsv: function (a) {
    177 |         var cur,
    178 |           out = '',
    179 |           row,
    180 |           i,
    181 |           j;
    182 | 
    183 |         for (i = 0; i < a.length; i += 1) {
    184 |           row = a[i];
    185 |           for (j = 0; j < row.length; j += 1) {
    186 |             cur = row[j];
    187 | 
    188 |             cur = prepField(cur);
    189 | 
    190 |             out += j < row.length - 1 ? cur + ',' : cur;
    191 |           }
    192 |           // End record
    193 |           out += "\n";
    194 |         }
    195 | 
    196 |         return out;
    197 |       },
    198 | 
    199 |       /**
    200 |         Converts a Comma Separated Values string into a multi-dimensional array.
    201 |         Each row in the CSV becomes an array.
    202 |         Empty fields are converted to nulls and non-quoted numbers are converted to integers or floats.
    203 | 
    204 |         @method csvToArray
    205 |         @return {Array} The CSV parsed as an array
    206 |         @param {String} s The string to convert
    207 |         @param {Object} [config] Object literal with extra configuration. For historical reasons setting config to `true` is the same as passing `{trim: true}`, but this usage is deprecated and will likely be removed in the next version.
    208 |         @param {Boolean} [config.trim=false] If set to True leading and trailing whitespace is stripped off of each non-quoted field as it is imported
    209 |         @for CSV
    210 |         @static
    211 |         @example
    212 |             var books,
    213 |               csv = 'JavaScript: The Good Parts,"Crockford, Douglas",2008\n' +
    214 |                 'Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n' +
    215 |                 'Effective JavaScript,"Herman, David",2012\n';
    216 | 
    217 |             books = CSV.csvToArray(csv);
    218 | 
    219 |             // books now equals:
    220 |             // [
    221 |             //   ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008],
    222 |             //   ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008],
    223 |             //   ['Effective JavaScript', 'Herman, David', 2012]
    224 |             // ];
    225 |       */
    226 |       csvToArray: function (s, config) {
    227 |         // Get rid of any trailing \n
    228 |         s = chomp(s);
    229 | 
    230 |         if (config === true) {
    231 |           config = {
    232 |             trim: true
    233 |           };
    234 |         } else {
    235 |           config = config || {};
    236 |         }
    237 | 
    238 |         var cur = '', // The character we are currently processing.
    239 |           inQuote = false,
    240 |           fieldQuoted = false,
    241 |           field = '', // Buffer for building up the current field
    242 |           row = [],
    243 |           out = [],
    244 |           trimIt = config.trim === true ? true : false,
    245 |           i,
    246 |           processField = function (field) {
    247 |             var trimmedField = trim(field);
    248 |             if (fieldQuoted !== true) {
    249 |               // If field is empty set to null
    250 |               if (field === '') {
    251 |                 field = null;
    252 |               // If the field was not quoted and we are trimming fields, trim it
    253 |               } else if (trimIt === true) {
    254 |                 field = trimmedField;
    255 |               }
    256 | 
    257 |               // Convert unquoted numbers to numbers
    258 |               if (rxIsInt.test(trimmedField) || rxIsFloat.test(trimmedField)) {
    259 |                 field = +trimmedField;
    260 |               }
    261 |             }
    262 |             return field;
    263 |           };
    264 | 
    265 |         for (i = 0; i < s.length; i += 1) {
    266 |           cur = s.charAt(i);
    267 | 
    268 |           // If we are at a EOF or EOR
    269 |           if (inQuote === false && (cur === ',' || cur === "\n")) {
    270 |             field = processField(field);
    271 |             // Add the current field to the current row
    272 |             row.push(field);
    273 |             // If this is EOR append row to output and flush row
    274 |             if (cur === "\n") {
    275 |               out.push(row);
    276 |               row = [];
    277 |             }
    278 |             // Flush the field buffer
    279 |             field = '';
    280 |             fieldQuoted = false;
    281 |           } else {
    282 |             // If it's not a ", add it to the field buffer
    283 |             if (cur !== '"') {
    284 |               field += cur;
    285 |             } else {
    286 |               if (!inQuote) {
    287 |                 // We are not in a quote, start a quote
    288 |                 inQuote = true;
    289 |                 fieldQuoted = true;
    290 |               } else {
    291 |                 // Next char is ", this is an escaped "
    292 |                 if (s.charAt(i + 1) === '"') {
    293 |                   field += '"';
    294 |                   // Skip the next char
    295 |                   i += 1;
    296 |                 } else {
    297 |                   // It's not escaping, so end quote
    298 |                   inQuote = false;
    299 |                 }
    300 |               }
    301 |             }
    302 |           }
    303 |         }
    304 | 
    305 |         // Add the last field
    306 |         field = processField(field);
    307 |         row.push(field);
    308 |         out.push(row);
    309 | 
    310 |         return out;
    311 |       },
    312 |       /**
    313 |         Converts a Comma Separated Values string into an array of objects.
    314 |         Each row in the CSV becomes an object with properties named after each column.
    315 |         Empty fields are converted to nulls and non-quoted numbers are converted to integers or floats.
    316 | 
    317 |         @method csvToObject
    318 |         @since 1.2.0
    319 |         @return {Array} The CSV parsed as an array of objects
    320 |         @param {String} s The string containing CSV data to convert
    321 |         @param {Object} config Object literal with extra configuration
    322 |         @param {Array} [config.columns] An array containing the name of each column in the CSV data. If not
    323 |           provided, the first row of the CSV data is assumed to contain the column names.
    324 |         @param {Boolean} [config.trim] If true any field parsed from the CSV data will have leading and
    325 |                                        trailing whitespace trimmed
    326 |         @for CSV
    327 |         @static
    328 |         @example
    329 |             var books,
    330 |               csv = 'title,author,year\n' +
    331 |                 'JavaScript: The Good Parts,"Crockford, Douglas",2008\n' +
    332 |                 'Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n' +
    333 |                 'Effective JavaScript,"Herman, David",2012\n';
    334 | 
    335 |             books = CSV.csvToObject(csv);
    336 | 
    337 |             // books now equals:
    338 |             // [
    339 |             //   {
    340 |             //     title: 'JavaScript: The Good Parts',
    341 |             //     author: 'Crockford, Douglas',
    342 |             //     year: 2008
    343 |             //   },
    344 |             //   {
    345 |             //     title: 'Object-Oriented JavaScript',
    346 |             //     author: 'Stefanov, Stoyan',
    347 |             //     year: 2008
    348 |             //   },
    349 |             //   {
    350 |             //     title: 'Effective JavaScript',
    351 |             //     author: 'Herman, David',
    352 |             //     year: 2012
    353 |             //   }
    354 |             // ];
    355 |       */
    356 |       csvToObject: function (s, config) {
    357 |         config = config !== undefined ? config : {};
    358 |         var columns = config.columns,
    359 |             trimIt = !!config.trim,
    360 |             csvArray = this.csvToArray(s, trimIt);
    361 | 
    362 |         // if columns were not provided, assume they are
    363 |         // in the first row
    364 |         if (!columns) {
    365 |           columns = csvArray.shift();
    366 |         }
    367 | 
    368 |         return csvArray.map(function (row) {
    369 |           var obj = {},
    370 |             i = 0,
    371 |             len = columns.length;
    372 |           for (; i < len; i += 1) {
    373 |             obj[columns[i]] = row[i];
    374 |           }
    375 |           return obj;
    376 |         });
    377 |       },
    378 | 
    379 |       /**
    380 |         Converts an array of objects into Comma Separated Values data
    381 |         Each propery on the objects becomes a column in the CSV data.
    382 | 
    383 |         @method objectToCsv
    384 |         @since 1.2.0
    385 |         @return {String} CSV data, each row representing an object from the input array, each field representing a property from those objects
    386 |         @param {String} arr An array of objects to be converted into CSV
    387 |         @param {Object} config Object literal with extra configuration
    388 |         @param {Array} [config.columns] An array containing the name of each column in the CSV data. If not
    389 |           provided, the column names will be inferred from the property names of the objects. Explicitly
    390 |           defining column names has several advantages:
    391 | 
    392 |           * It is faster since all column names are already known.
    393 |           * It allows you to specify a subset of the properties to use if you wish to.
    394 |           * It allows you to control what order the columns are output in, since the `for...in` statement used to infer field names does not guarantee a specific order.
    395 | 
    396 |         @param {Boolean} [config.includeColumns=true] By default `objectToCsv` outputs the column names as
    397 |           the first row of the CSV data. Set to false to prevent this.
    398 |         @for CSV
    399 |         @static
    400 |         @example
    401 |             var csv,
    402 |               books = [
    403 |                 {
    404 |                   title: 'JavaScript: The Good Parts',
    405 |                   author: 'Crockford, Douglas',
    406 |                   year: 2008
    407 |                 },
    408 |                 {
    409 |                   title: 'Object-Oriented JavaScript',
    410 |                   author: 'Stefanov, Stoyan',
    411 |                   year: 2008
    412 |                 },
    413 |                 {
    414 |                   title: 'Effective JavaScript',
    415 |                   author: 'Herman, David',
    416 |                   year: 2012
    417 |                 }
    418 |               ];
    419 | 
    420 |             csv = CSV.objectToCsv(books);
    421 | 
    422 |             // csv now contains:
    423 |             //
    424 |             // title,author,year\n
    425 |             // JavaScript: The Good Parts,"Crockford, Douglas",2008\n
    426 |             // Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n
    427 |             // Effective JavaScript,"Herman, David",2012\n
    428 |       */
    429 |       objectToCsv: function (arr, config) {
    430 |         config = config !== undefined ? config : {};
    431 |         var columns = config.columns,
    432 |           includeColumns = config.includeColumns,
    433 |           csv = '',
    434 |           csvColumns = '',
    435 |           processKnownColumns = function (obj) {
    436 |             var out = '',
    437 |               prop,
    438 |               i,
    439 |               len = arr.length,
    440 |               j,
    441 |               jlen = columns.length;
    442 | 
    443 |             for (i = 0; i < len; i += 1) {
    444 |               obj = arr[i];
    445 |               for (j = 0; j < jlen; j += 1) {
    446 |                 prop = columns[j];
    447 |                 out += prepField(obj[prop]);
    448 |                 out += j < jlen - 1 ? ',' : '';
    449 |               }
    450 |               out += '\n';
    451 |             }
    452 |             return out;
    453 |           },
    454 |           processUnknownColumns = function () {
    455 |             var cols = [],
    456 |               firstRowLength,
    457 |               finalRowLength,
    458 |               obj,
    459 |               prop,
    460 |               i,
    461 |               currentCol,
    462 |               len = arr.length,
    463 |               row,
    464 |               out = [];
    465 | 
    466 |             for (i = 0; i < len; i += 1) {
    467 |               obj = arr[i];
    468 |               row = [];
    469 | 
    470 |               // loop over all props in obj,
    471 |               for (prop in obj) {
    472 |                 if (obj.hasOwnProperty(prop)) {
    473 |                   currentCol = cols.indexOf(prop);
    474 |                   // if this prop does not have a column yet
    475 |                   if (currentCol === -1) {
    476 |                     currentCol = cols.push(prop);
    477 |                     currentCol -= 1;
    478 |                   }
    479 |                   row[currentCol] = prepField(obj[prop]);
    480 |                 }
    481 |               }
    482 | 
    483 |               if (i === 0) {
    484 |                 firstRowLength = row.length;
    485 |               }
    486 | 
    487 |               out.push(row);
    488 |             }
    489 | 
    490 |             finalRowLength = cols.length;
    491 | 
    492 |             // if some objects had properties that weren't on all the object
    493 |             // we need to resize each row.
    494 |             if (firstRowLength !== finalRowLength) {
    495 |               out.forEach(function (row) {
    496 |                 row.length = finalRowLength;
    497 |               });
    498 |             }
    499 | 
    500 |             // export cols to our parent scope so
    501 |             // includeColumns can use it
    502 |             columns = cols;
    503 | 
    504 |             return out.map(function (row) {
    505 |               return row.join(',');
    506 |             }).join('\n') + '\n';
    507 |           };
    508 | 
    509 |         includeColumns = includeColumns === undefined ? true : !!includeColumns;
    510 | 
    511 |         if (columns !== undefined) {
    512 |           csv = processKnownColumns();
    513 |         } else {
    514 |           csv = processUnknownColumns();
    515 |         }
    516 | 
    517 |         if (includeColumns) {
    518 |           columns.forEach(function (col) {
    519 |             csvColumns += prepField(col) + ',';
    520 |           });
    521 |           csvColumns = csvColumns.substring(0, csvColumns.length - 1);
    522 |           csv = csvColumns + '\n' + csv;
    523 |         }
    524 | 
    525 |         return csv;
    526 |       }
    527 |     };
    528 | 
    529 |     
    530 |
    531 | 532 |
    533 |
    534 |
    535 |
    536 |
    537 |
    538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | -------------------------------------------------------------------------------- /docs/files/source_intro.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | source\intro.js - ucsv 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 1.2.0 23 |
    24 |
    25 |
    26 | 27 |
    28 | 56 |
    57 |
    58 |
    59 | Show: 60 | 64 | 65 | 69 | 70 | 74 | 78 | 79 |
    80 | 81 | 82 |
    83 |
    84 |
    85 |

    File: source\intro.js

    86 | 87 |
    88 |
     89 | /*! %pkg.name% v%pkg.version% %build_date%
     90 |  * Copyright %copyright_date% %author%
     91 |  * Licensed %licenses%
     92 |  * %homepage%
     93 |  */
     94 | 
     95 | /* jsLint stuff */
     96 | /*global exports */
     97 | /*members arrayToCsv, csvToArray, csvToObject, objectToCsv, apply,
     98 |  charAt, length, prototype, push, replace, substring, test, toString,
     99 |  trim, columns, shift, map, includeColumns, hasOwnProperty, indexOf,
    100 |  forEach, join
    101 | */
    102 | 
    103 | /**
    104 |  * Namespace for CSV functions
    105 |  * @namespace
    106 |  */
    107 | var CSV = (function () {
    108 |   "use strict";
    109 | 
    110 |     
    111 |
    112 | 113 |
    114 |
    115 |
    116 |
    117 |
    118 |
    119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ucsv 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 1.2.0 23 |
    24 |
    25 |
    26 | 27 |
    28 | 56 |
    57 |
    58 |
    59 | Show: 60 | 64 | 65 | 69 | 70 | 74 | 78 | 79 |
    80 | 81 | 82 |
    83 |
    84 |
    85 |
    86 |
    87 |

    88 | Browse to a module or class using the sidebar to view its API documentation. 89 |

    90 | 91 |

    Keyboard Shortcuts

    92 | 93 |
      94 |
    • Press s to focus the API search box.

    • 95 | 96 |
    • Use Up and Down to select classes, modules, and search results.

    • 97 | 98 |
    • With the API search box or sidebar focused, use -Left or -Right to switch sidebar tabs.

    • 99 | 100 |
    • With the API search box or sidebar focused, use Ctrl+Left and Ctrl+Right to switch sidebar tabs.

    • 101 |
    102 |
    103 |
    104 | 105 | 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function (grunt) { 3 | "use strict"; 4 | 5 | var pkg = grunt.file.readJSON('package.json'), 6 | sourceDir = 'source/', 7 | baseName = pkg.name + '-' + pkg.version, 8 | concatenatedPath = 'dist/' + baseName + '.js', 9 | minifiedPath = 'dist/' + baseName + '.min.js', 10 | outputSrcDir = 'dist/<%= pkg.name %>_<%= pkg.version %>_src/', 11 | docDir = 'docs/', 12 | jshintGlobals = { 13 | //console: true, 14 | 'window': true, 15 | ok: true, 16 | test: true, 17 | strictEqual: true, 18 | deepEqual: true 19 | }, 20 | // quick-dirty copy obj 21 | jshintGlobalsBeforeConcat = JSON.parse(JSON.stringify(jshintGlobals)); 22 | 23 | // test.js needs to know about CSV 24 | jshintGlobalsBeforeConcat.CSV = true; 25 | 26 | 27 | // Project configuration. 28 | grunt.initConfig({ 29 | pkg: pkg, 30 | 31 | clean: { 32 | cleanBuild: ['dist', 'docs'], 33 | postBuild: { 34 | // Don't need the non-minified copy or .map for it 35 | src: [ 36 | concatenatedPath, 37 | concatenatedPath + '.map' 38 | ], 39 | }, 40 | removeMaps: [ 41 | outputSrcDir, 42 | minifiedPath + '.map' 43 | ] 44 | }, 45 | concat_sourcemap: { 46 | options: { 47 | }, 48 | main: { 49 | src: [outputSrcDir + 'intro.js', 50 | outputSrcDir + 'core.js', 51 | outputSrcDir + 'outro.js' 52 | ], 53 | dest: concatenatedPath 54 | } 55 | }, 56 | uglify: { 57 | options: { 58 | preserveComments: 'some' 59 | }, 60 | main: { 61 | options: { 62 | sourceMapIn: concatenatedPath + '.map', 63 | sourceMap: minifiedPath + '.map' 64 | }, 65 | src: concatenatedPath, 66 | dest: minifiedPath 67 | } 68 | }, 69 | 'regex-replace': { 70 | // concat_sourcemap doesn't seem to supports banners, so banner is in intro.js, 71 | // search/replace vars 72 | banner: { 73 | src: outputSrcDir + 'intro.js', 74 | actions: [ 75 | { 76 | search: '%pkg.name%', 77 | replace: '<%= pkg.name %>', 78 | flags: 'g' 79 | }, 80 | { 81 | search: '%pkg.version%', 82 | replace: '<%= pkg.version %>', 83 | flags: 'g' 84 | }, 85 | { 86 | search: '%build_date%', 87 | replace: '<%= grunt.template.today("yyyy-mm-dd") %>', 88 | flags: 'g' 89 | }, 90 | { 91 | search: '%copyright_date%', 92 | replace: '<%= grunt.template.today("yyyy") %>', 93 | flags: 'g' 94 | }, 95 | { 96 | search: '%author%', 97 | replace: '<%= pkg.author.name %>', 98 | flags: 'g' 99 | }, 100 | { 101 | search: '%licenses%', 102 | replace: '<%= _.pluck(pkg.licenses, "type").join(", ") %>', 103 | flags: 'g' 104 | }, 105 | { 106 | search: '%homepage%', 107 | replace: '<%= pkg.homepage %>', 108 | flags: 'g' 109 | } 110 | ] 111 | }, 112 | postMin: { 113 | src: [minifiedPath, 'dist/*.map'], 114 | actions: [ 115 | { 116 | search: 'dist/', 117 | replace: '', 118 | flags: 'g' 119 | }, 120 | { // right now Chrome seems to only support the old //@ syntax 121 | search: '//# sourceMappingURL=', 122 | replace: '//@ sourceMappingURL=', 123 | flags: 'g' 124 | } 125 | ] 126 | }, 127 | removeMaps: { 128 | src: [minifiedPath], 129 | actions: [ 130 | { 131 | search: '//.*sourceMappingURL=.*$', 132 | replace: '', 133 | flags: 'g' 134 | } 135 | ] 136 | }, 137 | test: { 138 | src: ['dist/test/tests.html'], 139 | actions: [ 140 | { 141 | search: '', 142 | replace: '' 143 | }, 144 | { 145 | search: /[^!]*/, 146 | replace: '', 147 | } 148 | ] 149 | } 150 | }, 151 | copy: { 152 | main: { 153 | expand: true, 154 | cwd: sourceDir, 155 | src: ['*.js'], 156 | dest: outputSrcDir, 157 | filter: 'isFile' 158 | }, 159 | test: { 160 | expand: true, 161 | cwd: 'test/', 162 | src: ['arrayToCsv.js', 'csvToArray.js', 'csvToObject.js', 'objectToCsv.js', 'lib/*', 'tests.html'], 163 | dest: 'dist/test/', 164 | filter: 'isFile' 165 | } 166 | }, 167 | qunit: { 168 | preBuild: ['test/**/*.html'], 169 | postBuild: ['dist/test/**/*.html'], 170 | }, 171 | compress: { 172 | options: { 173 | mode: 'gzip' 174 | }, 175 | main: { 176 | files: [ 177 | { 178 | src: minifiedPath, 179 | dest: minifiedPath + '.gz' 180 | }, 181 | { 182 | src: minifiedPath + '.map', 183 | dest: minifiedPath + '.map.gz' 184 | } 185 | ] 186 | } 187 | }, 188 | 189 | jshint: { 190 | options: { 191 | curly: true, 192 | eqeqeq: true, 193 | immed: true, 194 | latedef: true, 195 | newcap: true, 196 | noarg: true, 197 | sub: true, 198 | undef: true, 199 | boss: true, 200 | eqnull: true, 201 | trailing: true, 202 | indent: 2, 203 | white: true, 204 | globals: jshintGlobals 205 | }, 206 | beforeconcat: { 207 | options: { 208 | globals: jshintGlobalsBeforeConcat 209 | }, 210 | files: { 211 | src: ['gruntfile.js', 'test/*.js'] 212 | } 213 | }, 214 | afterconcat: [concatenatedPath] 215 | }, 216 | 217 | yuidoc: { 218 | compile: { 219 | name: '<%= pkg.name %>', 220 | description: '<%= pkg.description %>', 221 | version: '<%= pkg.version %>', 222 | url: '<%= pkg.homepage %>', 223 | options: { 224 | paths: sourceDir, 225 | //themedir: 'path/to/custom/theme/', 226 | outdir: docDir 227 | } 228 | } 229 | } 230 | }); 231 | 232 | grunt.loadNpmTasks('grunt-contrib-clean'); 233 | grunt.loadNpmTasks('grunt-contrib-copy'); 234 | grunt.loadNpmTasks('grunt-contrib-compress'); 235 | grunt.loadNpmTasks('grunt-contrib-uglify'); 236 | grunt.loadNpmTasks('grunt-contrib-qunit'); 237 | grunt.loadNpmTasks('grunt-contrib-jshint'); 238 | grunt.loadNpmTasks('grunt-concat-sourcemap'); 239 | grunt.loadNpmTasks('grunt-contrib-yuidoc'); 240 | grunt.loadNpmTasks('grunt-regex-replace'); 241 | 242 | // these tasks are common to the middle of all build types 243 | var buildCommon = ['copy', 'regex-replace:banner', 'concat_sourcemap', 'uglify', 'regex-replace:postMin', 'copy:test', 'regex-replace:test']; 244 | 245 | grunt.registerTask('keepconcat', ['jshint:beforeconcat', 'clean:cleanBuild', 'qunit:preBuild'].concat(buildCommon, ['jshint:afterconcat', 'yuidoc', 'qunit:postBuild'])); 246 | grunt.registerTask('default', ['keepconcat', 'clean:postBuild', 'regex-replace:removeMaps', 'clean:removeMaps']); 247 | grunt.registerTask('notest', ['clean:cleanBuild'].concat(buildCommon, ['clean:postBuild'])); 248 | grunt.registerTask('gz', ['keepconcat', 'clean:postBuild', 'compress']); 249 | 250 | grunt.registerTask('cleanup', ['clean:cleanBuild']); 251 | grunt.registerTask('test', ['qunit:preBuild']); 252 | grunt.registerTask('docs', ['yuidoc']); 253 | }; 254 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ucsv", 3 | "author": { 4 | "name": "Peter Johnson" 5 | }, 6 | "homepage": "https://github.com/uselesscode/ucsv", 7 | "version": "1.2.0", 8 | "licenses": [ 9 | { 10 | "type": "MIT", 11 | "url": "http://opensource.org/licenses/MIT" 12 | }, 13 | { 14 | "type": "GPL-3.0", 15 | "url": "http://opensource.org/licenses/GPL-3.0" 16 | } 17 | ], 18 | "devDependencies": { 19 | "grunt": "~0.4.1", 20 | "grunt-contrib-compress": "~0.5.1", 21 | "grunt-contrib-uglify": "~0.2.1", 22 | "grunt-contrib-qunit": "~0.2.2", 23 | "grunt-concat-sourcemap": "~0.2.2", 24 | "grunt-contrib-copy": "~0.4.1", 25 | "grunt-contrib-clean": "~0.4.1", 26 | "grunt-regex-replace": "~0.2.5", 27 | "grunt-contrib-yuidoc": "~0.5.0", 28 | "grunt-contrib-jshint": "~0.8.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Ucsv.js: A JavaScript CSV Library 2 | ======================================== 3 | 4 | UCSV is a small library for importing and exporting CSV into and out of 5 | ECMAScript programs. CSV text can be imported into a multi-dimensional array 6 | or an array of objects if column headings are available. These structures can 7 | also easily be output as CSV text. 8 | 9 | Features 10 | -------- 11 | * MIT, GLP3 dual licensed 12 | * Simple, namespaced API 13 | * Small (less than 1.5kb when minified and gzipped) 14 | * When exporting to CSV appropriate fields are automatically quoted 15 | * Optionally strip leading and trailing whitespace from fields 16 | * Proper support for quotes, commas and line-breaks in quoted fields 17 | * Use in browser or as a CommonJS module. 18 | 19 | Usage 20 | ----- 21 | Grab a copy of `ucsv-x.x.x.min.js` from the `dist/` directory and include it 22 | in your project. If you would like sourcemap support, you will need to build 23 | the library your self with the `grunt gz` command and then grab `ucsv-x.x.x.min.js.map` 24 | and the `ucsv_x.x.x_src` directory as well. 25 | 26 | 27 | Building Ucsv 28 | =============== 29 | ### Installing prerequisites 30 | * Install [node.js](http://nodejs.org/), this will also install [npm](https://npmjs.org/) 31 | * [Install grunt](http://gruntjs.com/getting-started) 32 | 33 | ### Getting/building Ucsv 34 | * Clone the Git repository `git clone https://github.com/uselesscode/ucsv.git` 35 | * In the cloned directory, run `npm install`, this will read `package.json` 36 | and install all of the dependencies needed to build ucsv. 37 | * Run `grunt` to build ucsv. 38 | 39 | 40 | Build Options 41 | -------- 42 | `grunt` will run tests, jshint and then build a minified copy of the 43 | library in `dist/` as well as documentation in `docs/`. 44 | 45 | `grunt gz` will do everything that the default command does but it will 46 | also generated .gz compressed versions of the library and .map file. 47 | 48 | `grunt test` will run the test suite on the source files without building. 49 | 50 | `grunt docs` will just generate documentation. 51 | 52 | `grunt notest` will build a copy of the library without linting or running tests 53 | 54 | `grunt keepconcat` the default build will delete the non-minified version of the 55 | concatenated source, keepconcat will not. 56 | 57 | `grunt cleanup` will remove the `dist` and `docs` directories. 58 | -------------------------------------------------------------------------------- /source/core.js: -------------------------------------------------------------------------------- 1 | var rxIsInt = /^\d+$/, 2 | rxIsFloat = /^\d*\.\d+$|^\d+\.\d*$/, 3 | // If a string has leading or trailing space, 4 | // contains a comma double quote or a newline 5 | // it needs to be quoted in CSV output 6 | rxNeedsQuoting = /^\s|\s$|,|"|\n/, 7 | trim = (function () { 8 | // Fx 3.1 has a native trim function, it's about 10x faster, use it if it exists 9 | if (String.prototype.trim) { 10 | return function (s) { 11 | return s.trim(); 12 | }; 13 | } 14 | return function (s) { 15 | return s.replace(/^\s*/, '').replace(/\s*$/, ''); 16 | }; 17 | }()), 18 | 19 | isNumber = function (o) { 20 | return Object.prototype.toString.apply(o) === '[object Number]'; 21 | }, 22 | 23 | isString = function (o) { 24 | return Object.prototype.toString.apply(o) === '[object String]'; 25 | }, 26 | 27 | chomp = function (s) { 28 | if (s.charAt(s.length - 1) !== "\n") { 29 | // Does not end with \n, just return string 30 | return s; 31 | } 32 | // Remove the \n 33 | return s.substring(0, s.length - 1); 34 | }, 35 | 36 | prepField = function (field) { 37 | if (isString(field)) { 38 | // Escape any " with double " ("") 39 | field = field.replace(/"/g, '""'); 40 | 41 | // If the field starts or ends with whitespace, contains " or , or a newline or 42 | // is a string representing a number, quote it. 43 | if (rxNeedsQuoting.test(field) || rxIsInt.test(field) || rxIsFloat.test(field)) { 44 | field = '"' + field + '"'; 45 | // quote empty strings 46 | } else if (field === "") { 47 | field = '""'; 48 | } 49 | } else if (isNumber(field)) { 50 | field = field.toString(10); 51 | } else if (field === null || field === undefined) { 52 | field = ''; 53 | } else { 54 | field = field.toString(); 55 | } 56 | return field; 57 | }, 58 | 59 | CSV = { 60 | /** 61 | Converts an array into a Comma Separated Values string. 62 | Each item in the array should be an array that represents one row in the CSV. 63 | Nulls and undefined values are interpreted as empty fields. 64 | 65 | @method arrayToCsv 66 | @param {String} a The array to convert 67 | 68 | @returns {String} A CSV representation of the provided array. 69 | @for CSV 70 | @public 71 | @static 72 | @example 73 | var csv, 74 | books = [ 75 | ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008], 76 | ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008], 77 | ['Effective JavaScript', 'Herman, David', 2012] 78 | ]; 79 | 80 | csv = CSV.arrayToCsv(books); 81 | 82 | // csv now contains: 83 | // 84 | // JavaScript: The Good Parts,"Crockford, Douglas",2008\n 85 | // Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n 86 | // Effective JavaScript,"Herman, David",2012\n 87 | */ 88 | arrayToCsv: function (a) { 89 | var cur, 90 | out = '', 91 | row, 92 | i, 93 | j; 94 | 95 | for (i = 0; i < a.length; i += 1) { 96 | row = a[i]; 97 | for (j = 0; j < row.length; j += 1) { 98 | cur = row[j]; 99 | 100 | cur = prepField(cur); 101 | 102 | out += j < row.length - 1 ? cur + ',' : cur; 103 | } 104 | // End record 105 | out += "\n"; 106 | } 107 | 108 | return out; 109 | }, 110 | 111 | /** 112 | Converts a Comma Separated Values string into a multi-dimensional array. 113 | Each row in the CSV becomes an array. 114 | Empty fields are converted to nulls and non-quoted numbers are converted to integers or floats. 115 | 116 | @method csvToArray 117 | @return {Array} The CSV parsed as an array 118 | @param {String} s The string to convert 119 | @param {Object} [config] Object literal with extra configuration. For historical reasons setting config to `true` is the same as passing `{trim: true}`, but this usage is deprecated and will likely be removed in the next version. 120 | @param {Boolean} [config.trim=false] If set to True leading and trailing whitespace is stripped off of each non-quoted field as it is imported 121 | @for CSV 122 | @static 123 | @example 124 | var books, 125 | csv = 'JavaScript: The Good Parts,"Crockford, Douglas",2008\n' + 126 | 'Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n' + 127 | 'Effective JavaScript,"Herman, David",2012\n'; 128 | 129 | books = CSV.csvToArray(csv); 130 | 131 | // books now equals: 132 | // [ 133 | // ['JavaScript: The Good Parts', 'Crockford, Douglas', 2008], 134 | // ['Object-Oriented JavaScript', 'Stefanov, Stoyan', 2008], 135 | // ['Effective JavaScript', 'Herman, David', 2012] 136 | // ]; 137 | */ 138 | csvToArray: function (s, config) { 139 | // Get rid of any trailing \n 140 | s = chomp(s); 141 | 142 | if (config === true) { 143 | config = { 144 | trim: true 145 | }; 146 | } else { 147 | config = config || {}; 148 | } 149 | 150 | var cur = '', // The character we are currently processing. 151 | inQuote = false, 152 | fieldQuoted = false, 153 | field = '', // Buffer for building up the current field 154 | row = [], 155 | out = [], 156 | trimIt = config.trim === true ? true : false, 157 | i, 158 | processField = function (field) { 159 | var trimmedField = trim(field); 160 | if (fieldQuoted !== true) { 161 | // If field is empty set to null 162 | if (field === '') { 163 | field = null; 164 | // If the field was not quoted and we are trimming fields, trim it 165 | } else if (trimIt === true) { 166 | field = trimmedField; 167 | } 168 | 169 | // Convert unquoted numbers to numbers 170 | if (rxIsInt.test(trimmedField) || rxIsFloat.test(trimmedField)) { 171 | field = +trimmedField; 172 | } 173 | } 174 | return field; 175 | }; 176 | 177 | for (i = 0; i < s.length; i += 1) { 178 | cur = s.charAt(i); 179 | 180 | // If we are at a EOF or EOR 181 | if (inQuote === false && (cur === ',' || cur === "\n")) { 182 | field = processField(field); 183 | // Add the current field to the current row 184 | row.push(field); 185 | // If this is EOR append row to output and flush row 186 | if (cur === "\n") { 187 | out.push(row); 188 | row = []; 189 | } 190 | // Flush the field buffer 191 | field = ''; 192 | fieldQuoted = false; 193 | } else { 194 | // If it's not a ", add it to the field buffer 195 | if (cur !== '"') { 196 | field += cur; 197 | } else { 198 | if (!inQuote) { 199 | // We are not in a quote, start a quote 200 | inQuote = true; 201 | fieldQuoted = true; 202 | } else { 203 | // Next char is ", this is an escaped " 204 | if (s.charAt(i + 1) === '"') { 205 | field += '"'; 206 | // Skip the next char 207 | i += 1; 208 | } else { 209 | // It's not escaping, so end quote 210 | inQuote = false; 211 | } 212 | } 213 | } 214 | } 215 | } 216 | 217 | // Add the last field 218 | field = processField(field); 219 | row.push(field); 220 | out.push(row); 221 | 222 | return out; 223 | }, 224 | /** 225 | Converts a Comma Separated Values string into an array of objects. 226 | Each row in the CSV becomes an object with properties named after each column. 227 | Empty fields are converted to nulls and non-quoted numbers are converted to integers or floats. 228 | 229 | @method csvToObject 230 | @since 1.2.0 231 | @return {Array} The CSV parsed as an array of objects 232 | @param {String} s The string containing CSV data to convert 233 | @param {Object} config Object literal with extra configuration 234 | @param {Array} [config.columns] An array containing the name of each column in the CSV data. If not 235 | provided, the first row of the CSV data is assumed to contain the column names. 236 | @param {Boolean} [config.trim] If true any field parsed from the CSV data will have leading and 237 | trailing whitespace trimmed 238 | @for CSV 239 | @static 240 | @example 241 | var books, 242 | csv = 'title,author,year\n' + 243 | 'JavaScript: The Good Parts,"Crockford, Douglas",2008\n' + 244 | 'Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n' + 245 | 'Effective JavaScript,"Herman, David",2012\n'; 246 | 247 | books = CSV.csvToObject(csv); 248 | 249 | // books now equals: 250 | // [ 251 | // { 252 | // title: 'JavaScript: The Good Parts', 253 | // author: 'Crockford, Douglas', 254 | // year: 2008 255 | // }, 256 | // { 257 | // title: 'Object-Oriented JavaScript', 258 | // author: 'Stefanov, Stoyan', 259 | // year: 2008 260 | // }, 261 | // { 262 | // title: 'Effective JavaScript', 263 | // author: 'Herman, David', 264 | // year: 2012 265 | // } 266 | // ]; 267 | */ 268 | csvToObject: function (s, config) { 269 | config = config !== undefined ? config : {}; 270 | var columns = config.columns, 271 | trimIt = !!config.trim, 272 | csvArray = this.csvToArray(s, trimIt); 273 | 274 | // if columns were not provided, assume they are 275 | // in the first row 276 | if (!columns) { 277 | columns = csvArray.shift(); 278 | } 279 | 280 | return csvArray.map(function (row) { 281 | var obj = {}, 282 | i = 0, 283 | len = columns.length; 284 | for (; i < len; i += 1) { 285 | obj[columns[i]] = row[i]; 286 | } 287 | return obj; 288 | }); 289 | }, 290 | 291 | /** 292 | Converts an array of objects into Comma Separated Values data 293 | Each propery on the objects becomes a column in the CSV data. 294 | 295 | @method objectToCsv 296 | @since 1.2.0 297 | @return {String} CSV data, each row representing an object from the input array, each field representing a property from those objects 298 | @param {String} arr An array of objects to be converted into CSV 299 | @param {Object} config Object literal with extra configuration 300 | @param {Array} [config.columns] An array containing the name of each column in the CSV data. If not 301 | provided, the column names will be inferred from the property names of the objects. Explicitly 302 | defining column names has several advantages: 303 | 304 | * It is faster since all column names are already known. 305 | * It allows you to specify a subset of the properties to use if you wish to. 306 | * It allows you to control what order the columns are output in, since the `for...in` statement used to infer field names does not guarantee a specific order. 307 | 308 | @param {Boolean} [config.includeColumns=true] By default `objectToCsv` outputs the column names as 309 | the first row of the CSV data. Set to false to prevent this. 310 | @for CSV 311 | @static 312 | @example 313 | var csv, 314 | books = [ 315 | { 316 | title: 'JavaScript: The Good Parts', 317 | author: 'Crockford, Douglas', 318 | year: 2008 319 | }, 320 | { 321 | title: 'Object-Oriented JavaScript', 322 | author: 'Stefanov, Stoyan', 323 | year: 2008 324 | }, 325 | { 326 | title: 'Effective JavaScript', 327 | author: 'Herman, David', 328 | year: 2012 329 | } 330 | ]; 331 | 332 | csv = CSV.objectToCsv(books); 333 | 334 | // csv now contains: 335 | // 336 | // title,author,year\n 337 | // JavaScript: The Good Parts,"Crockford, Douglas",2008\n 338 | // Object-Oriented JavaScript,"Stefanov, Stoyan",2008\n 339 | // Effective JavaScript,"Herman, David",2012\n 340 | */ 341 | objectToCsv: function (arr, config) { 342 | config = config !== undefined ? config : {}; 343 | var columns = config.columns, 344 | includeColumns = config.includeColumns, 345 | csv = '', 346 | csvColumns = '', 347 | processKnownColumns = function (obj) { 348 | var out = '', 349 | prop, 350 | i, 351 | len = arr.length, 352 | j, 353 | jlen = columns.length; 354 | 355 | for (i = 0; i < len; i += 1) { 356 | obj = arr[i]; 357 | for (j = 0; j < jlen; j += 1) { 358 | prop = columns[j]; 359 | out += prepField(obj[prop]); 360 | out += j < jlen - 1 ? ',' : ''; 361 | } 362 | out += '\n'; 363 | } 364 | return out; 365 | }, 366 | processUnknownColumns = function () { 367 | var cols = [], 368 | firstRowLength, 369 | finalRowLength, 370 | obj, 371 | prop, 372 | i, 373 | currentCol, 374 | len = arr.length, 375 | row, 376 | out = []; 377 | 378 | for (i = 0; i < len; i += 1) { 379 | obj = arr[i]; 380 | row = []; 381 | 382 | // loop over all props in obj, 383 | for (prop in obj) { 384 | if (obj.hasOwnProperty(prop)) { 385 | currentCol = cols.indexOf(prop); 386 | // if this prop does not have a column yet 387 | if (currentCol === -1) { 388 | currentCol = cols.push(prop); 389 | currentCol -= 1; 390 | } 391 | row[currentCol] = prepField(obj[prop]); 392 | } 393 | } 394 | 395 | if (i === 0) { 396 | firstRowLength = row.length; 397 | } 398 | 399 | out.push(row); 400 | } 401 | 402 | finalRowLength = cols.length; 403 | 404 | // if some objects had properties that weren't on all the object 405 | // we need to resize each row. 406 | if (firstRowLength !== finalRowLength) { 407 | out.forEach(function (row) { 408 | row.length = finalRowLength; 409 | }); 410 | } 411 | 412 | // export cols to our parent scope so 413 | // includeColumns can use it 414 | columns = cols; 415 | 416 | return out.map(function (row) { 417 | return row.join(','); 418 | }).join('\n') + '\n'; 419 | }; 420 | 421 | includeColumns = includeColumns === undefined ? true : !!includeColumns; 422 | 423 | if (columns !== undefined) { 424 | csv = processKnownColumns(); 425 | } else { 426 | csv = processUnknownColumns(); 427 | } 428 | 429 | if (includeColumns) { 430 | columns.forEach(function (col) { 431 | csvColumns += prepField(col) + ','; 432 | }); 433 | csvColumns = csvColumns.substring(0, csvColumns.length - 1); 434 | csv = csvColumns + '\n' + csv; 435 | } 436 | 437 | return csv; 438 | } 439 | }; 440 | -------------------------------------------------------------------------------- /source/intro.js: -------------------------------------------------------------------------------- 1 | /*! %pkg.name% v%pkg.version% %build_date% 2 | * Copyright %copyright_date% %author% 3 | * Licensed %licenses% 4 | * %homepage% 5 | */ 6 | 7 | /* jsLint stuff */ 8 | /*global exports */ 9 | /*members arrayToCsv, csvToArray, csvToObject, objectToCsv, apply, 10 | charAt, length, prototype, push, replace, substring, test, toString, 11 | trim, columns, shift, map, includeColumns, hasOwnProperty, indexOf, 12 | forEach, join 13 | */ 14 | 15 | /** 16 | * Namespace for CSV functions 17 | * @namespace 18 | */ 19 | var CSV = (function () { 20 | "use strict"; 21 | -------------------------------------------------------------------------------- /source/outro.js: -------------------------------------------------------------------------------- 1 | // Add support for use as a CommonJS module. 2 | if (typeof exports === "object") { 3 | exports.arrayToCsv = CSV.arrayToCsv; 4 | exports.csvToArray = CSV.csvToArray; 5 | exports.objectToCsv = CSV.objectToCsv; 6 | exports.csvToObject = CSV.csvToObject; 7 | } 8 | 9 | return CSV; 10 | }()); 11 | -------------------------------------------------------------------------------- /test/arrayToCsv.js: -------------------------------------------------------------------------------- 1 | /*global strictEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('arrayToCsv'); 5 | 6 | test('arrayToCsv strings', function () { 7 | var csvArray = [ 8 | ['XBOX "XBONE" One', 2013], 9 | ['Nintendo 64, AKA Nintendo Ultra 64', 1996], 10 | ['Playstation\n4', 2013] 11 | ], 12 | expected = '"XBOX ""XBONE"" One",2013\n' + 13 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 14 | '"Playstation\n4",2013\n', 15 | csv = CSV.arrayToCsv(csvArray); 16 | strictEqual(csv, expected, 'Outputted correct CSV'); 17 | }); 18 | 19 | test('arrayToCsv integers', function () { 20 | var csvArray = [[1, 2, 3], [4, 5, 6]], 21 | csv = CSV.arrayToCsv(csvArray), 22 | expected = '1,2,3\n4,5,6\n'; 23 | strictEqual(csv, expected, 'Outputted correct CSV'); 24 | }); 25 | 26 | test('arrayToCsv no trim', function () { 27 | var csvArray = [['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 ']], 28 | csv = CSV.arrayToCsv(csvArray), 29 | expected = 'no need to trim," should not trim 1","should not trim 2 "," should not trim 3 "\n'; 30 | strictEqual(csv, expected); 31 | }); 32 | 33 | test('arrayToCsv nulls are empty fields', function () { 34 | var csvArray = [["Tom", null, "Harry"]], 35 | csv = CSV.arrayToCsv(csvArray), 36 | expected = 'Tom,,Harry\n'; 37 | strictEqual(csv, expected); 38 | }); 39 | 40 | test('arrayToCsv undefined values are empty fields', function () { 41 | var csvArray = [["Tom", undefined, "Harry"]], 42 | csv = CSV.arrayToCsv(csvArray), 43 | expected = 'Tom,,Harry\n'; 44 | strictEqual(csv, expected); 45 | }); 46 | 47 | test('arrayToCsv integers and quoted integers', function () { 48 | var csvArray = [[1, 2, "3"]], 49 | csv = CSV.arrayToCsv(csvArray), 50 | expected = '1,2,"3"\n'; 51 | strictEqual(csv, expected); 52 | }); 53 | 54 | test('arrayToCsv floats and quoted floats', function () { 55 | var csvArray = [[1.5, 2.2, "3.14"]], 56 | csv = CSV.arrayToCsv(csvArray), 57 | expected = '1.5,2.2,"3.14"\n'; 58 | strictEqual(csv, expected); 59 | }); 60 | 61 | test('arrayToCsv empty strings are empty strings', function () { 62 | var csvArray = [["a", "", "b"]], 63 | csv = CSV.arrayToCsv(csvArray), 64 | expected = 'a,"",b\n'; 65 | strictEqual(csv, expected); 66 | }); 67 | 68 | test('arrayToCsv newline in string', function () { 69 | var csvArray = [["a", "b\nc", "d"]], 70 | csv = CSV.arrayToCsv(csvArray), 71 | expected = 'a,"b\nc",d\n'; 72 | strictEqual(csv, expected); 73 | }); 74 | }()); 75 | -------------------------------------------------------------------------------- /test/csvToArray.js: -------------------------------------------------------------------------------- 1 | /*global deepEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('csvToArray'); 5 | 6 | test('csvToArray strings', function () { 7 | var csv = '"XBOX ""XBONE"" One",2013\n' + 8 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 9 | '"Playstation\n4",2013\n', 10 | expected = [ 11 | ['XBOX "XBONE" One', 2013], 12 | ['Nintendo 64, AKA Nintendo Ultra 64', 1996], 13 | ['Playstation\n4', 2013] 14 | ], 15 | result = CSV.csvToArray(csv); 16 | deepEqual(result, expected); 17 | }); 18 | 19 | test('csvToArray integers', function () { 20 | var csv = '1,2,3\n4,5,6', 21 | expected = [ 22 | [1, 2, 3], 23 | [4, 5, 6] 24 | ], 25 | result = CSV.csvToArray(csv); 26 | 27 | deepEqual(result, expected); 28 | }); 29 | 30 | test('csvToArray no config', function () { 31 | var csv = 'no need to trim, should not trim 1,should not trim 2 , should not trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 32 | expected = [ 33 | ['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 '], 34 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 35 | ], 36 | result = CSV.csvToArray(csv); 37 | 38 | deepEqual(result, expected); 39 | }); 40 | 41 | test('csvToArray integers', function () { 42 | var csv = '1,2,3\n4,5,6', 43 | expected = [ 44 | [1, 2, 3], 45 | [4, 5, 6] 46 | ], 47 | result = CSV.csvToArray(csv); 48 | 49 | deepEqual(result, expected); 50 | }); 51 | 52 | test('csvToArray integers with trailing newline', function () { 53 | var csv = '1,2,3\n4,5,6\n', 54 | expected = [ 55 | [1, 2, 3], 56 | [4, 5, 6] 57 | ], 58 | result = CSV.csvToArray(csv); 59 | 60 | deepEqual(result, expected); 61 | }); 62 | 63 | test('csvToArray config === false', function () { 64 | var csv = 'no need to trim, should not trim 1,should not trim 2 , should not trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 65 | expected = [ 66 | ['no need to trim', ' should not trim 1', 'should not trim 2 ', ' should not trim 3 '], 67 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 68 | ], 69 | result = CSV.csvToArray(csv, false); 70 | deepEqual(result, expected); 71 | }); 72 | 73 | test('csvToArray config === true (legacy trim)', function () { 74 | var csv = 'no need to trim, should trim 1,should trim 2 , should trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 75 | expected = [ 76 | ['no need to trim', 'should trim 1', 'should trim 2', 'should trim 3'], 77 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 78 | ], 79 | result = CSV.csvToArray(csv, true); 80 | deepEqual(result, expected); 81 | }); 82 | 83 | test('csvToArray config trim', function () { 84 | var csv = 'no need to trim, should trim 1,should trim 2 , should trim 3 \n"quoted 1"," quoted 2","quoted 3 "," quoted 4 "', 85 | expected = [ 86 | ['no need to trim', 'should trim 1', 'should trim 2', 'should trim 3'], 87 | ['quoted 1', ' quoted 2', 'quoted 3 ', ' quoted 4 '] 88 | ], 89 | result = CSV.csvToArray(csv, {trim: true}); 90 | deepEqual(result, expected); 91 | }); 92 | 93 | test('csvToArray empty fields are null', function () { 94 | var csv = 'Billy West, Fry\nDavid X. Cohen,\nJohn Di Maggio,Bender', 95 | expected = [ 96 | ['Billy West', 'Fry'], 97 | ['David X. Cohen', null], 98 | ['John Di Maggio', 'Bender'] 99 | ], 100 | result = CSV.csvToArray(csv, true); 101 | 102 | deepEqual(result, expected); 103 | }); 104 | 105 | test('csvToArray integers and quoted integers', function () { 106 | var csv = '1,2,"3"', 107 | expected = [ 108 | [1, 2, '3'] 109 | ], 110 | result = CSV.csvToArray(csv, true); 111 | deepEqual(result, expected); 112 | }); 113 | 114 | test('csvToArray floats and quoted floats', function () { 115 | var csv = '1.5,2.2,"3.14"', 116 | expected = [ 117 | [1.5, 2.2, '3.14'] 118 | ], 119 | result = CSV.csvToArray(csv, true); 120 | 121 | deepEqual(result, expected); 122 | }); 123 | 124 | test('csvToArray numbers are interpreted as numbers even when not trimming fields', function () { 125 | var csv = ' 1 , 2, 3.14', 126 | expected = [ 127 | [1, 2, 3.14] 128 | ], 129 | result = CSV.csvToArray(csv, true); 130 | ok(Array.isArray(result), 'Result is an array'); 131 | deepEqual(result, expected); 132 | }); 133 | 134 | test('csvToArray newline in string', function () { 135 | var csv = 'a,"b\nc",d', 136 | expected = [ 137 | ['a', 'b\nc', 'd'] 138 | ], 139 | result = CSV.csvToArray(csv, true); 140 | deepEqual(result, expected); 141 | }); 142 | }()); 143 | -------------------------------------------------------------------------------- /test/csvToObject.js: -------------------------------------------------------------------------------- 1 | /*global deepEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('csvToObject'); 5 | // All the actual parsing is done by csvToArray, so these tests do not thoroughly cover all aspects 6 | // of the parsing, only things particular to csvToObject since the other details of parsing are already 7 | // tested in the tests for csvToArray. 8 | 9 | test('csvToObject explicit headings, no trim', function () { 10 | var headings = [' console ', 'introduced'], 11 | csv = 'XBOX , 2001\n' + 12 | 'Nintendo 64,1996\n' + 13 | ' Playstation,1994\n', 14 | expected = [ 15 | { 16 | ' console ': 'XBOX ', 17 | 'introduced': 2001, 18 | }, 19 | { 20 | ' console ': 'Nintendo 64', 21 | 'introduced': 1996 22 | }, 23 | { 24 | ' console ': ' Playstation', 25 | 'introduced': 1994 26 | } 27 | ], 28 | result = CSV.csvToObject(csv, {columns: headings}); 29 | 30 | deepEqual(result, expected); 31 | }); 32 | 33 | test('csvToObject implicit headings, no trim', function () { 34 | var csv = ' console ,introduced\n' + 35 | 'XBOX , 2001\n' + 36 | 'Nintendo 64,1996\n' + 37 | ' Playstation,1994\n', 38 | expected = [ 39 | { 40 | ' console ': 'XBOX ', 41 | 'introduced': 2001, 42 | }, 43 | { 44 | ' console ': 'Nintendo 64', 45 | 'introduced': 1996 46 | }, 47 | { 48 | ' console ': ' Playstation', 49 | 'introduced': 1994 50 | } 51 | ], 52 | result = CSV.csvToObject(csv); 53 | 54 | deepEqual(result, expected); 55 | }); 56 | 57 | test('csvToObject explicit headings with trim', function () { 58 | var headings = [' console ', 'introduced'], 59 | csv = 'XBOX , 2001\n' + 60 | 'Nintendo 64,1996\n' + 61 | ' Playstation,1994\n', 62 | expected = [ 63 | { 64 | ' console ': 'XBOX', 65 | 'introduced': 2001, 66 | }, 67 | { 68 | ' console ': 'Nintendo 64', 69 | 'introduced': 1996 70 | }, 71 | { 72 | ' console ': 'Playstation', 73 | 'introduced': 1994 74 | } 75 | ], 76 | result = CSV.csvToObject(csv, {columns: headings, trim: true}); 77 | 78 | deepEqual(result, expected); 79 | }); 80 | 81 | test('csvToObject implicit headings', function () { 82 | var csv = ' console , introduced\n' + 83 | 'XBOX , 2001\n' + 84 | 'Nintendo 64,1996\n' + 85 | ' Playstation,1994\n', 86 | expected = [ 87 | { 88 | 'console': 'XBOX', 89 | 'introduced': 2001, 90 | }, 91 | { 92 | 'console': 'Nintendo 64', 93 | 'introduced': 1996 94 | }, 95 | { 96 | 'console': 'Playstation', 97 | 'introduced': 1994 98 | } 99 | ], 100 | result = CSV.csvToObject(csv, {trim: true}); 101 | 102 | deepEqual(result, expected); 103 | }); 104 | }()); 105 | -------------------------------------------------------------------------------- /test/internal.js: -------------------------------------------------------------------------------- 1 | /*globals chomp, module */ 2 | module('Internal functions'); 3 | 4 | test('chomp with no new line', function () { 5 | var chompped = chomp('foo\nbar'); 6 | strictEqual(chompped, 'foo\nbar'); 7 | }); 8 | 9 | test('chomp with new line', function () { 10 | var chompped = chomp('foo\nbar\n'); 11 | strictEqual(chompped, 'foo\nbar'); 12 | }); 13 | -------------------------------------------------------------------------------- /test/lib/qunit-1.13.0.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * QUnit 1.13.0 3 | * http://qunitjs.com/ 4 | * 5 | * Copyright 2013 jQuery Foundation and other contributors 6 | * Released under the MIT license 7 | * http://jquery.org/license 8 | * 9 | * Date: 2014-01-04T17:09Z 10 | */ 11 | 12 | /** Font Family and Sizes */ 13 | 14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 16 | } 17 | 18 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 19 | #qunit-tests { font-size: smaller; } 20 | 21 | 22 | /** Resets */ 23 | 24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | 30 | /** Header */ 31 | 32 | #qunit-header { 33 | padding: 0.5em 0 0.5em 1em; 34 | 35 | color: #8699a4; 36 | background-color: #0d3349; 37 | 38 | font-size: 1.5em; 39 | line-height: 1em; 40 | font-weight: normal; 41 | 42 | border-radius: 5px 5px 0 0; 43 | -moz-border-radius: 5px 5px 0 0; 44 | -webkit-border-top-right-radius: 5px; 45 | -webkit-border-top-left-radius: 5px; 46 | } 47 | 48 | #qunit-header a { 49 | text-decoration: none; 50 | color: #c2ccd1; 51 | } 52 | 53 | #qunit-header a:hover, 54 | #qunit-header a:focus { 55 | color: #fff; 56 | } 57 | 58 | #qunit-testrunner-toolbar label { 59 | display: inline-block; 60 | padding: 0 .5em 0 .1em; 61 | } 62 | 63 | #qunit-banner { 64 | height: 5px; 65 | } 66 | 67 | #qunit-testrunner-toolbar { 68 | padding: 0.5em 0 0.5em 2em; 69 | color: #5E740B; 70 | background-color: #eee; 71 | overflow: hidden; 72 | } 73 | 74 | #qunit-userAgent { 75 | padding: 0.5em 0 0.5em 2.5em; 76 | background-color: #2b81af; 77 | color: #fff; 78 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 79 | } 80 | 81 | #qunit-modulefilter-container { 82 | float: right; 83 | } 84 | 85 | /** Tests: Pass/Fail */ 86 | 87 | #qunit-tests { 88 | list-style-position: inside; 89 | } 90 | 91 | #qunit-tests li { 92 | padding: 0.4em 0.5em 0.4em 2.5em; 93 | border-bottom: 1px solid #fff; 94 | list-style-position: inside; 95 | } 96 | 97 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 98 | display: none; 99 | } 100 | 101 | #qunit-tests li strong { 102 | cursor: pointer; 103 | } 104 | 105 | #qunit-tests li a { 106 | padding: 0.5em; 107 | color: #c2ccd1; 108 | text-decoration: none; 109 | } 110 | #qunit-tests li a:hover, 111 | #qunit-tests li a:focus { 112 | color: #000; 113 | } 114 | 115 | #qunit-tests li .runtime { 116 | float: right; 117 | font-size: smaller; 118 | } 119 | 120 | .qunit-assert-list { 121 | margin-top: 0.5em; 122 | padding: 0.5em; 123 | 124 | background-color: #fff; 125 | 126 | border-radius: 5px; 127 | -moz-border-radius: 5px; 128 | -webkit-border-radius: 5px; 129 | } 130 | 131 | .qunit-collapsed { 132 | display: none; 133 | } 134 | 135 | #qunit-tests table { 136 | border-collapse: collapse; 137 | margin-top: .2em; 138 | } 139 | 140 | #qunit-tests th { 141 | text-align: right; 142 | vertical-align: top; 143 | padding: 0 .5em 0 0; 144 | } 145 | 146 | #qunit-tests td { 147 | vertical-align: top; 148 | } 149 | 150 | #qunit-tests pre { 151 | margin: 0; 152 | white-space: pre-wrap; 153 | word-wrap: break-word; 154 | } 155 | 156 | #qunit-tests del { 157 | background-color: #e0f2be; 158 | color: #374e0c; 159 | text-decoration: none; 160 | } 161 | 162 | #qunit-tests ins { 163 | background-color: #ffcaca; 164 | color: #500; 165 | text-decoration: none; 166 | } 167 | 168 | /*** Test Counts */ 169 | 170 | #qunit-tests b.counts { color: black; } 171 | #qunit-tests b.passed { color: #5E740B; } 172 | #qunit-tests b.failed { color: #710909; } 173 | 174 | #qunit-tests li li { 175 | padding: 5px; 176 | background-color: #fff; 177 | border-bottom: none; 178 | list-style-position: inside; 179 | } 180 | 181 | /*** Passing Styles */ 182 | 183 | #qunit-tests li li.pass { 184 | color: #3c510c; 185 | background-color: #fff; 186 | border-left: 10px solid #C6E746; 187 | } 188 | 189 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 190 | #qunit-tests .pass .test-name { color: #366097; } 191 | 192 | #qunit-tests .pass .test-actual, 193 | #qunit-tests .pass .test-expected { color: #999999; } 194 | 195 | #qunit-banner.qunit-pass { background-color: #C6E746; } 196 | 197 | /*** Failing Styles */ 198 | 199 | #qunit-tests li li.fail { 200 | color: #710909; 201 | background-color: #fff; 202 | border-left: 10px solid #EE5757; 203 | white-space: pre; 204 | } 205 | 206 | #qunit-tests > li:last-child { 207 | border-radius: 0 0 5px 5px; 208 | -moz-border-radius: 0 0 5px 5px; 209 | -webkit-border-bottom-right-radius: 5px; 210 | -webkit-border-bottom-left-radius: 5px; 211 | } 212 | 213 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 214 | #qunit-tests .fail .test-name, 215 | #qunit-tests .fail .module-name { color: #000000; } 216 | 217 | #qunit-tests .fail .test-actual { color: #EE5757; } 218 | #qunit-tests .fail .test-expected { color: green; } 219 | 220 | #qunit-banner.qunit-fail { background-color: #EE5757; } 221 | 222 | 223 | /** Result */ 224 | 225 | #qunit-testresult { 226 | padding: 0.5em 0.5em 0.5em 2.5em; 227 | 228 | color: #2b81af; 229 | background-color: #D2E0E6; 230 | 231 | border-bottom: 1px solid white; 232 | } 233 | #qunit-testresult .module-name { 234 | font-weight: bold; 235 | } 236 | 237 | /** Fixture */ 238 | 239 | #qunit-fixture { 240 | position: absolute; 241 | top: -10000px; 242 | left: -10000px; 243 | width: 1000px; 244 | height: 1000px; 245 | } 246 | -------------------------------------------------------------------------------- /test/objectToCsv.js: -------------------------------------------------------------------------------- 1 | /*global strictEqual, module */ 2 | (function () { 3 | "use strict"; 4 | module('objectToCsv'); 5 | 6 | test('objectToCsv explicit headings', function () { 7 | var headings = ['console', 'introduced'], 8 | objs = [ 9 | { 10 | 'console': 'XBOX', 11 | 'introduced': 2001, 12 | }, 13 | { 14 | 'console': 'Nintendo 64', 15 | 'introduced': 1996 16 | }, 17 | { 18 | 'console': 'Playstation', 19 | 'introduced': 1994 20 | } 21 | ], 22 | expected = 'console,introduced\n' + 23 | 'XBOX,2001\n' + 24 | 'Nintendo 64,1996\n' + 25 | 'Playstation,1994\n', 26 | result = CSV.objectToCsv(objs, {columns: headings}); 27 | 28 | strictEqual(result, expected); 29 | }); 30 | 31 | test('objectToCsv implicit headings', function () { 32 | var objs = [ 33 | { 34 | 'console': 'XBOX', 35 | 'introduced': 2001, 36 | }, 37 | { 38 | 'console': 'Nintendo 64', 39 | 'introduced': 1996 40 | }, 41 | { 42 | 'console': 'Playstation', 43 | 'introduced': 1994 44 | } 45 | ], 46 | expected = 'console,introduced\n' + 47 | 'XBOX,2001\n' + 48 | 'Nintendo 64,1996\n' + 49 | 'Playstation,1994\n', 50 | result = CSV.objectToCsv(objs); 51 | 52 | strictEqual(result, expected); 53 | }); 54 | 55 | test('objectToCsv implicit headings, missing and extra fields', function () { 56 | var objs = [ 57 | { 58 | 'console': 'XBOX', 59 | 'introduced': 2001, 60 | }, 61 | { 62 | 'console': 'Nintendo 64', 63 | 'discontinued': 2003 64 | }, 65 | { 66 | 'console': 'Playstation', 67 | 'introduced': 1994 68 | } 69 | ], 70 | expected = 'console,introduced,discontinued\n' + 71 | 'XBOX,2001,\n' + 72 | 'Nintendo 64,,2003\n' + 73 | 'Playstation,1994,\n', 74 | result = CSV.objectToCsv(objs); 75 | 76 | strictEqual(result, expected); 77 | }); 78 | 79 | test('objectToCsv explicit headings, missing and extra fields', function () { 80 | var headings = ['console', 'introduced'], 81 | objs = [ 82 | { 83 | 'console': 'XBOX', 84 | 'introduced': 2001, 85 | }, 86 | { 87 | 'console': 'Nintendo 64', 88 | 'discontinued': 2003 89 | }, 90 | { 91 | 'console': 'Playstation', 92 | 'introduced': 1994 93 | } 94 | ], 95 | expected = 'console,introduced\n' + 96 | 'XBOX,2001\n' + 97 | 'Nintendo 64,\n' + 98 | 'Playstation,1994\n', 99 | result = CSV.objectToCsv(objs, {columns: headings}); 100 | 101 | strictEqual(result, expected); 102 | }); 103 | 104 | test('objectToCsv with includeColumns = true', function () { 105 | var headings = ['console', 'introduced'], 106 | objs = [ 107 | { 108 | 'console': 'XBOX', 109 | 'introduced': 2001, 110 | }, 111 | { 112 | 'console': 'Nintendo 64', 113 | 'introduced': 1996 114 | }, 115 | { 116 | 'console': 'Playstation', 117 | 'introduced': 1994 118 | } 119 | ], 120 | expected = 'console,introduced\n' + 121 | 'XBOX,2001\n' + 122 | 'Nintendo 64,1996\n' + 123 | 'Playstation,1994\n', 124 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: true}); 125 | 126 | strictEqual(result, expected); 127 | }); 128 | 129 | test('objectToCsv with includeColumns = false', function () { 130 | var headings = ['console', 'introduced'], 131 | objs = [ 132 | { 133 | 'console': 'XBOX', 134 | 'introduced': 2001, 135 | }, 136 | { 137 | 'console': 'Nintendo 64', 138 | 'introduced': 1996 139 | }, 140 | { 141 | 'console': 'Playstation', 142 | 'introduced': 1994 143 | } 144 | ], 145 | expected = 'XBOX,2001\n' + 146 | 'Nintendo 64,1996\n' + 147 | 'Playstation,1994\n', 148 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: false}); 149 | 150 | strictEqual(result, expected); 151 | }); 152 | 153 | test('objectToCsv with commas double quotes and newlines', function () { 154 | var headings = ['console', 'introduced'], 155 | objs = [ 156 | { 157 | 'console': 'XBOX "XBONE" One', 158 | 'introduced': 2013, 159 | }, 160 | { 161 | 'console': 'Nintendo 64, AKA Nintendo Ultra 64', 162 | 'introduced': 1996 163 | }, 164 | { 165 | 'console': 'Playstation\n4', 166 | 'introduced': 2013 167 | } 168 | ], 169 | expected = '"XBOX ""XBONE"" One",2013\n' + 170 | '"Nintendo 64, AKA Nintendo Ultra 64",1996\n' + 171 | '"Playstation\n4",2013\n', 172 | result = CSV.objectToCsv(objs, {columns: headings, includeColumns: false}); 173 | 174 | strictEqual(result, expected); 175 | }); 176 | }()); 177 | -------------------------------------------------------------------------------- /test/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Example 6 | 7 | 8 | 9 |
    10 |
    11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------