More scaffolding.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@4 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-01-26 05:17:14 +00:00
parent e1fa9279eb
commit 9f436ad717
13 changed files with 335 additions and 27 deletions

View File

@ -17,6 +17,7 @@ import org.json.JSONTokener;
import com.metaweb.gridlock.commands.Command;
import com.metaweb.gridlock.commands.CreateProjectFromUploadCommand;
import com.metaweb.gridlock.commands.GetColumnModelCommand;
import com.metaweb.gridlock.commands.GetProjectMetadataCommand;
import com.metaweb.gridlock.commands.GetRowsCommand;
public class GridlockServlet extends HttpServlet {
@ -26,6 +27,7 @@ public class GridlockServlet extends HttpServlet {
static {
_commands.put("create-project-from-upload", new CreateProjectFromUploadCommand());
_commands.put("get-project-metadata", new GetProjectMetadataCommand());
_commands.put("get-column-model", new GetColumnModelCommand());
_commands.put("get-rows", new GetRowsCommand());
}

View File

@ -16,7 +16,7 @@ public class ProjectManager implements Serializable {
private static final long serialVersionUID = -2967415873336723962L;
protected File _dir;
protected Map<Long, ProjectMetadata> _projectsMetadata = new HashMap<Long, ProjectMetadata>();
protected Map<Long, ProjectMetadata> _projectsMetadata;
transient protected Map<Long, Project> _projects;
@ -67,6 +67,9 @@ public class ProjectManager implements Serializable {
private ProjectManager(File dir) {
_dir = dir;
_dir.mkdirs();
_projectsMetadata = new HashMap<Long, ProjectMetadata>();
internalInitialize();
}
@ -88,6 +91,10 @@ public class ProjectManager implements Serializable {
return project;
}
public ProjectMetadata getProjectMetadata(long id) {
return _projectsMetadata.get(id);
}
public Project getProject(long id) {
if (_projects.containsKey(id)) {
return _projects.get(id);

View File

@ -2,9 +2,20 @@ package com.metaweb.gridlock;
import java.io.Serializable;
import org.json.JSONException;
import org.json.JSONObject;
public class ProjectMetadata implements Serializable {
private static final long serialVersionUID = 7959027046468240844L;
public String name;
public String password;
public JSONObject getJSON() throws JSONException {
JSONObject o = new JSONObject();
o.put("name", name);
return o;
}
}

View File

@ -23,8 +23,8 @@ public class CreateProjectFromUploadCommand extends Command {
String content = readFileUpload(request, properties);
ProjectMetadata pm = new ProjectMetadata();
pm.name = properties.getProperty("name");
pm.password = properties.getProperty("password");
pm.name = properties.getProperty("project-name");
pm.password = properties.getProperty("project-password");
Project project = ProjectManager.singleton.createProject(pm);
@ -49,14 +49,14 @@ public class CreateProjectFromUploadCommand extends Command {
if (tab >= 0) {
sep = "\t";
} else {
sep = "\\,";
sep = ",";
}
}
String[] cells = line.split(sep);
if (first) {
first = false;
String[] cells = line.split(sep);
first = false;
for (int c = 0; c < cells.length; c++) {
String cell = cells[c];
if (cell.startsWith("\"") && cell.endsWith("\"")) {
@ -74,13 +74,10 @@ public class CreateProjectFromUploadCommand extends Command {
} else {
Row row = new Row(cellCount);
for (int c = 0; c < cells.length; c++) {
String text = cells[c];
Cell cell = new Cell();
cell.value = parseCellValue(text);
row.cells.add(cell);
if (sep.charAt(0) == ',') {
parseCSVIntoRow(row, line);
} else {
parseTSVIntoRow(row, line);
}
project.rows.add(row);
@ -90,21 +87,66 @@ public class CreateProjectFromUploadCommand extends Command {
redirect(response, "/project.html?project=" + project.id);
}
static public Object parseCellValue(String text) {
if (text.startsWith("\"") && text.endsWith("\"")) {
return text.substring(1, text.length() - 1);
}
try {
return Long.parseLong(text);
} catch (NumberFormatException e) {
static protected void parseTSVIntoRow(Row row, String line) {
String[] cells = line.split("\t");
for (int c = 0; c < cells.length; c++) {
String text = cells[c];
Cell cell = new Cell();
cell.value = parseCellValue(text);
row.cells.add(cell);
}
}
try {
return Double.parseDouble(text);
} catch (NumberFormatException e) {
static protected void parseCSVIntoRow(Row row, String line) {
int start = 0;
while (start < line.length()) {
String text = null;
if (line.charAt(start) == '"') {
int next = line.indexOf('"', start + 1);
if (next < 0) {
text = line.substring(start);
start = line.length();
} else {
text = line.substring(start, next + 1);
start = next + 2;
}
} else {
int next = line.indexOf(',', start);
if (next < 0) {
text = line.substring(start);
start = line.length();
} else {
text = line.substring(start, next);
start = next + 1;
}
}
Cell cell = new Cell();
cell.value = parseCellValue(text);
row.cells.add(cell);
}
}
static public Object parseCellValue(String text) {
if (text.length() > 0) {
if (text.length() > 1 && text.startsWith("\"") && text.endsWith("\"")) {
return text.substring(1, text.length() - 1);
}
try {
return Long.parseLong(text);
} catch (NumberFormatException e) {
}
try {
return Double.parseDouble(text);
} catch (NumberFormatException e) {
}
}
return text;
}
}

View File

@ -0,0 +1,27 @@
package com.metaweb.gridlock.commands;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import com.metaweb.gridlock.ProjectManager;
import com.metaweb.gridlock.model.Project;
public class GetProjectMetadataCommand extends Command {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Project project = getProject(request);
try {
respondJSON(response, ProjectManager.singleton.getProjectMetadata(project.id).getJSON());
} catch (JSONException e) {
respondException(response, e);
}
}
}

View File

@ -40,6 +40,7 @@ public class GetRowsCommand extends Command {
o.put("start", start);
o.put("limit", limit);
o.put("rows", a);
o.put("total", project.rows.size());
respondJSON(response, o);
} catch (JSONException e) {

View File

@ -1 +1 @@
<html> <head> <title>Gridlock</title> <link rel="stylesheet" href="/styles/common.css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript" src="scripts/util/string.js"></script> <script type="text/javascript" src="scripts/index.js"></script> </head> <body> <div id="header"> <h1>Gridlock</h1> </div> <div id="body"> <h2>New Project</h2> <p>Create a new project by uploading a tab-separated value or comma-separated value file.</p> <form id="file-upload-form" method="post" enctype="multipart/form-data" action="/command/create-project-from-upload"> <table cellspacing="10"> <tr><td>Project Name:</td><td><input type="text" size="30" id="project-name-input" name="project-name" /></td></tr> <tr><td>Project Password:</td><td><input type="password" size="30" id="project-password-input" name="project-password" /><br/>optional, not protected, so use some password you don't care to reveal</td></tr> <tr><td>Upload File:</td><td> <input type="file" id="project-file-input" name="project-file" size="50" /> </td></tr> <tr><td></td><td> <input type="submit" value="Create Project" id="upload-file-button" /> </td></tr> </table> </form> </div> </body> </html>
<html> <head> <title>Gridlock</title> <link rel="stylesheet" href="/styles/common.css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script type="text/javascript" src="scripts/util/string.js"></script> <script type="text/javascript" src="scripts/index.js"></script> </head> <body> <div id="header"> <h1>Gridlock</h1> </div> <div id="body"> <h2>New Project</h2> <p>Create a new project by uploading a tab-separated value or comma-separated value file.</p> <form id="file-upload-form" method="post" enctype="multipart/form-data" action="/command/create-project-from-upload"> <table cellspacing="10"> <tr><td>Project Name:</td><td><input type="text" size="30" id="project-name-input" name="project-name" /></td></tr> <tr><td>Project Password:</td><td><input type="password" size="30" id="project-password-input" name="project-password" /><br/>optional, not protected, so use some password you don't care to reveal</td></tr> <tr><td>Upload File:</td><td> <input type="file" id="project-file-input" name="project-file" size="50" /> </td></tr> <tr><td></td><td> <input type="submit" value="Create Project" id="upload-file-button" /> </td></tr> </table> </form> </div> </body> </html>

View File

@ -1 +1 @@
<html> <head> <title>Gridlock</title> <link rel="stylesheet" href="/styles/common.css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript" src="scripts/util/string.js"></script> <script type="text/javascript" src="scripts/project.js"></script> </head> <body> <div id="header"> <h1 id="title">Gridlock</h1> </div> <div id="body"> Loading ... </div> </body> </html>
<html> <head> <title>Gridlock</title> <link rel="stylesheet" href="/styles/common.css" /> <link rel="stylesheet" href="/styles/project.css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script type="text/javascript" src="scripts/util/url.js"></script> <script type="text/javascript" src="scripts/util/string.js"></script> <script type="text/javascript" src="scripts/util/ajax.js"></script> <script type="text/javascript" src="scripts/project.js"></script> </head> <body> <div id="header"> <h1 id="title">Gridlock</h1> </div> <div id="body"> Loading ... </div> </body> </html>

View File

@ -1,4 +1,153 @@
var theProject;
var ui = {};
function onLoad() {
var params = URL.getParameters();
if ("project" in params) {
theProject = {
id: parseInt(params.project),
view: {
pageSize: 25
}
};
Ajax.chainGetJSON(
"/command/get-project-metadata?" + $.param({ project: theProject.id }), null,
function(data) {
theProject.metadata = data;
},
"/command/get-column-model?" + $.param({ project: theProject.id }), null,
function(data) {
theProject.columnModel = data;
},
"/command/get-rows?" + $.param({ project: theProject.id, start: 0, limit: 25 }), null,
function(data) {
theProject.rowModel = data;
},
function() {
initializeUI();
renderView();
}
);
}
}
$(onLoad);
function initializeUI() {
document.title = theProject.metadata.name + " - Gridlock";
$("#title").html(document.title);
var body = $("#body").empty();
var table = document.createElement("table");
$(table).attr("cellspacing", 20).css("width", "100%");
body.append(table);
var tr = table.insertRow(0);
var tdLeft = tr.insertCell(0);
var tdRight = tr.insertCell(1);
tdLeft.setAttribute("width", "75%");
tdRight.setAttribute("width", "25%");
ui.viewPanel = $('<div></div>').appendTo(tdLeft).css("width", tdLeft.offsetWidth + "px").css("overflow-x", "auto");
ui.facetPanel = $('<div></div>').appendTo(tdRight);
}
function renderView() {
ui.viewPanel.empty();
var divSummary = $('<div></div>').addClass("viewPanel-summary").appendTo(ui.viewPanel);
$('<span>' +
(theProject.rowModel.start + 1) + " to " +
(theProject.rowModel.start + theProject.rowModel.limit) + " of " +
(theProject.rowModel.total) +
" rows total" +
'</span>'
).appendTo(divSummary);
var pagingControls = $('<div></div>').addClass("viewPanel-pagingControls").appendTo(ui.viewPanel);
var firstPage = $('<a href="javascript:{}">&laquo; first</a>').appendTo(pagingControls);
var previousPage = $('<a href="javascript:{}">&laquo; previous</a>').appendTo(pagingControls);
if (theProject.rowModel.start > 0) {
firstPage.addClass("action").click(onClickFirstPage);
previousPage.addClass("action").click(onClickPreviousPage);
} else {
firstPage.addClass("inaction");
previousPage.addClass("inaction");
}
$('<span> &bull; </span>').appendTo(pagingControls);
var nextPage = $('<a href="javascript:{}">next page &raquo;</a>').appendTo(pagingControls);
var lastPage = $('<a href="javascript:{}">last &raquo;</a>').appendTo(pagingControls);
if (theProject.rowModel.start + theProject.rowModel.limit < theProject.rowModel.total) {
nextPage.addClass("action").click(onClickNextPage);
lastPage.addClass("action").click(onClickLastPage);
} else {
nextPage.addClass("inaction");
lastPage.addClass("inaction");
}
var table = document.createElement("table");
table.className = "data-table";
ui.viewPanel.append(table);
var trHead = table.insertRow(0);
var td = trHead.insertCell(trHead.cells.length);
var columns = theProject.columnModel.columns;
for (var i = 0; i < columns.length; i++) {
var column = columns[i];
var td = trHead.insertCell(trHead.cells.length);
$(td).html(column.headerLabel);
}
var rows = theProject.rowModel.rows;
for (var r = 0; r < rows.length; r++) {
var row = rows[r];
var cells = row.cells;
var tr = table.insertRow(table.rows.length);
tr.className = (r % 2) == 1 ? "odd" : "even";
var td = tr.insertCell(tr.cells.length);
$(td).html((theProject.rowModel.start + r + 1) + ".");
for (var i = 0; i < columns.length; i++) {
var column = columns[i];
var td = tr.insertCell(tr.cells.length);
if (column.cellIndex < cells.length) {
var cell = cells[column.cellIndex];
if (cell.v != null) {
$(td).html(cell.v);
}
}
}
}
}
function showRows(start, onDone) {
Ajax.chainGetJSON(
"/command/get-rows?" + $.param({ project: theProject.id, start: start, limit: theProject.view.pageSize }), null,
function(data) {
theProject.rowModel = data;
renderView();
}
);
}
function onClickPreviousPage() {
showRows(theProject.rowModel.start - theProject.view.pageSize);
}
function onClickNextPage() {
showRows(theProject.rowModel.start + theProject.view.pageSize);
}
function onClickFirstPage() {
showRows(0, theProject.view.pageSize);
}
function onClickLastPage() {
showRows(Math.floor(theProject.rowModel.total / theProject.view.pageSize) * theProject.view.pageSize);
}

View File

@ -0,0 +1,22 @@
Ajax = {};
Ajax.chainGetJSON = function() {
var a = arguments;
var i = 0;
var next = function() {
if (i <= a.length - 3) {
var url = a[i++];
var data = a[i++];
var callback = a[i++];
$.getJSON(url, data, function(o) {
callback(o);
next();
}, "json");
} else if (i < a.length) {
var finalCallback = a[i++];
finalCallback();
}
};
next();
};

View File

@ -0,0 +1,16 @@
URL = {};
URL.getParameters = function() {
var r = {};
var params = window.location.search;
if (params.length > 1) {
params = params.substr(1).split("&");
$.each(params, function() {
pair = this.split("=");
r[pair[0]] = unescape(pair[1]);
});
}
return r;
};

View File

@ -30,3 +30,17 @@ tr, td {
padding: 20px;
}
a.action {
margin: 0 3px;
text-decoration: none;
color: #448;
}
a.action:hover {
color: #88f;
}
a.inaction {
margin: 0 3px;
text-decoration: none;
color: #ccc;
}

View File

@ -0,0 +1,17 @@
table.data-table td {
padding: 2px 5px;
}
table.data-table tr.odd {
}
table.data-table tr.even {
background: #eee;
}
.viewPanel-summary {
}
.viewPanel-pagingControls {
text-align: center;
margin: 1em 0;
}