From 65388f3d50695a2aedaece2c8b3387248393bf3a Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Tue, 25 Nov 2014 22:03:10 +0000 Subject: [PATCH 1/3] Remove document.write for script path and allow external config 1. Use document.getElementsByTag name to find the script's path. When used async, this fails by providing the wrong path instead of failing catastrophically. 2. Detect if the script was loaded asynchronously by attaching a load event to the body and seeing if it fires. 3. Evaluate the correct script path when it is requested. This gives the user time to manually configuring it using the Papa.SCRIPT_PATH global. If this isn't done and the script was loaded async, throw a helpful error explaining how to fix. --- papaparse.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/papaparse.js b/papaparse.js index 230be43..7832d24 100644 --- a/papaparse.js +++ b/papaparse.js @@ -7,7 +7,7 @@ { "use strict"; - var IS_WORKER = !global.document, SCRIPT_PATH; + var IS_WORKER = !global.document, IS_SYNC = false, AUTO_SCRIPT_PATH; var workers = {}, workerIdCounter = 0; // A configuration object from which to draw default settings @@ -39,6 +39,8 @@ global.Papa.BYTE_ORDER_MARK = "\ufeff"; global.Papa.BAD_DELIMITERS = ["\r", "\n", "\"", global.Papa.BYTE_ORDER_MARK]; global.Papa.WORKERS_SUPPORTED = !!global.Worker; + // Must be set externally if using workers and Papa Parse is loaded asynchronously + global.Papa.SCRIPT_PATH = null; // Configurable chunk sizes for local and remote files, respectively global.Papa.LocalChunkSize = 1024 * 1024 * 10; // 10 MB @@ -147,9 +149,17 @@ if (IS_WORKER) + { global.onmessage = workerThreadReceivedMessage; + } else if (Papa.WORKERS_SUPPORTED) - SCRIPT_PATH = getScriptPath(); + { + AUTO_SCRIPT_PATH = getScriptPath(); + // Check if the script was loaded synchronously + document.body.addEventListener('load', function () { + IS_SYNC = true; + }, true); + } @@ -157,7 +167,7 @@ function CsvToJson(_input, _config) { var config = IS_WORKER ? _config : copyAndValidateConfig(_config); - var useWorker = config.worker && Papa.WORKERS_SUPPORTED && SCRIPT_PATH; + var useWorker = config.worker && Papa.WORKERS_SUPPORTED && (Papa.SCRIPT_PATH || AUTO_SCRIPT_PATH); if (useWorker) { @@ -1349,16 +1359,20 @@ // the script path here. See: https://github.com/mholt/PapaParse/issues/87#issuecomment-57885358 function getScriptPath() { - var id = "worker" + String(Math.random()).substr(2); - document.write(''); - return document.getElementById(id).previousSibling.src; + var scripts = document.getElementsByTagName('script'); + return scripts.length ? scripts[scripts.length - 1].src : ''; } function newWorker() { if (!Papa.WORKERS_SUPPORTED) return false; - var w = new global.Worker(SCRIPT_PATH); + if (!IS_SYNC && Papa.SCRIPT_PATH === null) + throw new Error( + 'Script path cannot be determined automatically when Papa Parse is loaded asynchronously. ' + + 'You need to set Papa.SCRIPT_PATH manually.' + ); + var w = new global.Worker(Papa.SCRIPT_PATH || AUTO_SCRIPT_PATH); w.onmessage = mainThreadReceivedMessage; w.id = workerIdCounter++; workers[w.id] = w; From 8d33f90c1363fa8404da80aef446f9bdb6cae90c Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Mon, 1 Dec 2014 13:19:06 +0000 Subject: [PATCH 2/3] Check body exists before attaching load listener & rename flag to LOADED_SYNC --- papaparse.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/papaparse.js b/papaparse.js index 7832d24..ab50e66 100644 --- a/papaparse.js +++ b/papaparse.js @@ -7,7 +7,7 @@ { "use strict"; - var IS_WORKER = !global.document, IS_SYNC = false, AUTO_SCRIPT_PATH; + var IS_WORKER = !global.document, LOADED_SYNC = false, AUTO_SCRIPT_PATH; var workers = {}, workerIdCounter = 0; // A configuration object from which to draw default settings @@ -156,9 +156,17 @@ { AUTO_SCRIPT_PATH = getScriptPath(); // Check if the script was loaded synchronously - document.body.addEventListener('load', function () { - IS_SYNC = true; - }, true); + if ( document.body ) + { + document.body.addEventListener('load', function () { + LOADED_SYNC = true; + }, true); + } + else + { + // Body doesn't exist yet, must be synchronous + LOADED_SYNC = true; + } } @@ -1367,7 +1375,7 @@ { if (!Papa.WORKERS_SUPPORTED) return false; - if (!IS_SYNC && Papa.SCRIPT_PATH === null) + if (!LOADED_SYNC && Papa.SCRIPT_PATH === null) throw new Error( 'Script path cannot be determined automatically when Papa Parse is loaded asynchronously. ' + 'You need to set Papa.SCRIPT_PATH manually.' From 7dea98ebe4d97ced27ac9271807f449dd4c0b0c9 Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Tue, 2 Dec 2014 17:03:55 +0000 Subject: [PATCH 3/3] Use DOMContentLoaded event, always try to use a worker so error is thrown DOMContentLoaded event fires sooner fixing the body-async case. If the user reqeusts a worker, try to use one even if no path is set so that a helpful error is shown. --- papaparse.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/papaparse.js b/papaparse.js index ab50e66..5db9d00 100644 --- a/papaparse.js +++ b/papaparse.js @@ -156,16 +156,13 @@ { AUTO_SCRIPT_PATH = getScriptPath(); // Check if the script was loaded synchronously - if ( document.body ) - { - document.body.addEventListener('load', function () { - LOADED_SYNC = true; - }, true); - } - else - { + if ( !document.body ) { // Body doesn't exist yet, must be synchronous LOADED_SYNC = true; + } else { + document.addEventListener('DOMContentLoaded', function () { + LOADED_SYNC = true; + }, true); } } @@ -175,7 +172,7 @@ function CsvToJson(_input, _config) { var config = IS_WORKER ? _config : copyAndValidateConfig(_config); - var useWorker = config.worker && Papa.WORKERS_SUPPORTED && (Papa.SCRIPT_PATH || AUTO_SCRIPT_PATH); + var useWorker = config.worker && Papa.WORKERS_SUPPORTED; if (useWorker) {