Output: update method to allow downloads without modifying htaccess. Fixes #681

This commit is contained in:
Mottie 2014-07-15 21:19:47 -05:00
parent c4cad65dc4
commit c9c11a8495
3 changed files with 77 additions and 78 deletions

View File

@ -79,6 +79,7 @@ div.ui-slider .ui-slider-handle { width: 0.8em; height: 0.8em; }
a.alert { color: #a00; padding: 0; } a.alert { color: #a00; padding: 0; }
span.alert { padding: 1px 3px; } span.alert { padding: 1px 3px; }
.hidden { display: none; } .hidden { display: none; }
.fade { opacity: 0.5; }
.results { color: red; } .results { color: red; }
.clear { clear: both; } .clear { clear: both; }
.bootstrap_buttons button { margin: 5px 0 0 0; } .bootstrap_buttons button { margin: 5px 0 0 0; }

View File

@ -53,9 +53,6 @@
.output-separator-input, .output-replacequotes { .output-separator-input, .output-replacequotes {
width: 26px; width: 26px;
} }
.output-type {
width: 80px;
}
pre { pre {
/* override bootstrap setting */ /* override bootstrap setting */
overflow-y: hidden !important; overflow-y: hidden !important;
@ -102,12 +99,7 @@
<script id="js">$(function() { <script id="js">$(function() {
// set up demo for two table groups // set up demo for two table groups
var demos = ['.group1', '.group2'], var demos = ['.group1', '.group2'];
outputTypes = [
'data:text/csv;charset=utf8,', // utf-8 no BOM
'data:text/csv;charset=utf8,%EF%BB%BF', // utf-8 with BOM
'data:text/csv;charset=windows-1252,' // windows 1252
];
$.each(demos, function(groupIndex){ $.each(demos, function(groupIndex){
var $this = $(demos[groupIndex]); var $this = $(demos[groupIndex]);
@ -140,11 +132,9 @@
// return true to continue download/output // return true to continue download/output
// return false to stop delivery & do something else with the data // return false to stop delivery & do something else with the data
output_callback : function(config, data) { return true; }, output_callback : function(config, data) { return true; },
// output data type (with BOM or Windows-1252 is needed for excel)
// NO BOM : 'data:text/csv;charset=utf8,' // the need to modify this for Excel no longer exists
// With BOM : 'data:text/csv;charset=utf8,%EF%BB%BF' output_encoding : 'data:application/octet-stream;charset=utf8,'
// WIN 1252 : 'data:text/csv;charset=windows-1252'
output_encoding : 'data:text/csv;charset=utf8,'
} }
}); });
@ -186,7 +176,8 @@
// clicking the download button; all you really need is to // clicking the download button; all you really need is to
// trigger an "output" event on the table // trigger an "output" event on the table
$this.find('.download').click(function(){ $this.find('.download').click(function(){
var $table = $this.find('table'), var typ,
$table = $this.find('table'),
wo = $table[0].config.widgetOptions, wo = $table[0].config.widgetOptions,
saved = $this.find('.output-filter-all :checked').attr('class'); saved = $this.find('.output-filter-all :checked').attr('class');
wo.output_separator = $this.find('.output-separator-input').val(); wo.output_separator = $this.find('.output-separator-input').val();
@ -198,7 +189,6 @@
wo.output_wrapQuotes = $this.find('.output-wrap').is(':checked'); wo.output_wrapQuotes = $this.find('.output-wrap').is(':checked');
wo.output_headerRows = $this.find('.output-headers').is(':checked'); wo.output_headerRows = $this.find('.output-headers').is(':checked');
wo.output_saveFileName = $this.find('.output-filename').val(); wo.output_saveFileName = $this.find('.output-filename').val();
wo.output_encoding = outputTypes[ parseInt( $this.find('.output-type').val(), 10) ];
$table.trigger('outputTable'); $table.trigger('outputTable');
return false; return false;
}); });
@ -230,6 +220,7 @@
<h4>Changes</h4> <h4>Changes</h4>
<ul> <ul>
<li>In <span class="version">v2.17.5</span>, the need to modify the server's content disposition no longer exists.</li>
<li>In <span class="version">v2.17.0</span>, <li>In <span class="version">v2.17.0</span>,
<ul> <ul>
<li>Added the <code>output_ignoreColumns</code> option &amp; modified the <code>output_callback</code> parameters.</li> <li>Added the <code>output_ignoreColumns</code> option &amp; modified the <code>output_callback</code> parameters.</li>
@ -242,20 +233,9 @@
<h4>Requirements</h4> <h4>Requirements</h4>
<ul> <ul>
<li>This widget will <strong>only work</strong> in tablesorter version 2.8+ and jQuery version 1.7+.</li> <li>This widget will <strong>only work</strong> in tablesorter version 2.8+ and jQuery version 1.7+.</li>
<li>To download a file with the set filename and extension, the server's <code>Content-disposition</code> needs to be set.<p> <li><del>To download a file with the set filename and extension, the server's <code>Content-disposition</code> needs to be set</del></li>
<div class="alert alert-danger"> <li>This widget now uses a method available in modern browsers (IE10+) to download files without the need for server side modifications</li>
<span class="alert-link">This widget <em>WILL NOT</em> download the file nor use the proper filename and extension, unless you make these server-side changes.</span> <li>Support in older browsers (IE9 and older) have not been throughly tested.</li>
<br>
(<small>This is a GitHub demo and will not save the file using the selected filename &amp; extension because I don't work at GitHub and I can't modify their server.</small>)
</div>
See the:
<ul>
<li><code>.htacess</code> example in the "Basic Setup" section below.</li>
<li>or, look at the "Setup Example (php)" section on how to set this up in php</li>
</ul>
<p>
</li>
<li><span class="label label-info">Excel</span> support requires setting the <code>output_encoding</code> option to use the "with BOM" encoding string. Get more details in the "Options" section below.</li>
</ul> </ul>
<h4>Features &amp; Usage</h4> <h4>Features &amp; Usage</h4>
@ -283,6 +263,7 @@
<ul> <ul>
<li><a href="http://www.kunalbabre.com/projects/table2CSV.php">HTML Table to CSV</a> (License unknown)</li> <li><a href="http://www.kunalbabre.com/projects/table2CSV.php">HTML Table to CSV</a> (License unknown)</li>
<li><a href="https://github.com/PixelsCommander/Download-File-JS">Download-File-JS</a> (<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache v2.0</a>)</li> <li><a href="https://github.com/PixelsCommander/Download-File-JS">Download-File-JS</a> (<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache v2.0</a>)</li>
<li><a href="http://html5-demos.appspot.com/static/a.download.html">Download demo</a> from <a href="https://github.com/ebidel/html5demos">ebidel/html5demos</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -318,13 +299,16 @@
widgets: ['zebra', 'output'] widgets: ['zebra', 'output']
}); });
});</pre> });</pre>
Modification of the <code>.htaccess</code> is no longer required
<div class="fade">
<h4>.htaccess</h4> <h4>.htaccess</h4>
Do not forget to set Content-disposition headers in order to make downloads work properly in IE and FF. So <code>.htaccess</code> can look like: The Content-disposition headers <em>may need to be set</em> in order to make downloads work properly in IE. So <code>.htaccess</code> can look like:
<pre class="prettyprint lang-xml">&lt;FilesMatch "\.(?i:csv|txt)$"&gt; <pre class="prettyprint lang-xml">&lt;FilesMatch "\.(?i:csv|txt)$"&gt;
ForceType application/octet-stream ForceType application/octet-stream
Header set Content-Disposition attachment Header set Content-Disposition attachment
&lt;/FilesMatch&gt;</pre> &lt;/FilesMatch&gt;</pre>
</div> </div>
</div>
<h3><a href="#">Setup Example (php)</a></h3> <h3><a href="#">Setup Example (php)</a></h3>
<div> <div>
@ -672,9 +656,16 @@ line,value1,value2,value3
<tr id="output_encoding"> <tr id="output_encoding">
<td><a href="#" class="permalink">output_encoding</a></td> <td><a href="#" class="permalink">output_encoding</a></td>
<td>{see description}</td> <td>{see description}</td>
<td>Default encoding is utf-8 no BOM (<span class="version">2.16.4</span>) <td>Default encoding setting (<span class="version">2.16.4</span>; <span class="version updated">2.17.5</span>)
<div class="collapsible"> <div class="collapsible">
<br> <br>
As of <span class="version updated">2.17.5</span>, this option no longer needs to be modified to specifically make this widget download files that will work in Excel.<br>
<br>
The method used to download has been completely changed. The downloads still need an encoding setting, but this option is now set to a default of
<pre class="prettyprint lang-js">output_encoding : 'data:application/octet-stream;charset=utf8,'</pre>
<hr>
The information below is no longer relavant:
<div class="fade">
With the default settings (utf-8 no BOM), Excel does not properly encode accented characters unless the csv file is imported. Depending on the characters used, there are various methods which will allow proper encoding, but no one method is ideal. So this option can be set to allow the user to try different encodings. Set it as follows: With the default settings (utf-8 no BOM), Excel does not properly encode accented characters unless the csv file is imported. Depending on the characters used, there are various methods which will allow proper encoding, but no one method is ideal. So this option can be set to allow the user to try different encodings. Set it as follows:
<pre class="prettyprint lang-js">// output data type (with BOM or Windows-1252 is needed for excel) <pre class="prettyprint lang-js">// output data type (with BOM or Windows-1252 is needed for excel)
// NO BOM : 'data:text/csv;charset=utf8,' // NO BOM : 'data:text/csv;charset=utf8,'
@ -682,6 +673,7 @@ line,value1,value2,value3
// WIN 1252 : 'data:text/csv;charset=windows-1252,' // ANSI (subset of ISO-8859-1) // WIN 1252 : 'data:text/csv;charset=windows-1252,' // ANSI (subset of ISO-8859-1)
output_encoding : 'data:text/csv;charset=utf8,'</pre><span class="label label-info">Note</span> The commas are important! output_encoding : 'data:text/csv;charset=utf8,'</pre><span class="label label-info">Note</span> The commas are important!
</div> </div>
</div>
</td> </td>
</tr> </tr>
@ -757,16 +749,9 @@ $.tablesorter.output.replaceTab = '\\t';</pre>
<button type="button" class="output-quotes btn btn-default btn-xs" title="escaped quote">\"</button> <button type="button" class="output-quotes btn btn-default btn-xs" title="escaped quote">\"</button>
</li> </li>
<li><label title="Remove extra white space from each cell">Trim spaces: <input class="output-trim" type="checkbox" checked /></label></li> <li><label title="Remove extra white space from each cell">Trim spaces: <input class="output-trim" type="checkbox" checked /></label></li>
<li><label title="Include HTML from cells in output">Include HTML: <input class="output-html" type="checkbox" /></lable></li> <li><label title="Include HTML from cells in output">Include HTML: <input class="output-html" type="checkbox" /></label></li>
<li><label title="Wrap all values in quotes">Wrap in Quotes: <input class="output-wrap" type="checkbox" /></label></li> <li><label title="Wrap all values in quotes">Wrap in Quotes: <input class="output-wrap" type="checkbox" /></label></li>
<li> <li><label title="Choose a download filename">Filename: <input class="output-filename" type="text" size="15" value="mytable.csv"/></label></li>
<label title="Choose a download filename">Filename: <input class="output-filename" type="text" size="15" value="mytable.csv"/></label>
<select class="output-type">
<option value="0">utf8</option>
<option value="1">utf8-BOM</option>
<option value="2">windows-1252</option>
</select>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -868,17 +853,10 @@ $.tablesorter.output.replaceTab = '\\t';</pre>
<button type="button" class="output-quotes btn btn-default btn-xs" title="escaped quote">\"</button> <button type="button" class="output-quotes btn btn-default btn-xs" title="escaped quote">\"</button>
</li> </li>
<li><label title="Remove extra white space from each cell">Trim spaces: <input class="output-trim" type="checkbox" checked /></label></li> <li><label title="Remove extra white space from each cell">Trim spaces: <input class="output-trim" type="checkbox" checked /></label></li>
<li><label title="Include HTML from cells in output">Include HTML: <input class="output-html" type="checkbox" /></lable></li> <li><label title="Include HTML from cells in output">Include HTML: <input class="output-html" type="checkbox" /></label></li>
<li><label title="Wrap all values in quotes">Wrap in Quotes: <input class="output-wrap" type="checkbox" /></label></li> <li><label title="Wrap all values in quotes">Wrap in Quotes: <input class="output-wrap" type="checkbox" /></label></li>
<li><label title="Include both header rows in output">Include both header rows: <input class="output-headers" type="checkbox" checked /></label></li> <li><label title="Include both header rows in output">Include both header rows: <input class="output-headers" type="checkbox" checked /></label></li>
<li> <li><label title="Choose a download filename">Filename: <input class="output-filename" type="text" size="15" value="mytable.csv"/></label></li>
<label title="Choose a download filename">Filename: <input class="output-filename" type="text" size="15" value="mytable.csv"/></label>
<select class="output-type">
<option value="0">utf8</option>
<option value="1">utf8-BOM</option>
<option value="2">windows-1252</option>
</select>
</li>
</ul> </ul>
</div> </div>

