Support uploading directly to a new Google spreadsheet.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@2243 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
b585140c34
commit
5c446d28d0
@ -47,6 +47,7 @@ function init() {
|
||||
RS.registerCommand(module, "authorize", Packages.com.google.refine.extension.gdata.AuthorizeCommand());
|
||||
RS.registerCommand(module, "authorize2", Packages.com.google.refine.extension.gdata.AuthorizeCommand2());
|
||||
RS.registerCommand(module, "deauthorize", Packages.com.google.refine.extension.gdata.DeAuthorizeCommand());
|
||||
RS.registerCommand(module, "upload", Packages.com.google.refine.extension.gdata.UploadCommand());
|
||||
|
||||
// Register importer and exporter
|
||||
var IM = Packages.com.google.refine.importing.ImportingManager;
|
||||
@ -80,6 +81,15 @@ function init() {
|
||||
"styles/importing-controller.less"
|
||||
]
|
||||
);
|
||||
|
||||
// Script files to inject into /project page
|
||||
ClientSideResourceManager.addPaths(
|
||||
"project/scripts",
|
||||
module,
|
||||
[
|
||||
"scripts/project/exporters.js"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
82
extensions/gdata/module/scripts/project/exporters.js
Normal file
82
extensions/gdata/module/scripts/project/exporters.js
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
Copyright 2011, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
CustomTabularExporterDialog.uploadTargets.push({
|
||||
id: 'gdata/google-spreadsheet',
|
||||
label: 'A new Google spreadsheet',
|
||||
handler: function(options, exportAllRows, onDone) {
|
||||
var doUpload = function() {
|
||||
var name = window.prompt('Enter name of new spreadsheet', theProject.metadata.name);
|
||||
if (name) {
|
||||
var dismiss = DialogSystem.showBusy('Uploading...');
|
||||
$.post(
|
||||
"/command/gdata/upload",
|
||||
{
|
||||
"project" : theProject.id,
|
||||
"engine" : exportAllRows ? '' : JSON.stringify(ui.browsingEngine.getJSON()),
|
||||
"name" : name,
|
||||
"format" : options.format,
|
||||
"options" : JSON.stringify(options)
|
||||
},
|
||||
function(o) {
|
||||
dismiss();
|
||||
|
||||
if (o.url) {
|
||||
window.open(o.url, '_blank');
|
||||
}
|
||||
onDone();
|
||||
},
|
||||
"json"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var messageListener = function(evt) {
|
||||
window.removeEventListener("message", messageListener, false);
|
||||
if ($.cookie('authsub_token')) {
|
||||
doUpload();
|
||||
}
|
||||
};
|
||||
|
||||
var authenticate = function() {
|
||||
window.addEventListener("message", messageListener, false);
|
||||
window.open(
|
||||
"/command/gdata/authorize",
|
||||
"google-refine-gdata-signin",
|
||||
"resizable=1,width=600,height=450"
|
||||
);
|
||||
};
|
||||
|
||||
authenticate();
|
||||
}
|
||||
});
|
@ -1,4 +1,31 @@
|
||||
package com.google.refine.extension.gdata;
|
||||
/*
|
||||
* Copyright (c) 2011, Thomas F. Morris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Google nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
@ -33,7 +60,7 @@ public class AuthorizeCommand extends Command {
|
||||
|
||||
String requestUrl = AuthSubUtil.getRequestUrl(
|
||||
authorizedUrl.toExternalForm(), // execution continues at authorized on redirect
|
||||
"https://spreadsheets.google.com/feeds https://www.google.com/fusiontables/api/query",
|
||||
"https://docs.google.com/feeds https://spreadsheets.google.com/feeds https://www.google.com/fusiontables/api/query",
|
||||
false,
|
||||
true);
|
||||
response.sendRedirect(requestUrl);
|
||||
|
@ -1,3 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Thomas F. Morris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Google nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -1,3 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Thomas F. Morris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Google nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Thomas F. Morris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Google nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.google.refine.extension.gdata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gdata.client.docs.DocsService;
|
||||
import com.google.gdata.client.spreadsheet.CellQuery;
|
||||
import com.google.gdata.client.spreadsheet.SpreadsheetService;
|
||||
import com.google.gdata.data.Link;
|
||||
import com.google.gdata.data.PlainTextConstruct;
|
||||
import com.google.gdata.data.batch.BatchOperationType;
|
||||
import com.google.gdata.data.batch.BatchStatus;
|
||||
import com.google.gdata.data.batch.BatchUtils;
|
||||
import com.google.gdata.data.docs.SpreadsheetEntry;
|
||||
import com.google.gdata.data.spreadsheet.Cell;
|
||||
import com.google.gdata.data.spreadsheet.CellEntry;
|
||||
import com.google.gdata.data.spreadsheet.CellFeed;
|
||||
import com.google.gdata.data.spreadsheet.WorksheetEntry;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
|
||||
import com.google.refine.ProjectManager;
|
||||
import com.google.refine.browsing.Engine;
|
||||
import com.google.refine.commands.Command;
|
||||
import com.google.refine.commands.HttpUtilities;
|
||||
import com.google.refine.commands.project.ExportRowsCommand;
|
||||
import com.google.refine.exporters.CustomizableTabularExporterUtilities;
|
||||
import com.google.refine.exporters.TabularSerializer;
|
||||
import com.google.refine.model.Project;
|
||||
|
||||
public class UploadCommand extends Command {
|
||||
static final Logger logger = LoggerFactory.getLogger("gdata_upload");
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
String token = TokenCookie.getToken(request);
|
||||
if (token == null) {
|
||||
HttpUtilities.respond(response, "error", "Not authorized");
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectManager.singleton.setBusy(true);
|
||||
try {
|
||||
Project project = getProject(request);
|
||||
Engine engine = getEngine(request, project);
|
||||
Properties params = ExportRowsCommand.getRequestParameters(request);
|
||||
String name = params.getProperty("name");
|
||||
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
|
||||
Writer w = response.getWriter();
|
||||
JSONWriter writer = new JSONWriter(w);
|
||||
try {
|
||||
writer.object();
|
||||
String url = upload(project, engine, params, token, name);
|
||||
if (url != null) {
|
||||
writer.key("status"); writer.value("ok");
|
||||
writer.key("url"); writer.value(url);
|
||||
} else {
|
||||
writer.key("status"); writer.value("error");
|
||||
writer.key("message"); writer.value("No such format");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
writer.key("status"); writer.value("error");
|
||||
writer.key("message"); writer.value(e.getMessage());
|
||||
} finally {
|
||||
writer.endObject();
|
||||
w.flush();
|
||||
w.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServletException(e);
|
||||
} finally {
|
||||
ProjectManager.singleton.setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
static private String upload(
|
||||
Project project, Engine engine, Properties params,
|
||||
String token, String name) throws Exception {
|
||||
String format = params.getProperty("format");
|
||||
if ("gdata/google-spreadsheet".equals(format)) {
|
||||
return uploadSpreadsheet(project, engine, params, token, name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static private String uploadSpreadsheet(
|
||||
final Project project, final Engine engine, final Properties params,
|
||||
String token, String name)
|
||||
throws MalformedURLException, IOException, ServiceException {
|
||||
DocsService docsService = GDataExtension.getDocsService(token);
|
||||
final SpreadsheetService spreadsheetService = GDataExtension.getSpreadsheetService(token);
|
||||
|
||||
SpreadsheetEntry spreadsheetEntry = new SpreadsheetEntry();
|
||||
spreadsheetEntry.setTitle(new PlainTextConstruct(name));
|
||||
|
||||
final SpreadsheetEntry spreadsheetEntry2 = docsService.insert(
|
||||
new URL("https://docs.google.com/feeds/default/private/full/"), spreadsheetEntry);
|
||||
|
||||
int[] size = CustomizableTabularExporterUtilities.countColumnsRows(
|
||||
project, engine, params);
|
||||
|
||||
URL worksheetFeedUrl = spreadsheetEntry2.getWorksheetFeedUrl();
|
||||
WorksheetEntry worksheetEntry = new WorksheetEntry(size[1], size[0]);
|
||||
worksheetEntry.setTitle(new PlainTextConstruct("Uploaded Data"));
|
||||
|
||||
final WorksheetEntry worksheetEntry2 =
|
||||
spreadsheetService.insert(worksheetFeedUrl, worksheetEntry);
|
||||
|
||||
spreadsheetEntry2.getDefaultWorksheet().delete();
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
spreadsheetService.setProtocolVersion(SpreadsheetService.Versions.V1);
|
||||
try {
|
||||
uploadToCellFeed(
|
||||
project, engine, params,
|
||||
spreadsheetService,
|
||||
spreadsheetEntry2,
|
||||
worksheetEntry2);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error uploading data to Google Spreadsheets", e);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
||||
return spreadsheetEntry2.getDocumentLink().getHref();
|
||||
}
|
||||
|
||||
static private void uploadToCellFeed(
|
||||
Project project,
|
||||
Engine engine,
|
||||
Properties params,
|
||||
final SpreadsheetService service,
|
||||
final SpreadsheetEntry spreadsheetEntry,
|
||||
final WorksheetEntry worksheetEntry)
|
||||
throws IOException, ServiceException {
|
||||
|
||||
final URL cellFeedUrl = worksheetEntry.getCellFeedUrl();
|
||||
final CellEntry[][] cellEntries =
|
||||
new CellEntry[worksheetEntry.getRowCount()][worksheetEntry.getColCount()];
|
||||
{
|
||||
CellQuery cellQuery = new CellQuery(cellFeedUrl);
|
||||
cellQuery.setReturnEmpty(true);
|
||||
|
||||
CellFeed fetchingCellFeed = service.getFeed(cellQuery, CellFeed.class);
|
||||
for (CellEntry cellEntry : fetchingCellFeed.getEntries()) {
|
||||
Cell cell = cellEntry.getCell();
|
||||
cellEntries[cell.getRow() - 1][cell.getCol() - 1] = cellEntry;
|
||||
}
|
||||
}
|
||||
|
||||
TabularSerializer serializer = new TabularSerializer() {
|
||||
CellFeed cellFeed = service.getFeed(cellFeedUrl, CellFeed.class);
|
||||
CellFeed batchRequest = null;
|
||||
int row = 0;
|
||||
|
||||
@Override
|
||||
public void startFile(JSONObject options) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFile() {
|
||||
if (batchRequest != null) {
|
||||
sendBatch();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendBatch() {
|
||||
try {
|
||||
Link batchLink = cellFeed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
|
||||
CellFeed batchResponse = service.batch(new URL(batchLink.getHref()), batchRequest);
|
||||
|
||||
for (CellEntry entry : batchResponse.getEntries()) {
|
||||
String batchId = BatchUtils.getBatchId(entry);
|
||||
if (!BatchUtils.isSuccess(entry)) {
|
||||
BatchStatus status = BatchUtils.getBatchStatus(entry);
|
||||
logger.warn(
|
||||
String.format(
|
||||
"Error: %s failed (%s) %s\n",
|
||||
batchId, status.getReason(), status.getContent()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
batchRequest = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRow(List<CellData> cells, boolean isHeader) {
|
||||
if (batchRequest == null) {
|
||||
batchRequest = new CellFeed();
|
||||
}
|
||||
for (int c = 0; c < cells.size(); c++) {
|
||||
CellData cellData = cells.get(c);
|
||||
if (cellData != null && cellData.text != null) {
|
||||
String cellId = String.format("R%sC%s", row + 1, c + 1);
|
||||
|
||||
CellEntry cellEntry = cellEntries[row][c];
|
||||
cellEntry.changeInputValueLocal(cellData.text);
|
||||
if (cellData.link != null) {
|
||||
cellEntry.addHtmlLink(cellData.link, null, cellData.text);
|
||||
}
|
||||
cellEntry.setId(cellId);
|
||||
BatchUtils.setBatchId(cellEntry, cellId);
|
||||
BatchUtils.setBatchOperationType(cellEntry, BatchOperationType.UPDATE);
|
||||
|
||||
batchRequest.getEntries().add(cellEntry);
|
||||
}
|
||||
}
|
||||
row++;
|
||||
if (row % 20 == 0) {
|
||||
sendBatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CustomizableTabularExporterUtilities.exportRows(
|
||||
project, engine, params, serializer);
|
||||
}
|
||||
}
|
@ -171,6 +171,34 @@ abstract public class CustomizableTabularExporterUtilities {
|
||||
filteredRows.accept(project, visitor);
|
||||
}
|
||||
|
||||
static public int[] countColumnsRows(
|
||||
final Project project,
|
||||
final Engine engine,
|
||||
Properties params) {
|
||||
RowCountingTabularSerializer serializer = new RowCountingTabularSerializer();
|
||||
exportRows(project, engine, params, serializer);
|
||||
return new int[] { serializer.columns, serializer.rows };
|
||||
}
|
||||
|
||||
static private class RowCountingTabularSerializer implements TabularSerializer {
|
||||
int columns;
|
||||
int rows;
|
||||
|
||||
@Override
|
||||
public void startFile(JSONObject options) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFile() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRow(List<CellData> cells, boolean isHeader) {
|
||||
columns = Math.max(columns, cells.size());
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ReconOutputMode {
|
||||
ENTITY_NAME,
|
||||
ENTITY_ID,
|
||||
|
@ -3,49 +3,12 @@
|
||||
<div class="dialog-body" bind="dialogBody">
|
||||
<div id="custom-tabular-exporter-tabs" class="refine-tabs">
|
||||
<ul>
|
||||
<li><a href="#custom-tabular-exporter-tabs-format">File Format</a></li>
|
||||
<li><a href="#custom-tabular-exporter-tabs-content">Content</a></li>
|
||||
<li><a href="#custom-tabular-exporter-tabs-download">Download</a></li>
|
||||
<li bind="uploadTabHeader"><a href="#custom-tabular-exporter-tabs-upload">Upload</a></li>
|
||||
<li><a href="#custom-tabular-exporter-tabs-code">Option Code</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="custom-tabular-exporter-tabs-format" style="display: none;"><div class="grid-layout grid-layout-for-ui layout-loose layout-full"><table>
|
||||
<tr>
|
||||
<th>Line-based text formats</th>
|
||||
<th>Other formats</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="60%"><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="tsv" /></td><td>Tab-separated values (TSV)</td></tr>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="csv" /></td><td>Comma-separated values (CSV)</td></tr>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="*sv" /></td><td>Custom separator
|
||||
<input type="text" class="lightweight" size="5" bind="separatorInput" />
|
||||
</td></tr>
|
||||
</table></div></td>
|
||||
|
||||
<td><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="xls" /></td>
|
||||
<td>Excel (.xls)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="xlsx" /></td>
|
||||
<td>Excel in XML (.xlsx)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-format" value="html" /></td>
|
||||
<td>HTML table</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr><td>Line separator</td><td><input type="text" size="5" class="lightweight" bind="lineSeparatorInput" /></td></tr>
|
||||
<tr><td>Character encoding</td><td><input type="text" size="10" class="lightweight" bind="encodingInput" /></td></tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
</table></div></div>
|
||||
|
||||
<div id="custom-tabular-exporter-tabs-content"><div class="grid-layout grid-layout-for-ui layout-normal layout-full"><table>
|
||||
<tr>
|
||||
<td>Select and Order Columns to Export</td>
|
||||
@ -109,22 +72,86 @@
|
||||
</table></div></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<td colspan="2">
|
||||
<button class="button" bind="selectAllButton">Select All</button>
|
||||
<button class="button" bind="deselectAllButton">De-select All</button>
|
||||
</td>
|
||||
<td><div class="grid-layout layout-tighter"><table>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><div class="grid-layout layout-tighter layout-full"><table>
|
||||
<tr>
|
||||
<td width="1%"><input type="checkbox" bind="outputColumnHeadersCheckbox" checked /></td>
|
||||
<td width="50%">Output column headers</td>
|
||||
<td width="25%">Output column headers</td>
|
||||
<td width="1%"><input type="checkbox" bind="outputBlankRowsCheckbox" /></td>
|
||||
<td width="50%">Output blank rows</td>
|
||||
<td width="25%">Output blank rows</td>
|
||||
<td width="1%"><input type="checkbox" bind="exportAllRowsCheckbox" /></td>
|
||||
<td width="50%">Ignore facets and filters and export all rows</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
</table></div></div>
|
||||
|
||||
|
||||
<div id="custom-tabular-exporter-tabs-download" style="display: none;"><div class="grid-layout grid-layout-for-ui layout-loose layout-full"><table>
|
||||
<tr>
|
||||
<th>Line-based text formats</th>
|
||||
<th>Other formats</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="60%"><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="tsv" checked /></td><td>Tab-separated values (TSV)</td></tr>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="csv" /></td><td>Comma-separated values (CSV)</td></tr>
|
||||
<tr><td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="*sv" /></td><td>Custom separator
|
||||
<input type="text" class="lightweight" size="5" bind="separatorInput" />
|
||||
</td></tr>
|
||||
</table></div></td>
|
||||
|
||||
<td><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="xls" /></td>
|
||||
<td>Excel (.xls)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="xlsx" /></td>
|
||||
<td>Excel in XML (.xlsx)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1%"><input type="radio" name="custom-tabular-exporter-download-format" value="html" /></td>
|
||||
<td>HTML table</td>
|
||||
</tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><div class="grid-layout grid-layout-for-text layout-tightest"><table>
|
||||
<tr><td>Line separator</td><td><input type="text" size="5" class="lightweight" bind="lineSeparatorInput" /></td></tr>
|
||||
<tr><td>Character encoding</td><td><input type="text" size="10" class="lightweight" bind="encodingInput" /></td></tr>
|
||||
</table></div></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"><div class="grid-layout grid-layout-for-text layout-tightest layout-full"><table><tr>
|
||||
<td width="100%"> </td>
|
||||
<td width="1%"><button class="button" bind="downloadPreviewButton">Preview</button></td>
|
||||
<td width="1%"><button class="button button-primary" bind="downloadButton">Download</button></td>
|
||||
</tr></table></div></td>
|
||||
</tr>
|
||||
</table></div></div>
|
||||
|
||||
|
||||
<div bind="uploadTabBody" id="custom-tabular-exporter-tabs-upload" style="display: none;"><div class="grid-layout grid-layout-for-ui layout-loose layout-full"><table bind="uploadTargetTable">
|
||||
<tr>
|
||||
<th colspan="2">Upload to</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><div class="grid-layout grid-layout-for-text layout-tightest layout-full"><table><tr>
|
||||
<td width="100%"> </td>
|
||||
<td width="1%"><button class="button button-primary" bind="uploadButton">Upload</button></td>
|
||||
</tr></table></div></td>
|
||||
</tr>
|
||||
</table></div></div>
|
||||
|
||||
|
||||
<div id="custom-tabular-exporter-tabs-code" style="display: none;"><div class="grid-layout grid-layout-for-ui layout-loose layout-full"><table>
|
||||
<tr>
|
||||
<td>The following JSON text encodes the options you have set in the other tabs.
|
||||
@ -139,11 +166,5 @@
|
||||
</div>
|
||||
<div class="dialog-footer" bind="dialogFooter"><div class="grid-layout layout-tightest layout-full"><table><tr>
|
||||
<td><button class="button" bind="cancelButton">Cancel</button></td>
|
||||
|
||||
<td width="1%"><input type="checkbox" bind="exportAllRowsCheckbox" /></td>
|
||||
<td>Ignore facets and filters and export all rows</td>
|
||||
|
||||
<td width="1%"><button class="button" bind="previewButton">Preview</button></td>
|
||||
<td width="1%"><button class="button button-primary" bind="exportButton">Export</button></td>
|
||||
</tr></table></div></div>
|
||||
</div>
|
@ -68,6 +68,8 @@ CustomTabularExporterDialog.formats = {
|
||||
}
|
||||
};
|
||||
|
||||
CustomTabularExporterDialog.uploadTargets = [];
|
||||
|
||||
CustomTabularExporterDialog.prototype._createDialog = function(options) {
|
||||
var self = this;
|
||||
|
||||
@ -75,8 +77,14 @@ CustomTabularExporterDialog.prototype._createDialog = function(options) {
|
||||
this._elmts = DOM.bind(this._dialog);
|
||||
this._level = DialogSystem.showDialog(this._dialog);
|
||||
|
||||
$("#custom-tabular-exporter-tabs-format").css("display", "");
|
||||
if (CustomTabularExporterDialog.uploadTargets.length == 0) {
|
||||
this._elmts.uploadTabHeader.remove();
|
||||
this._elmts.uploadTabBody.remove();
|
||||
}
|
||||
|
||||
$("#custom-tabular-exporter-tabs-content").css("display", "");
|
||||
$("#custom-tabular-exporter-tabs-download").css("display", "");
|
||||
$("#custom-tabular-exporter-tabs-upload").css("display", "");
|
||||
$("#custom-tabular-exporter-tabs-code").css("display", "");
|
||||
$("#custom-tabular-exporter-tabs").tabs();
|
||||
|
||||
@ -116,6 +124,34 @@ CustomTabularExporterDialog.prototype._createDialog = function(options) {
|
||||
}
|
||||
this._elmts.columnList.sortable({});
|
||||
|
||||
/*
|
||||
* Populate upload targets.
|
||||
*/
|
||||
if (CustomTabularExporterDialog.uploadTargets.length > 0) {
|
||||
var table = this._elmts.uploadTargetTable[0];
|
||||
for (var i = 0; i < CustomTabularExporterDialog.uploadTargets.length; i++) {
|
||||
var target = CustomTabularExporterDialog.uploadTargets[i];
|
||||
var tr = table.insertRow(table.rows.length - 1);
|
||||
|
||||
var td0 = $(tr.insertCell(0))
|
||||
.attr('width', '1');
|
||||
var input = $('<input>')
|
||||
.attr('type', 'radio')
|
||||
.attr('name', 'custom-tabular-exporter-upload-format')
|
||||
.attr('value', target.id)
|
||||
.appendTo(td0);
|
||||
if (i === 0) {
|
||||
input.attr('checked', 'checked');
|
||||
}
|
||||
|
||||
$(tr.insertCell(1))
|
||||
.attr('width', '100%')
|
||||
.text(target.label);
|
||||
}
|
||||
|
||||
this._elmts.uploadButton.click(function() { self._upload(); });
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook up event handlers.
|
||||
*/
|
||||
@ -146,21 +182,21 @@ CustomTabularExporterDialog.prototype._createDialog = function(options) {
|
||||
$('#custom-tabular-exporter-tabs-content').find('input').bind('change', function() {
|
||||
self._updateOptionCode();
|
||||
});
|
||||
$('#custom-tabular-exporter-tabs-format').find('input').bind('change', function() {
|
||||
$('#custom-tabular-exporter-tabs-download').find('input').bind('change', function() {
|
||||
self._updateOptionCode();
|
||||
});
|
||||
|
||||
this._elmts.applyOptionCodeButton.click(function(evt) { self._applyOptionCode(); });
|
||||
this._elmts.cancelButton.click(function() { self._dismiss(); });
|
||||
this._elmts.exportButton.click(function() { self._commit(); });
|
||||
this._elmts.previewButton.click(function(evt) { self._preview(); });
|
||||
this._elmts.downloadButton.click(function() { self._download(); });
|
||||
this._elmts.downloadPreviewButton.click(function(evt) { self._previewDownload(); });
|
||||
|
||||
this._configureUIFromOptionCode(options);
|
||||
this._updateOptionCode();
|
||||
};
|
||||
|
||||
CustomTabularExporterDialog.prototype._configureUIFromOptionCode = function(options) {
|
||||
this._dialog.find('input[name="custom-tabular-exporter-format"][value="' + options.format + '"]').attr('checked', 'checked');
|
||||
this._dialog.find('input[name="custom-tabular-exporter-download-format"][value="' + options.format + '"]').attr('checked', 'checked');
|
||||
this._elmts.separatorInput[0].value = String.encodeSeparator(options.separator || ',');
|
||||
this._elmts.lineSeparatorInput[0].value = String.encodeSeparator(options.lineSeparator || '\n');
|
||||
this._elmts.encodingInput[0].value = options.encoding;
|
||||
@ -188,11 +224,11 @@ CustomTabularExporterDialog.prototype._dismiss = function() {
|
||||
DialogSystem.dismissUntil(this._level - 1);
|
||||
};
|
||||
|
||||
CustomTabularExporterDialog.prototype._preview = function() {
|
||||
CustomTabularExporterDialog.prototype._previewDownload = function() {
|
||||
this._postExport(true);
|
||||
};
|
||||
|
||||
CustomTabularExporterDialog.prototype._commit = function() {
|
||||
CustomTabularExporterDialog.prototype._download = function() {
|
||||
this._postExport(false);
|
||||
this._dismiss();
|
||||
};
|
||||
@ -290,7 +326,7 @@ CustomTabularExporterDialog.prototype._applyOptionCode = function() {
|
||||
|
||||
CustomTabularExporterDialog.prototype._getOptionCode = function() {
|
||||
var options = {
|
||||
format: this._dialog.find('input[name="custom-tabular-exporter-format"]:checked').val()
|
||||
format: this._dialog.find('input[name="custom-tabular-exporter-download-format"]:checked').val()
|
||||
};
|
||||
|
||||
if (options.format == 'tsv' || options.format == 'csv' || options.format == '*sv') {
|
||||
@ -329,3 +365,22 @@ CustomTabularExporterDialog.prototype._getOptionCode = function() {
|
||||
return options;
|
||||
};
|
||||
|
||||
CustomTabularExporterDialog.prototype._upload = function() {
|
||||
var id = this._dialog.find('input[name="custom-tabular-exporter-upload-format"]:checked').val()
|
||||
for (var i = 0; i < CustomTabularExporterDialog.uploadTargets.length; i++) {
|
||||
var target = CustomTabularExporterDialog.uploadTargets[i];
|
||||
if (id == target.id) {
|
||||
var self = this;
|
||||
var options = this._getOptionCode();
|
||||
options.format = id;
|
||||
|
||||
target.handler(
|
||||
options,
|
||||
this._elmts.exportAllRowsCheckbox[0].checked,
|
||||
function() {
|
||||
self._dismiss();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user