Browse Source

Updated docs and code for 3.1

pull/89/head
Matthew Holt 11 years ago
parent
commit
15af8981c6
  1. 2
      demo.html
  2. 11
      docs.html
  3. 4
      faq.html
  4. 2
      index.html
  5. 109
      resources/js/papaparse.js

2
demo.html

@ -41,7 +41,7 @@
<a href="https://github.com/mholt/PapaParse/issues"> <a href="https://github.com/mholt/PapaParse/issues">
<i class="fa fa-bug fa-lg"></i> Issues <i class="fa fa-bug fa-lg"></i> Issues
</a> </a>
<a href="https://www.gittip.com/mholt/" class="donate"> <a href="https://www.gratipay.com/mholt/" class="donate">
<i class="fa fa-heart fa-lg"></i> Donate <i class="fa fa-heart fa-lg"></i> Donate
</a> </a>
</div> </div>

11
docs.html

@ -39,7 +39,7 @@
<a href="https://github.com/mholt/PapaParse/issues"> <a href="https://github.com/mholt/PapaParse/issues">
<i class="fa fa-bug fa-lg"></i> Issues <i class="fa fa-bug fa-lg"></i> Issues
</a> </a>
<a href="https://www.gittip.com/mholt/" class="donate"> <a href="https://www.gratipay.com/mholt/" class="donate">
<i class="fa fa-heart fa-lg"></i> Donate <i class="fa fa-heart fa-lg"></i> Donate
</a> </a>
</div> </div>
@ -329,11 +329,11 @@ var csv = Papa.unparse({
<li><code>preview</code> If > 0, only that many rows will be parsed.</li> <li><code>preview</code> If > 0, only that many rows will be parsed.</li>
<li> <li>
<code>step</code> To <a href="faq.html#streaming">stream</a> the input, define a callback function to receive <a href="#results">results</a> row-by-row rather than together at the end: <code>step</code> To <a href="faq.html#streaming">stream</a> the input, define a callback function to receive <a href="#results">results</a> row-by-row rather than together at the end:
<code class="block">step: function(results, parser) { <code class="block">step: function(results, handle) {
console.log("Row data:", results.data); console.log("Row data:", results.data);
console.log("Row errors:", results.errors); console.log("Row errors:", results.errors);
}</code> }</code>
You can call <code>parser.abort()</code> to halt parsing that input (not available if using a worker). Except when using a worker, you can call <code>handle.abort()</code> to stop parsing, <code>handle.pause()</code> to pause it, or <code>handle.resume()</code> to resume.
</li> </li>
</ul> </ul>
</div> </div>
@ -468,6 +468,7 @@ var csv = Papa.unparse({
delimiter: <span class="comment">// Delimiter used</span> delimiter: <span class="comment">// Delimiter used</span>
aborted: <span class="comment">// Whether process was aborted</span> aborted: <span class="comment">// Whether process was aborted</span>
fields: <span class="comment">// Array of field names</span> fields: <span class="comment">// Array of field names</span>
truncated: <span class="comment">// Whether preview consumed all input</span>
}</code> }</code>
</div> </div>
<div class="grid-50"> <div class="grid-50">
@ -546,6 +547,10 @@ var csv = Papa.unparse({
<code>Papa.RemoteChunkSize</code> &nbsp; <code>Papa.RemoteChunkSize</code> &nbsp;
Same as LocalChunkSize, but for downloading files from remote locations. Default 5 MB. Same as LocalChunkSize, but for downloading files from remote locations. Default 5 MB.
</li> </li>
<li>
<code>Papa.DefaultDelimiter</code> &nbsp;
The delimiter used when one is not specified and it cannot be detected automatically. Default is comma <code>","</code>.
</li>
</div> </div>
<div class="grid-50"> <div class="grid-50">
<p> <p>

4
faq.html

@ -39,7 +39,7 @@
<a href="https://github.com/mholt/PapaParse/issues"> <a href="https://github.com/mholt/PapaParse/issues">
<i class="fa fa-bug fa-lg"></i> Issues <i class="fa fa-bug fa-lg"></i> Issues
</a> </a>
<a href="https://www.gittip.com/mholt/" class="donate"> <a href="https://www.gratipay.com/mholt/" class="donate">
<i class="fa fa-heart fa-lg"></i> Donate <i class="fa fa-heart fa-lg"></i> Donate
</a> </a>
</div> </div>
@ -87,7 +87,7 @@
<h4>Is it open source? (Can I contribute something?)</h4> <h4>Is it open source? (Can I contribute something?)</h4>
<p> <p>
Yes, please! I don't want to do this all by myself. Head over to the <a href="https://github.com/mholt/PapaParse">GitHub project page</a> and hack away. Yes, please! I don't want to do this all by myself. Head over to the <a href="https://github.com/mholt/PapaParse">GitHub project page</a> and hack away. If you're making a significant change, open an issue first so we can talk about it.
</p> </p>

2
index.html

@ -48,7 +48,7 @@
<a href="https://github.com/mholt/PapaParse/issues"> <a href="https://github.com/mholt/PapaParse/issues">
<i class="fa fa-bug fa-lg"></i> Issues <i class="fa fa-bug fa-lg"></i> Issues
</a> </a>
<a href="https://www.gittip.com/mholt/" class="donate"> <a href="https://www.gratipay.com/mholt/" class="donate">
<i class="fa fa-heart fa-lg"></i> Donate <i class="fa fa-heart fa-lg"></i> Donate
</a> </a>
</div> </div>

109
resources/js/papaparse.js

@ -1,6 +1,6 @@
/* /*
Papa Parse Papa Parse
v3.0.1 v3.1.0
https://github.com/mholt/PapaParse https://github.com/mholt/PapaParse
*/ */
(function(global) (function(global)
@ -21,6 +21,7 @@
worker: false, worker: false,
comments: false, comments: false,
complete: undefined, complete: undefined,
error: undefined,
download: false, download: false,
chunk: undefined, chunk: undefined,
keepEmptyRows: false keepEmptyRows: false
@ -40,6 +41,7 @@
// Configurable chunk sizes for local and remote files, respectively // Configurable chunk sizes for local and remote files, respectively
global.Papa.LocalChunkSize = 1024 * 1024 * 10; // 10 MB global.Papa.LocalChunkSize = 1024 * 1024 * 10; // 10 MB
global.Papa.RemoteChunkSize = 1024 * 1024 * 5; // 5 MB global.Papa.RemoteChunkSize = 1024 * 1024 * 5; // 5 MB
global.Papa.DefaultDelimiter = ","; // Used if not specified and detection fails
// Exposed for testing and development only // Exposed for testing and development only
global.Papa.Parser = Parser; global.Papa.Parser = Parser;
@ -81,11 +83,7 @@
function parseNextFile() function parseNextFile()
{ {
if (queue.length == 0) if (queue.length == 0)
{
if (isFunction(options.complete))
options.complete();
return; return;
}
var f = queue[0]; var f = queue[0];
@ -189,8 +187,6 @@
{ {
var ph = new ParserHandle(config); var ph = new ParserHandle(config);
var results = ph.parse(_input); var results = ph.parse(_input);
if (isFunction(config.complete))
config.complete(results);
return results; return results;
} }
} }
@ -218,8 +214,6 @@
{ {
var ph = new ParserHandle(config); var ph = new ParserHandle(config);
var results = ph.parse(event.target.result); var results = ph.parse(event.target.result);
if (isFunction(config.complete))
config.complete(results);
}; };
reader.onerror = function() reader.onerror = function()
{ {
@ -364,7 +358,7 @@
// Encloses a value around quotes if needed (makes a value safe for CSV insertion) // Encloses a value around quotes if needed (makes a value safe for CSV insertion)
function safe(str, col) function safe(str, col)
{ {
if (typeof str === "undefined") if (typeof str === "undefined" || str === null)
return ""; return "";
str = str.toString().replace(/"/g, '""'); str = str.toString().replace(/"/g, '""');
@ -390,7 +384,7 @@
// NOTE/TODO: Many of the functions of NetworkStreamer and FileStreamer are the same. Consolidate? // TODO: Many of the functions of NetworkStreamer and FileStreamer are similar or the same. Consolidate?
function NetworkStreamer(config) function NetworkStreamer(config)
{ {
config = config || {}; config = config || {};
@ -498,15 +492,11 @@
} }
else if (isFunction(config.chunk)) else if (isFunction(config.chunk))
{ {
config.chunk(results); // TODO: Implement abort? (like step) config.chunk(results);
results = undefined; results = undefined;
} }
if (finishedWithEntireFile && isFunction(config.complete)) if (!finishedWithEntireFile && !results.meta.paused)
config.complete(results);
else if (results && results.meta.aborted && isFunction(config.complete))
config.complete(results);
else if (!finishedWithEntireFile)
nextChunk(); nextChunk();
} }
@ -634,11 +624,7 @@
results = undefined; results = undefined;
} }
if (finishedWithEntireFile && isFunction(config.complete)) if (!finishedWithEntireFile && !results.meta.paused)
config.complete(undefined, file);
else if (results && results.meta.aborted && isFunction(config.complete)) // TODO: Abort needs reworking like pause/resume need it (if streaming, no results object is returned, so it has no meta to say aborted: true...)
config.complete(results, file);
else if (!finishedWithEntireFile)
nextChunk(); nextChunk();
} }
@ -669,6 +655,10 @@
// One goal is to minimize the use of regular expressions... // One goal is to minimize the use of regular expressions...
var FLOAT = /^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i; var FLOAT = /^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i;
var self = this;
var _input; // The input being parsed
var _parser; // The core parser being used
var _paused = false; // Whether we are paused or not
var _delimiterError; // Temporary state between delimiter detection and processing results var _delimiterError; // Temporary state between delimiter detection and processing results
var _fields = []; // Fields are from the header row of the input, if there is one var _fields = []; // Fields are from the header row of the input, if there is one
var _results = { // The last results returned from the parser var _results = { // The last results returned from the parser
@ -689,7 +679,7 @@
else else
{ {
_delimiterError = true; // add error after parsing (otherwise it would be overwritten) _delimiterError = true; // add error after parsing (otherwise it would be overwritten)
_config.delimiter = ","; _config.delimiter = Papa.DefaultDelimiter;
} }
_results.meta.delimiter = _config.delimiter; _results.meta.delimiter = _config.delimiter;
} }
@ -697,25 +687,57 @@
if (isFunction(_config.step)) if (isFunction(_config.step))
{ {
var userStep = _config.step; var userStep = _config.step;
_config.step = function(results, parser) _config.step = function(results)
{ {
_results = results; _results = results;
if (needsHeaderRow()) if (needsHeaderRow())
processResults(); processResults();
else else
userStep(processResults(), parser); userStep(processResults(), self);
}; };
} }
_results = new Parser(_config).parse(input); if (_config.preview && _config.header)
return processResults(); _config.preview++; // to compensate for header row
_input = input;
_parser = new Parser(_config);
_results = _parser.parse(_input);
processResults();
if (isFunction(_config.complete) && !_paused)
_config.complete(_results);
return _paused ? { meta: { paused: true } } : _results;
}; };
this.pause = function()
{
_paused = true;
_parser.abort();
_input = _input.substr(_parser.getCharIndex());
};
this.resume = function()
{
_paused = false;
_parser = new Parser(_config);
_parser.parse(_input);
if (isFunction(_config.complete) && !_paused)
_config.complete(_results);
};
this.abort = function()
{
_parser.abort();
if (isFunction(_config.complete))
_config.complete(_results);
_input = "";
}
function processResults() function processResults()
{ {
if (_results && _delimiterError) if (_results && _delimiterError)
{ {
addError("Delimiter", "UndetectableDelimiter", "Unable to auto-detect delimiting character; defaulted to comma"); addError("Delimiter", "UndetectableDelimiter", "Unable to auto-detect delimiting character; defaulted to '"+Papa.DefaultDelimiter+"'");
_delimiterError = false; _delimiterError = false;
} }
@ -869,7 +891,6 @@
function Parser(config) function Parser(config)
{ {
var self = this;
var EMPTY = /^\s*$/; var EMPTY = /^\s*$/;
var _input; // The input text being parsed var _input; // The input text being parsed
@ -888,7 +909,6 @@
var _colIdx; // Current col index within result row (0-based) var _colIdx; // Current col index within result row (0-based)
var _runningRowIdx; // Cumulative row index, used by the preview feature var _runningRowIdx; // Cumulative row index, used by the preview feature
var _aborted = false; // Abort flag var _aborted = false; // Abort flag
var _paused = false; // Pause flag
// Unpack the config object // Unpack the config object
config = config || {}; config = config || {};
@ -920,34 +940,23 @@
reset(input); reset(input);
return parserLoop(); return parserLoop();
}; };
/*
// TODO: Pause and resume just doesn't work well.
// I suspect this may need to be implemented at a higher-level
// scope than just this core Parser.
this.pause = function()
{
_paused = true;
};
this.resume = function()
{
_paused = false;
if (_i < _input.length)
return parserLoop();
};
*/
this.abort = function() this.abort = function()
{ {
_aborted = true; _aborted = true;
}; };
this.getCharIndex = function()
{
return _i;
};
function parserLoop() function parserLoop()
{ {
while (_i < _input.length) while (_i < _input.length)
{ {
if (_aborted) break; if (_aborted) break;
if (_preview > 0 && _runningRowIdx >= _preview) break; if (_preview > 0 && _runningRowIdx >= _preview) break;
if (_paused) return finishParsing();
if (_ch == '"') if (_ch == '"')
parseQuotes(); parseQuotes();
@ -1066,7 +1075,7 @@
if (isFunction(_step)) if (isFunction(_step))
{ {
if (_data[_rowIdx]) if (_data[_rowIdx])
_step(returnable(), self); _step(returnable());
clearErrorsAndData(); clearErrorsAndData();
} }
} }
@ -1157,7 +1166,8 @@
meta: { meta: {
lines: _lineNum, lines: _lineNum,
delimiter: _delimiter, delimiter: _delimiter,
aborted: _aborted aborted: _aborted,
truncated: _preview > 0 && _i < _input.length
} }
}; };
} }
@ -1277,6 +1287,9 @@
if (typeof config.complete !== 'function') if (typeof config.complete !== 'function')
config.complete = DEFAULTS.complete; config.complete = DEFAULTS.complete;
if (typeof config.error !== 'function')
config.error = DEFAULTS.error;
if (typeof config.encoding !== 'string') if (typeof config.encoding !== 'string')
config.encoding = DEFAULTS.encoding; config.encoding = DEFAULTS.encoding;

Loading…
Cancel
Save