View File

@ -221,33 +221,55 @@ output = ts.output = {
}, },
// modified from https://github.com/PixelsCommander/Download-File-JS // modified from https://github.com/PixelsCommander/Download-File-JS
// & http://html5-demos.appspot.com/static/a.download.html
download : function (wo, data){ download : function (wo, data){
var e, link,
processedData = wo.output_encoding + encodeURIComponent(data); var e, blob, gotBlob,
nav = window.navigator,
link = document.createElement('a');
// iOS devices do not support downloading. We have to inform user about this. // iOS devices do not support downloading. We have to inform user about this.
if (/(iP)/g.test(navigator.userAgent)) { if (/(iP)/g.test(nav.userAgent)) {
alert(output.message); alert(output.message);
return false; return false;
} }
// If in Chrome or Safari - download via virtual link click
if ( /(chrome|safari)/.test(navigator.userAgent.toLowerCase()) ) { // test for blob support
// Creating new link node. try {
link = document.createElement('a'); gotBlob = !!new Blob();
link.href = processedData; } catch (e) {
gotBlob = false;
};
// Use HTML5 Blob if browser supports it
if ( gotBlob ) {
window.URL = window.webkitURL || window.URL;
blob = new Blob([data], {type: wo.output_encoding});
if (nav.msSaveBlob) {
// IE 10+
nav.msSaveBlob(blob, wo.output_saveFileName);
} else {
// all other browsers
link.href = window.URL.createObjectURL(blob);
link.download = wo.output_saveFileName; link.download = wo.output_saveFileName;
// Dispatching click event. // Dispatching click event; using $(link).trigger() won't work
if (document.createEvent) { if (document.createEvent) {
e = document.createEvent('MouseEvents'); e = document.createEvent('MouseEvents');
e.initEvent('click', true, true); // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(e); link.dispatchEvent(e);
return true;
} }
} }
// Force file download (whether supported by server). return false;
processedData += '?download'; }
window.open(processedData, '_self');
// fallback to force file download (whether supported by server).
// not sure if this actually works in IE9 and older...
window.open( wo.output_encoding + encodeURIComponent(data) + '?download' , '_self');
return true; return true;
}, },
remove : function(c) { remove : function(c) {
@ -278,11 +300,9 @@ ts.addWidget({
output_callback : function(config, data){ return true; }, output_callback : function(config, data){ return true; },
// JSON callback executed when a colspan is encountered in the header // JSON callback executed when a colspan is encountered in the header
output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex) + ')'; }, output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex) + ')'; },
// output data type (with BOM or Windows-1252 is needed for excel) // the need to modify this for Excel no longer exists
// NO BOM : 'data:text/csv;charset=utf8,' output_encoding : 'data:application/octet-stream;charset=utf8,'
// With BOM : 'data:text/csv;charset=utf8,%EF%BB%BF'
// WIN 1252 : 'data:text/csv;charset=windows-1252'
output_encoding : 'data:text/csv;charset=utf8,'
}, },
init: function(table, thisWidget, c) { init: function(table, thisWidget, c) {
output.init(c); output.init(c);