Started supporting resource creation by form
git-svn-id: http://svn.d4science-ii.research-infrastructures.eu/gcube/trunk/portlets/widgets/ckan-metadata-publisher-widget@129011 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
acd1343032
commit
60ecb288d6
4
pom.xml
4
pom.xml
|
@ -156,9 +156,9 @@
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.dataaccess</groupId>
|
<groupId>org.gcube.data-catalogue</groupId>
|
||||||
<artifactId>ckan-util-library</artifactId>
|
<artifactId>ckan-util-library</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.core</groupId>
|
<groupId>org.gcube.core</groupId>
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client;
|
||||||
|
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.RemoteService;
|
import com.google.gwt.user.client.rpc.RemoteService;
|
||||||
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
|
||||||
|
@ -31,8 +32,17 @@ public interface CKanPublisherService extends RemoteService {
|
||||||
/**
|
/**
|
||||||
* Try to create such dataset starting from the information contained into the toCreate bean.
|
* Try to create such dataset starting from the information contained into the toCreate bean.
|
||||||
* @param toCreate
|
* @param toCreate
|
||||||
* @return <b>true</b> on success, <b>false</b> otherwise
|
* @return the identifier of the created dataset or null on error
|
||||||
*/
|
*/
|
||||||
boolean createCKanDataset(DatasetMetadataBean toCreate);
|
String createCKanDataset(DatasetMetadataBean toCreate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add this resource to the dataset whose id is datasetId
|
||||||
|
* @param resource
|
||||||
|
* @param datasetId
|
||||||
|
* @param owner of the dataset
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
boolean addResourceToDataset(ResourceBean resource, String datasetId, String owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client;
|
||||||
|
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
|
|
||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
|
||||||
|
@ -33,6 +34,16 @@ public interface CKanPublisherServiceAsync {
|
||||||
* @return <b>true</b> on success, <b>false</b> otherwise
|
* @return <b>true</b> on success, <b>false</b> otherwise
|
||||||
*/
|
*/
|
||||||
void createCKanDataset(DatasetMetadataBean toCreate,
|
void createCKanDataset(DatasetMetadataBean toCreate,
|
||||||
|
AsyncCallback<String> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add this resource to the dataset whose id is datasetId
|
||||||
|
* @param resource
|
||||||
|
* @param datasetId
|
||||||
|
* @param owner of the dataset
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
void addResourceToDataset(ResourceBean resource, String datasetId, String owner,
|
||||||
AsyncCallback<Boolean> callback);
|
AsyncCallback<Boolean> callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.client.events;
|
||||||
|
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
|
|
||||||
|
import com.google.gwt.event.shared.GwtEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Added resource event
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
|
public class AddResourceEvent extends GwtEvent<AddResourceEventHandler> {
|
||||||
|
public static Type<AddResourceEventHandler> TYPE = new Type<AddResourceEventHandler>();
|
||||||
|
|
||||||
|
private ResourceBean resource;
|
||||||
|
|
||||||
|
public AddResourceEvent(ResourceBean resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBean getResource() {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<AddResourceEventHandler> getAssociatedType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dispatch(AddResourceEventHandler handler) {
|
||||||
|
handler.onAddedResource(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.client.events;
|
||||||
|
|
||||||
|
import com.google.gwt.event.shared.EventHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Added resource handler interface
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
|
public interface AddResourceEventHandler extends EventHandler {
|
||||||
|
void onAddedResource(AddResourceEvent addResourceEvent);
|
||||||
|
}
|
|
@ -3,7 +3,10 @@ import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.CustomFieldE
|
||||||
|
|
||||||
import com.google.gwt.event.shared.GwtEvent;
|
import com.google.gwt.event.shared.GwtEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete custom field event.
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
public class DeleteCustomFieldEvent extends GwtEvent<DeleteCustomFieldEventHandler> {
|
public class DeleteCustomFieldEvent extends GwtEvent<DeleteCustomFieldEventHandler> {
|
||||||
public static Type<DeleteCustomFieldEventHandler> TYPE = new Type<DeleteCustomFieldEventHandler>();
|
public static Type<DeleteCustomFieldEventHandler> TYPE = new Type<DeleteCustomFieldEventHandler>();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client.events;
|
||||||
|
|
||||||
import com.google.gwt.event.shared.EventHandler;
|
import com.google.gwt.event.shared.EventHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler associated to the DeleteCustomFieldEvent
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
public interface DeleteCustomFieldEventHandler extends EventHandler {
|
public interface DeleteCustomFieldEventHandler extends EventHandler {
|
||||||
void onRemoveEntry(DeleteCustomFieldEvent event);
|
void onRemoveEntry(DeleteCustomFieldEvent event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui;
|
||||||
|
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.AddResourceEvent;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
|
|
||||||
|
import com.github.gwtbootstrap.client.ui.AlertBlock;
|
||||||
|
import com.github.gwtbootstrap.client.ui.Button;
|
||||||
|
import com.github.gwtbootstrap.client.ui.TextArea;
|
||||||
|
import com.github.gwtbootstrap.client.ui.TextBox;
|
||||||
|
import com.github.gwtbootstrap.client.ui.constants.AlertType;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.shared.HandlerManager;
|
||||||
|
import com.google.gwt.uibinder.client.UiBinder;
|
||||||
|
import com.google.gwt.uibinder.client.UiField;
|
||||||
|
import com.google.gwt.uibinder.client.UiHandler;
|
||||||
|
import com.google.gwt.user.client.Timer;
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form used to add resource(s) to a dataset
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
|
public class AddResourceToDataset extends Composite{
|
||||||
|
|
||||||
|
private static AddResourceToDatasetUiBinder uiBinder = GWT
|
||||||
|
.create(AddResourceToDatasetUiBinder.class);
|
||||||
|
|
||||||
|
interface AddResourceToDatasetUiBinder extends
|
||||||
|
UiBinder<Widget, AddResourceToDataset> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// bus to alert the dataset form about this new resource
|
||||||
|
private HandlerManager eventBus;
|
||||||
|
|
||||||
|
// the dataset id
|
||||||
|
private String datasetId;
|
||||||
|
|
||||||
|
// the owner
|
||||||
|
private String owner;
|
||||||
|
|
||||||
|
//Create a remote service proxy to talk to the server-side ckan service.
|
||||||
|
private final CKanPublisherServiceAsync ckanServices = GWT.create(CKanPublisherService.class);
|
||||||
|
|
||||||
|
@UiField TextBox resourceUrlTextBox;
|
||||||
|
@UiField TextBox resourceNameTextBox;
|
||||||
|
@UiField TextArea resourceDescriptionTextArea;
|
||||||
|
@UiField Button addResourceButton;
|
||||||
|
@UiField AlertBlock infoBlock;
|
||||||
|
|
||||||
|
public AddResourceToDataset(HandlerManager eventBus, String datasetId, String owner) {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
|
||||||
|
// save bus
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
|
||||||
|
// save dataset id (it is needed when we will add resources)
|
||||||
|
this.datasetId = datasetId;
|
||||||
|
|
||||||
|
// the owner of the dataset/files
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("addResourceButton")
|
||||||
|
void onAddButtonClick(ClickEvent e){
|
||||||
|
|
||||||
|
infoBlock.setVisible(false);
|
||||||
|
|
||||||
|
// validation
|
||||||
|
if(resourceUrlTextBox.getText().isEmpty()){
|
||||||
|
|
||||||
|
infoBlock.setType(AlertType.ERROR);
|
||||||
|
infoBlock.setText("URL cannot be empty");
|
||||||
|
infoBlock.setVisible(true);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove html tags into description
|
||||||
|
//String description = convert(resourceDescriptionTextArea.getText()); TODO
|
||||||
|
|
||||||
|
// collect data and build up the bean
|
||||||
|
final ResourceBean resource = new ResourceBean(resourceUrlTextBox.getText(), resourceNameTextBox.getText(), resourceDescriptionTextArea.getText());
|
||||||
|
|
||||||
|
// disable add button
|
||||||
|
addResourceButton.setEnabled(false);
|
||||||
|
|
||||||
|
// try to create
|
||||||
|
ckanServices.addResourceToDataset(resource, datasetId, owner, new AsyncCallback<Boolean>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Boolean result) {
|
||||||
|
|
||||||
|
if(result){
|
||||||
|
showAlert("Resource created correctly", AlertType.SUCCESS);
|
||||||
|
eventBus.fireEvent(new AddResourceEvent(resource));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
showAlert("Unable to add this resource. Check the url is correct", AlertType.ERROR);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
|
||||||
|
showAlert("Unable to add this resource, sorry", AlertType.ERROR);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show error/success after resource creation attempt.
|
||||||
|
* @param text
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
protected void showAlert(String text, AlertType type) {
|
||||||
|
|
||||||
|
infoBlock.setText(text);
|
||||||
|
infoBlock.setType(type);
|
||||||
|
infoBlock.setVisible(true);
|
||||||
|
addResourceButton.setEnabled(true);
|
||||||
|
|
||||||
|
// hide after some seconds
|
||||||
|
Timer t = new Timer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
infoBlock.setVisible(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
t.schedule(4000);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||||
|
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||||
|
xmlns:b="urn:import:com.github.gwtbootstrap.client.ui" xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||||
|
<ui:style>
|
||||||
|
.form-main-style {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset-border-style {
|
||||||
|
border: 1px groove #444;
|
||||||
|
-webkit-box-shadow: 0px 0px 0px 0px #000;
|
||||||
|
box-shadow: 0px 0px 0px 0px #000;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-style {
|
||||||
|
width: auto;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@external .form-horizontal .input-large;
|
||||||
|
.form-horizontal .input-large {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-alert-style {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagsPanelStyle {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-resource-button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-markdown {
|
||||||
|
width: 95%;
|
||||||
|
background-color: #ebebeb;
|
||||||
|
border-bottom: 1px thin;
|
||||||
|
border-left: 1px thin;
|
||||||
|
border-right: 1px thin;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<b:Form type="HORIZONTAL" styleName="{style.form-main-style}"
|
||||||
|
ui:field="form">
|
||||||
|
<b:Fieldset styleName="{style.fieldset-border-style}">
|
||||||
|
|
||||||
|
<b:Legend styleName="{style.legend-style}">
|
||||||
|
Add Resource
|
||||||
|
<small>
|
||||||
|
<span style="color:red;">*</span>
|
||||||
|
is required
|
||||||
|
</small>
|
||||||
|
</b:Legend>
|
||||||
|
|
||||||
|
<b:ControlGroup>
|
||||||
|
<b:ControlLabel for="url" title="File url">
|
||||||
|
<font color="red">*</font>
|
||||||
|
URL:
|
||||||
|
</b:ControlLabel>
|
||||||
|
<b:Controls>
|
||||||
|
<b:TextBox alternateSize="LARGE" placeholder="http://example.com/image.jpg"
|
||||||
|
b:id="url" title="Dataset title" ui:field="resourceUrlTextBox" />
|
||||||
|
</b:Controls>
|
||||||
|
</b:ControlGroup>
|
||||||
|
|
||||||
|
<b:ControlGroup>
|
||||||
|
<b:ControlLabel for="name" title="Resource name">
|
||||||
|
Name:
|
||||||
|
</b:ControlLabel>
|
||||||
|
<b:Controls>
|
||||||
|
<b:TextBox alternateSize="LARGE" placeholder="my-image"
|
||||||
|
b:id="name" title="Resource name" ui:field="resourceNameTextBox" />
|
||||||
|
</b:Controls>
|
||||||
|
</b:ControlGroup>
|
||||||
|
|
||||||
|
<b:ControlGroup>
|
||||||
|
<b:ControlLabel for="description" title="Resource description">
|
||||||
|
Description:
|
||||||
|
</b:ControlLabel>
|
||||||
|
<b:Controls>
|
||||||
|
<b:TextArea alternateSize="LARGE"
|
||||||
|
placeholder="Some useful notes about data" b:id="description"
|
||||||
|
title="Resource description" ui:field="resourceDescriptionTextArea" />
|
||||||
|
<b:Paragraph styleName="{style.info-markdown}">
|
||||||
|
You can use
|
||||||
|
<b:Popover html="true"
|
||||||
|
text="__Bold text__ or _italic text_
|
||||||
|
# title
|
||||||
|
## secondary title
|
||||||
|
### etc
|
||||||
|
|
||||||
|
* list
|
||||||
|
* of
|
||||||
|
* items
|
||||||
|
|
||||||
|
http://auto.link.ed/
|
||||||
|
|
||||||
|
Please note: HTML tags are stripped out for security reasons"
|
||||||
|
heading="Markdown short guide">
|
||||||
|
<b:Button type="LINK">Markdown formatting</b:Button>
|
||||||
|
</b:Popover>
|
||||||
|
</b:Paragraph>
|
||||||
|
</b:Controls>
|
||||||
|
</b:ControlGroup>
|
||||||
|
|
||||||
|
<!-- Alert blocks for info/errors -->
|
||||||
|
<b:AlertBlock type="INFO" animation="true" visible="false"
|
||||||
|
ui:field="infoBlock" styleName="{style.block-alert-style}"></b:AlertBlock>
|
||||||
|
|
||||||
|
<!-- Add resource button -->
|
||||||
|
<b:Button title="Add resource" ui:field="addResourceButton" >Add</b:Button>
|
||||||
|
|
||||||
|
</b:Fieldset>
|
||||||
|
</b:Form>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
|
@ -0,0 +1,134 @@
|
||||||
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.AddResourceEvent;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.AddResourceEventHandler;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
|
|
||||||
|
import com.github.gwtbootstrap.client.ui.Button;
|
||||||
|
import com.github.gwtbootstrap.client.ui.constants.ButtonType;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.event.shared.HandlerManager;
|
||||||
|
import com.google.gwt.uibinder.client.UiBinder;
|
||||||
|
import com.google.gwt.uibinder.client.UiField;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of the added resources by the user.
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
|
public class AddedResourcesSummary extends Composite{
|
||||||
|
|
||||||
|
private static AddedResourcesSummaryUiBinder uiBinder = GWT
|
||||||
|
.create(AddedResourcesSummaryUiBinder.class);
|
||||||
|
|
||||||
|
interface AddedResourcesSummaryUiBinder extends
|
||||||
|
UiBinder<Widget, AddedResourcesSummary> {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event bus
|
||||||
|
private HandlerManager eventBus;
|
||||||
|
|
||||||
|
// list of added resources
|
||||||
|
List<ResourceBean> addedResources;
|
||||||
|
|
||||||
|
@UiField VerticalPanel addResourcesPanel;
|
||||||
|
|
||||||
|
public AddedResourcesSummary(HandlerManager eventBus) {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
|
||||||
|
// save bus
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
|
||||||
|
// bind on add resource event
|
||||||
|
bind();
|
||||||
|
|
||||||
|
// init list
|
||||||
|
addedResources = new ArrayList<ResourceBean>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bind() {
|
||||||
|
|
||||||
|
// when a new resource is added
|
||||||
|
eventBus.addHandler(AddResourceEvent.TYPE, new AddResourceEventHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAddedResource(AddResourceEvent addResourceEvent) {
|
||||||
|
|
||||||
|
// get the resource
|
||||||
|
final ResourceBean justAddedResource = addResourceEvent.getResource();
|
||||||
|
|
||||||
|
// check if a resource with this id already exists
|
||||||
|
for (ResourceBean resource : addedResources){
|
||||||
|
|
||||||
|
if(resource.getId().equals(justAddedResource.getId())){
|
||||||
|
|
||||||
|
// clear list and rebuild
|
||||||
|
rebuildSummary();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button associatedButton = new Button();
|
||||||
|
associatedButton.setType(ButtonType.LINK);
|
||||||
|
associatedButton.setText("-" + justAddedResource.getName());
|
||||||
|
|
||||||
|
// add to the list
|
||||||
|
addedResources.add(justAddedResource);
|
||||||
|
|
||||||
|
// add to the panel
|
||||||
|
addResourcesPanel.add(associatedButton);
|
||||||
|
|
||||||
|
// add handler to swap tab on click
|
||||||
|
associatedButton.addClickHandler(new ClickHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
|
||||||
|
// TODO show information below this link and swap panel
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuild the summary list
|
||||||
|
*/
|
||||||
|
protected void rebuildSummary() {
|
||||||
|
|
||||||
|
addResourcesPanel.clear();
|
||||||
|
|
||||||
|
for (final ResourceBean resource : addedResources){
|
||||||
|
|
||||||
|
Button associatedButton = new Button();
|
||||||
|
associatedButton.setType(ButtonType.LINK);
|
||||||
|
associatedButton.setText("-" + resource.getName());
|
||||||
|
|
||||||
|
// add to the list
|
||||||
|
addedResources.add(resource);
|
||||||
|
|
||||||
|
// add to the panel
|
||||||
|
addResourcesPanel.add(associatedButton);
|
||||||
|
|
||||||
|
// add handler to swap tab on click
|
||||||
|
associatedButton.addClickHandler(new ClickHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
|
||||||
|
// TODO show information below this link and swap panel
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||||
|
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||||
|
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||||
|
<ui:style>
|
||||||
|
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<h2>Added Resources</h2>
|
||||||
|
<g:VerticalPanel ui:field="addResourcesPanel"></g:VerticalPanel>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringEscapeUtils;
|
|
||||||
import org.gcube.portlets.user.gcubewidgets.client.elements.Span;
|
import org.gcube.portlets.user.gcubewidgets.client.elements.Span;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync;
|
||||||
|
@ -20,12 +19,14 @@ import com.github.gwtbootstrap.client.ui.AlertBlock;
|
||||||
import com.github.gwtbootstrap.client.ui.Button;
|
import com.github.gwtbootstrap.client.ui.Button;
|
||||||
import com.github.gwtbootstrap.client.ui.CheckBox;
|
import com.github.gwtbootstrap.client.ui.CheckBox;
|
||||||
import com.github.gwtbootstrap.client.ui.ControlGroup;
|
import com.github.gwtbootstrap.client.ui.ControlGroup;
|
||||||
import com.github.gwtbootstrap.client.ui.HelpBlock;
|
|
||||||
import com.github.gwtbootstrap.client.ui.ListBox;
|
import com.github.gwtbootstrap.client.ui.ListBox;
|
||||||
|
import com.github.gwtbootstrap.client.ui.Tab;
|
||||||
|
import com.github.gwtbootstrap.client.ui.TabPanel;
|
||||||
import com.github.gwtbootstrap.client.ui.TextArea;
|
import com.github.gwtbootstrap.client.ui.TextArea;
|
||||||
import com.github.gwtbootstrap.client.ui.TextBox;
|
import com.github.gwtbootstrap.client.ui.TextBox;
|
||||||
import com.github.gwtbootstrap.client.ui.base.ListItem;
|
import com.github.gwtbootstrap.client.ui.base.ListItem;
|
||||||
import com.github.gwtbootstrap.client.ui.constants.AlertType;
|
import com.github.gwtbootstrap.client.ui.constants.AlertType;
|
||||||
|
import com.github.gwtbootstrap.client.ui.resources.Bootstrap.Tabs;
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
import com.google.gwt.event.dom.client.ClickHandler;
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
@ -39,6 +40,7 @@ import com.google.gwt.user.client.Timer;
|
||||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.google.gwt.user.client.ui.Composite;
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +67,6 @@ public class EditMetadataForm extends Composite{
|
||||||
@UiField FlowPanel tagsPanel;
|
@UiField FlowPanel tagsPanel;
|
||||||
@UiField ListBox licenseListbox;
|
@UiField ListBox licenseListbox;
|
||||||
@UiField ListBox visibilityListbox;
|
@UiField ListBox visibilityListbox;
|
||||||
@UiField ListBox searchableListbox;
|
|
||||||
@UiField ListBox organizationsListbox;
|
@UiField ListBox organizationsListbox;
|
||||||
@UiField TextBox versionTextbox;
|
@UiField TextBox versionTextbox;
|
||||||
@UiField TextBox authorTextbox;
|
@UiField TextBox authorTextbox;
|
||||||
|
@ -75,10 +76,19 @@ public class EditMetadataForm extends Composite{
|
||||||
@UiField ControlGroup customFields;
|
@UiField ControlGroup customFields;
|
||||||
@UiField Button addCustomFieldButton;
|
@UiField Button addCustomFieldButton;
|
||||||
@UiField CheckBox addResourcesCheckBox;
|
@UiField CheckBox addResourcesCheckBox;
|
||||||
|
@UiField ControlGroup resourcesControlGroup;
|
||||||
@UiField Button createButton;
|
@UiField Button createButton;
|
||||||
|
@UiField Button addResourcesButton;
|
||||||
@UiField Button resetButton;
|
@UiField Button resetButton;
|
||||||
@UiField AlertBlock infoBlock;
|
@UiField AlertBlock infoBlock;
|
||||||
@UiField AlertBlock onCreateAlertBlock;
|
@UiField AlertBlock onCreateAlertBlock;
|
||||||
|
@UiField VerticalPanel resourcesPanel;
|
||||||
|
|
||||||
|
// tab panel
|
||||||
|
private TabPanel tabPanel;
|
||||||
|
|
||||||
|
// add resource form
|
||||||
|
AddResourceToDataset resourceForm;
|
||||||
|
|
||||||
// tags list
|
// tags list
|
||||||
private List<String> tagsList = new ArrayList<String>();
|
private List<String> tagsList = new ArrayList<String>();
|
||||||
|
@ -95,14 +105,18 @@ public class EditMetadataForm extends Composite{
|
||||||
// dataset metadata bean
|
// dataset metadata bean
|
||||||
private DatasetMetadataBean receivedBean;
|
private DatasetMetadataBean receivedBean;
|
||||||
|
|
||||||
|
// the owner
|
||||||
|
private String owner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked in the most general case
|
* Invoked in the most general case
|
||||||
* @param owner
|
* @param owner
|
||||||
*/
|
*/
|
||||||
public EditMetadataForm(String user) {
|
public EditMetadataForm(String owner) {
|
||||||
initWidget(uiBinder.createAndBindUi(this));
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
|
||||||
// bind on events
|
// bind on events
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
|
@ -114,7 +128,7 @@ public class EditMetadataForm extends Composite{
|
||||||
resetButton.setEnabled(false);
|
resetButton.setEnabled(false);
|
||||||
|
|
||||||
// get back the licenses and the metadata information
|
// get back the licenses and the metadata information
|
||||||
ckanServices.getDatasetBean(null, user, new AsyncCallback<DatasetMetadataBean>() {
|
ckanServices.getDatasetBean(null, owner, new AsyncCallback<DatasetMetadataBean>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(DatasetMetadataBean bean) {
|
public void onSuccess(DatasetMetadataBean bean) {
|
||||||
|
@ -187,6 +201,9 @@ public class EditMetadataForm extends Composite{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// hide the Add resources checkbox
|
||||||
|
resourcesControlGroup.setVisible(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,6 +214,8 @@ public class EditMetadataForm extends Composite{
|
||||||
public EditMetadataForm(String idFolderWorkspace, String owner) {
|
public EditMetadataForm(String idFolderWorkspace, String owner) {
|
||||||
initWidget(uiBinder.createAndBindUi(this));
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
|
||||||
// bind on events
|
// bind on events
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
|
@ -355,7 +374,6 @@ public class EditMetadataForm extends Composite{
|
||||||
String description = descriptionTextarea.getText();
|
String description = descriptionTextarea.getText();
|
||||||
String selectedLicense = licenseListbox.getSelectedItemText();
|
String selectedLicense = licenseListbox.getSelectedItemText();
|
||||||
String visibility = visibilityListbox.getSelectedItemText();
|
String visibility = visibilityListbox.getSelectedItemText();
|
||||||
String searchable = searchableListbox.getSelectedItemText();
|
|
||||||
long version = Long.valueOf(versionTextbox.getValue());
|
long version = Long.valueOf(versionTextbox.getValue());
|
||||||
String author = authorTextbox.getValue();
|
String author = authorTextbox.getValue();
|
||||||
String authorEmail = authorEmailTextbox.getValue();
|
String authorEmail = authorEmailTextbox.getValue();
|
||||||
|
@ -374,7 +392,6 @@ public class EditMetadataForm extends Composite{
|
||||||
receivedBean.setVersion(version);
|
receivedBean.setVersion(version);
|
||||||
receivedBean.setVisibility(visibility.equals("Public"));
|
receivedBean.setVisibility(visibility.equals("Public"));
|
||||||
receivedBean.setTitle(title);
|
receivedBean.setTitle(title);
|
||||||
receivedBean.setSearchable(searchable.equals("Yes"));
|
|
||||||
receivedBean.setTags(tagsList);
|
receivedBean.setTags(tagsList);
|
||||||
receivedBean.setSelectedOrganization(chosenOrganization);
|
receivedBean.setSelectedOrganization(chosenOrganization);
|
||||||
receivedBean.setAddResources(addResources);
|
receivedBean.setAddResources(addResources);
|
||||||
|
@ -399,15 +416,62 @@ public class EditMetadataForm extends Composite{
|
||||||
onCreateAlertBlock.setText("Trying to create dataset, please wait");
|
onCreateAlertBlock.setText("Trying to create dataset, please wait");
|
||||||
onCreateAlertBlock.setVisible(true);
|
onCreateAlertBlock.setVisible(true);
|
||||||
|
|
||||||
ckanServices.createCKanDataset(receivedBean, new AsyncCallback<Boolean>() {
|
ckanServices.createCKanDataset(receivedBean, new AsyncCallback<String>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Boolean result) {
|
public void onSuccess(final String datasetId) {
|
||||||
|
|
||||||
if(result){
|
if(datasetId != null){
|
||||||
|
|
||||||
alertOnCreate("Dataset correctly created!", AlertType.SUCCESS);
|
alertOnCreate("Dataset correctly created!", AlertType.SUCCESS);
|
||||||
|
|
||||||
|
// disable dataset fields
|
||||||
|
disableDatasetFields();
|
||||||
|
|
||||||
|
// if we are in the "general case" we need to show a form for adding resources
|
||||||
|
if(!resourcesControlGroup.isVisible()){
|
||||||
|
|
||||||
|
createButton.setVisible(false);
|
||||||
|
resetButton.setVisible(false);
|
||||||
|
|
||||||
|
// show the add resources button
|
||||||
|
addResourcesButton.setVisible(true);
|
||||||
|
addResourcesButton.addClickHandler(new ClickHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
|
||||||
|
// hide the button
|
||||||
|
addResourcesButton.setVisible(false);
|
||||||
|
|
||||||
|
// TabPanel
|
||||||
|
tabPanel = new TabPanel(Tabs.ABOVE);
|
||||||
|
tabPanel.setWidth("100%");
|
||||||
|
|
||||||
|
// add the form
|
||||||
|
resourceForm = new AddResourceToDataset(eventBus, datasetId, owner);
|
||||||
|
|
||||||
|
// tab for the form
|
||||||
|
Tab formContainer = new Tab();
|
||||||
|
formContainer.add(resourceForm);
|
||||||
|
formContainer.setHeading("Add New Resource");
|
||||||
|
tabPanel.add(formContainer);
|
||||||
|
|
||||||
|
// tab for the added resources
|
||||||
|
Tab addedResources = new Tab();
|
||||||
|
addedResources.add(new AddedResourcesSummary(eventBus));
|
||||||
|
addedResources.setHeading("Added Resource");
|
||||||
|
tabPanel.add(addedResources);
|
||||||
|
|
||||||
|
// add tabs to resources panel
|
||||||
|
tabPanel.selectTab(0);
|
||||||
|
resourcesPanel.add(tabPanel);
|
||||||
|
resourcesPanel.setVisible(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
alertOnCreate("Unable to create this dataset, please retry later", AlertType.ERROR);
|
alertOnCreate("Unable to create this dataset, please retry later", AlertType.ERROR);
|
||||||
|
@ -458,7 +522,7 @@ public class EditMetadataForm extends Composite{
|
||||||
*/
|
*/
|
||||||
private boolean validateData() {
|
private boolean validateData() {
|
||||||
|
|
||||||
|
// TODO
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,6 +547,24 @@ public class EditMetadataForm extends Composite{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable dataset editable fields
|
||||||
|
*/
|
||||||
|
protected void disableDatasetFields() {
|
||||||
|
titleTextBox.setEnabled(false);
|
||||||
|
descriptionTextarea.setEnabled(false);
|
||||||
|
versionTextbox.setEnabled(false);
|
||||||
|
authorTextbox.setEnabled(false);
|
||||||
|
authorEmailTextbox.setEnabled(false);
|
||||||
|
maintainerTextbox.setEnabled(false);
|
||||||
|
maintainerEmailTextbox.setEnabled(false);
|
||||||
|
visibilityListbox.setEnabled(false);
|
||||||
|
tagsEnterTextBox.setEnabled(false);
|
||||||
|
licenseListbox.setEnabled(false);
|
||||||
|
organizationsListbox.setEnabled(false);
|
||||||
|
addCustomFieldButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* change alert block behavior.
|
* change alert block behavior.
|
||||||
* @param textToShow
|
* @param textToShow
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
@external .form-horizontal .input-large;
|
@external .form-horizontal .input-large;
|
||||||
.form-horizontal .input-large {
|
.form-horizontal .input-large {
|
||||||
width: 95%;
|
width: 95%;
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.block-alert-style {
|
.block-alert-style {
|
||||||
|
@ -34,6 +33,15 @@
|
||||||
.tagsPanelStyle {
|
.tagsPanelStyle {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-markdown {
|
||||||
|
width: 95%;
|
||||||
|
background-color: #ebebeb;
|
||||||
|
border-bottom: 1px thin;
|
||||||
|
border-left: 1px thin;
|
||||||
|
border-right: 1px thin;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
</ui:style>
|
</ui:style>
|
||||||
<g:HTMLPanel>
|
<g:HTMLPanel>
|
||||||
<b:Form type="HORIZONTAL" styleName="{style.form-main-style}"
|
<b:Form type="HORIZONTAL" styleName="{style.form-main-style}"
|
||||||
|
@ -83,6 +91,25 @@
|
||||||
<b:TextArea placeholder="eg. Some useful notes about the data"
|
<b:TextArea placeholder="eg. Some useful notes about the data"
|
||||||
alternateSize="LARGE" b:id="description" title="Dataset description"
|
alternateSize="LARGE" b:id="description" title="Dataset description"
|
||||||
ui:field="descriptionTextarea"></b:TextArea>
|
ui:field="descriptionTextarea"></b:TextArea>
|
||||||
|
<b:Paragraph styleName="{style.info-markdown}">
|
||||||
|
You can use
|
||||||
|
<b:Popover html="true"
|
||||||
|
text="__Bold text__ or _italic text_
|
||||||
|
# title
|
||||||
|
## secondary title
|
||||||
|
### etc
|
||||||
|
|
||||||
|
* list
|
||||||
|
* of
|
||||||
|
* items
|
||||||
|
|
||||||
|
http://auto.link.ed/
|
||||||
|
|
||||||
|
Please note: HTML tags are stripped out for security reasons"
|
||||||
|
heading="Markdown formatting short guide">
|
||||||
|
<b:Button type="LINK">Markdown formatting</b:Button>
|
||||||
|
</b:Popover>
|
||||||
|
</b:Paragraph>
|
||||||
</b:Controls>
|
</b:Controls>
|
||||||
</b:ControlGroup>
|
</b:ControlGroup>
|
||||||
|
|
||||||
|
@ -135,23 +162,6 @@
|
||||||
</b:Controls>
|
</b:Controls>
|
||||||
</b:ControlGroup>
|
</b:ControlGroup>
|
||||||
|
|
||||||
<b:ControlGroup>
|
|
||||||
<b:ControlLabel for="searchable" title="Searchable">Searchable:</b:ControlLabel>
|
|
||||||
<b:Controls>
|
|
||||||
<b:ListBox b:id="searchable" title="Dataset searchable"
|
|
||||||
width="70%" ui:field="searchableListbox">
|
|
||||||
<g:item enabled="true" title="Yes">Yes</g:item>
|
|
||||||
<g:item title="No">No</g:item>
|
|
||||||
</b:ListBox>
|
|
||||||
<span style="float:right; width:256px;color: #aaaaaa;">
|
|
||||||
<b:Icon type="INFO_SIGN" size="TWO_TIMES" />
|
|
||||||
Searchable datasets can be searched by anyone, while
|
|
||||||
not-searchable datasets can only be accessed by entering directly
|
|
||||||
its URL.
|
|
||||||
</span>
|
|
||||||
</b:Controls>
|
|
||||||
</b:ControlGroup>
|
|
||||||
|
|
||||||
<b:ControlGroup>
|
<b:ControlGroup>
|
||||||
<b:ControlLabel for="organization" title="Organizations">Publish in:</b:ControlLabel>
|
<b:ControlLabel for="organization" title="Organizations">Publish in:</b:ControlLabel>
|
||||||
<b:Controls>
|
<b:Controls>
|
||||||
|
@ -233,7 +243,7 @@
|
||||||
</b:Controls>
|
</b:Controls>
|
||||||
</b:ControlGroup>
|
</b:ControlGroup>
|
||||||
|
|
||||||
<b:ControlGroup>
|
<b:ControlGroup ui:field="resourcesControlGroup">
|
||||||
<b:Controls>
|
<b:Controls>
|
||||||
<b:CheckBox
|
<b:CheckBox
|
||||||
title="Automatically add the folder content to the dataset as resource"
|
title="Automatically add the folder content to the dataset as resource"
|
||||||
|
@ -252,6 +262,11 @@
|
||||||
visible="false" ui:field="onCreateAlertBlock" styleName="{style.block-alert-style}">
|
visible="false" ui:field="onCreateAlertBlock" styleName="{style.block-alert-style}">
|
||||||
</b:AlertBlock>
|
</b:AlertBlock>
|
||||||
|
|
||||||
|
<b:Button title="Add resources to the just created dataset" visible="false"
|
||||||
|
ui:field="addResourcesButton">Add Resources</b:Button>
|
||||||
|
|
||||||
|
<!-- Here will be placed the form for the resources -->
|
||||||
|
<g:VerticalPanel ui:field="resourcesPanel" visible="false" width="100%"></g:VerticalPanel>
|
||||||
|
|
||||||
<b:Button title="Create dataset" ui:field="createButton"
|
<b:Button title="Create dataset" ui:field="createButton"
|
||||||
type="PRIMARY" block="true">Create</b:Button>
|
type="PRIMARY" block="true">Create</b:Button>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.gcube.portlets.widgets.ckandatapublisherwidget.server;
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.server;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -15,10 +17,11 @@ import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
||||||
import org.gcube.common.homelibrary.home.workspace.folder.FolderItem;
|
import org.gcube.common.homelibrary.home.workspace.folder.FolderItem;
|
||||||
import org.gcube.common.homelibrary.home.workspace.folder.items.GCubeItem;
|
import org.gcube.common.homelibrary.home.workspace.folder.items.GCubeItem;
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
import org.gcube.dataaccess.ckanutillibrary.CKanUtilsFactory;
|
import org.gcube.datacatalogue.ckanutillibrary.CKanUtilsFactory;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
|
||||||
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
|
||||||
|
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBean;
|
||||||
import org.gcube.vomanagement.usermanagement.UserManager;
|
import org.gcube.vomanagement.usermanagement.UserManager;
|
||||||
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
|
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
|
||||||
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
|
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
|
||||||
|
@ -53,7 +56,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
if(isWithinPortal())
|
if(isWithinPortal())
|
||||||
return ScopeProvider.instance.get();
|
return ScopeProvider.instance.get();
|
||||||
else
|
else
|
||||||
return "/gcube";
|
return "/gcube"; // Development
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +70,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
|
|
||||||
try{
|
try{
|
||||||
String currentScope = getCurrentScope();
|
String currentScope = getCurrentScope();
|
||||||
return "https://" + CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getCatalogueUrl();
|
return CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getCatalogueUrl();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
logger.error("Failed to retrieve catalogue url information", e);
|
logger.error("Failed to retrieve catalogue url information", e);
|
||||||
}
|
}
|
||||||
|
@ -92,7 +95,6 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -300,7 +302,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createCKanDataset(DatasetMetadataBean toCreate) {
|
public String createCKanDataset(DatasetMetadataBean toCreate) {
|
||||||
|
|
||||||
// retrieve ckan's catalog url
|
// retrieve ckan's catalog url
|
||||||
String ckanPortalUrl = getCatalogueUrl();
|
String ckanPortalUrl = getCatalogueUrl();
|
||||||
|
@ -334,10 +336,6 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
dataset.setMaintainerEmail(toCreate.getMaintainerEmail());
|
dataset.setMaintainerEmail(toCreate.getMaintainerEmail());
|
||||||
dataset.setVersion(String.valueOf(toCreate.getVersion()));
|
dataset.setVersion(String.valueOf(toCreate.getVersion()));
|
||||||
dataset.setNotes(toCreate.getDescription());
|
dataset.setNotes(toCreate.getDescription());
|
||||||
|
|
||||||
logger.info("Searchable is " + toCreate.isSearchable() + " and visible is " + toCreate.getVisibility());
|
|
||||||
|
|
||||||
dataset.setPriv(false);
|
|
||||||
dataset.setOpen(toCreate.getVisibility());
|
dataset.setOpen(toCreate.getVisibility());
|
||||||
|
|
||||||
// iterate over the licenses to find the id of the chosen one
|
// iterate over the licenses to find the id of the chosen one
|
||||||
|
@ -431,10 +429,10 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
logger.debug("Dataset created/updated " + res.getId());
|
logger.debug("Dataset created/updated " + res.getId());
|
||||||
else{
|
else{
|
||||||
logger.error("Dataset described by " + toCreate + " not created!");
|
logger.error("Dataset described by " + toCreate + " not created!");
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return res.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -450,4 +448,66 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
|
||||||
|
|
||||||
return convertedName;
|
return convertedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods
|
||||||
|
* @param URLName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean exists(String URLName){
|
||||||
|
try {
|
||||||
|
HttpURLConnection.setFollowRedirects(true);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) new URL(URLName).openConnection();
|
||||||
|
con.setRequestMethod("HEAD");
|
||||||
|
logger.info("Return code is " + con.getResponseCode());
|
||||||
|
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
logger.error("Exception while checking url", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addResourceToDataset(ResourceBean resourceBean, String datasetId, String owner) {
|
||||||
|
|
||||||
|
logger.info("Incoming request for creating new resource for dataset with id " + datasetId);
|
||||||
|
logger.info("Owner is " + owner + " and resource is " + resourceBean);
|
||||||
|
|
||||||
|
// of course, if it exists
|
||||||
|
if(exists(resourceBean.getUrl())){
|
||||||
|
|
||||||
|
try{
|
||||||
|
// retrieve ckan's catalog url
|
||||||
|
String ckanPortalUrl = getCatalogueUrl();
|
||||||
|
|
||||||
|
// retrieve the api key for this user
|
||||||
|
String apiKey = getCKANApikeyFromUser(owner);
|
||||||
|
|
||||||
|
CkanResource resource = new CkanResource(ckanPortalUrl, datasetId);
|
||||||
|
resource.setName(resourceBean.getName());
|
||||||
|
resource.setDescription(resourceBean.getDescription());
|
||||||
|
resource.setUrl(resourceBean.getUrl());
|
||||||
|
resource.setOwner(owner);
|
||||||
|
|
||||||
|
// Checked client
|
||||||
|
CheckedCkanClient client = new CheckedCkanClient(ckanPortalUrl, apiKey);
|
||||||
|
CkanResource createdRes = client.createResource(resource);
|
||||||
|
|
||||||
|
if(createdRes != null){
|
||||||
|
|
||||||
|
logger.info("Resource " + createdRes.getName() + " is now available");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(Exception e){
|
||||||
|
logger.error("Unable to create new resource", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("No resource created");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import java.util.Map;
|
||||||
* <li> Description -> folders' description
|
* <li> Description -> folders' description
|
||||||
* <li> tags -> folder's custom fields keys' names
|
* <li> tags -> folder's custom fields keys' names
|
||||||
* <li> visibility -> as chosen by the creator (visible = true, not visible = false)
|
* <li> visibility -> as chosen by the creator (visible = true, not visible = false)
|
||||||
* <li> searchable -> as chosen by the creator
|
|
||||||
* <li> source -> url of the folder within the workspace
|
* <li> source -> url of the folder within the workspace
|
||||||
* <li> version -> during creation it is going to be 1.0
|
* <li> version -> during creation it is going to be 1.0
|
||||||
* <li> author, maintainer -> folder's owner
|
* <li> author, maintainer -> folder's owner
|
||||||
|
@ -34,7 +33,6 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
List<String> tags; // on retrieve, they are the keys of the custom fields
|
List<String> tags; // on retrieve, they are the keys of the custom fields
|
||||||
private String license; // chosen by the user
|
private String license; // chosen by the user
|
||||||
private boolean visibility; // Private (false) or Public(true)
|
private boolean visibility; // Private (false) or Public(true)
|
||||||
private boolean searchable; // true or false
|
|
||||||
private String source; // url of the folder in the workspace
|
private String source; // url of the folder in the workspace
|
||||||
private long version; // version 1, 2 ...
|
private long version; // version 1, 2 ...
|
||||||
private String author; // folder's owner fullname
|
private String author; // folder's owner fullname
|
||||||
|
@ -59,7 +57,6 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
* @param tags
|
* @param tags
|
||||||
* @param license
|
* @param license
|
||||||
* @param visibility
|
* @param visibility
|
||||||
* @param searchable
|
|
||||||
* @param source
|
* @param source
|
||||||
* @param version
|
* @param version
|
||||||
* @param author
|
* @param author
|
||||||
|
@ -72,7 +69,7 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
*/
|
*/
|
||||||
public DatasetMetadataBean(String id, String title, String description,
|
public DatasetMetadataBean(String id, String title, String description,
|
||||||
Map<String, String> customFields, List<String> tags,
|
Map<String, String> customFields, List<String> tags,
|
||||||
String license, boolean visibility, boolean searchable,
|
String license, boolean visibility,
|
||||||
String source, long version, String author, String authorEmail,
|
String source, long version, String author, String authorEmail,
|
||||||
String maintainer, String maintainerEmail,
|
String maintainer, String maintainerEmail,
|
||||||
String ownerFolderInWorkspace, List<String> organizationList,
|
String ownerFolderInWorkspace, List<String> organizationList,
|
||||||
|
@ -85,7 +82,6 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
this.license = license;
|
this.license = license;
|
||||||
this.visibility = visibility;
|
this.visibility = visibility;
|
||||||
this.searchable = searchable;
|
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
@ -161,14 +157,6 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
this.visibility = visibility;
|
this.visibility = visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSearchable() {
|
|
||||||
return searchable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSearchable(boolean searchable) {
|
|
||||||
this.searchable = searchable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +242,7 @@ public class DatasetMetadataBean implements Serializable {
|
||||||
return "DatasetMetadataBean [id=" + id + ", title=" + title
|
return "DatasetMetadataBean [id=" + id + ", title=" + title
|
||||||
+ ", description=" + description + ", customFields="
|
+ ", description=" + description + ", customFields="
|
||||||
+ customFields + ", tags=" + tags + ", license=" + license
|
+ customFields + ", tags=" + tags + ", license=" + license
|
||||||
+ ", visibility=" + visibility + ", searchable=" + searchable
|
+ ", visibility=" + visibility
|
||||||
+ ", source=" + source + ", version=" + version + ", author="
|
+ ", source=" + source + ", version=" + version + ", author="
|
||||||
+ author + ", authorEmail=" + authorEmail + ", maintainer="
|
+ author + ", authorEmail=" + authorEmail + ", maintainer="
|
||||||
+ maintainer + ", maintainerEmail=" + maintainerEmail
|
+ maintainer + ", maintainerEmail=" + maintainerEmail
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
package org.gcube.portlets.widgets.ckandatapublisherwidget.shared;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dataset's resource bean.
|
||||||
|
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
|
||||||
|
*/
|
||||||
|
public class ResourceBean implements Serializable{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -6542455246456049712L;
|
||||||
|
private String url;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
public ResourceBean(){
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param url
|
||||||
|
* @param name
|
||||||
|
* @param description
|
||||||
|
*/
|
||||||
|
public ResourceBean(String url, String name, String description) {
|
||||||
|
super();
|
||||||
|
this.url = url;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param url
|
||||||
|
* @param name
|
||||||
|
* @param description
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
public ResourceBean(String url, String name, String description, String id) {
|
||||||
|
super();
|
||||||
|
this.url = url;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the url
|
||||||
|
*/
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param url the url to set
|
||||||
|
*/
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the description
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description the description to set
|
||||||
|
*/
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id the id to set
|
||||||
|
*/
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ResourceBean [url=" + url + ", name=" + name + ", description="
|
||||||
|
+ description + ", id=" + id + "]";
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,4 +19,7 @@
|
||||||
<source path='client' />
|
<source path='client' />
|
||||||
<source path='shared' />
|
<source path='shared' />
|
||||||
|
|
||||||
|
<!-- Specify the application specific style sheet. -->
|
||||||
|
<stylesheet src='CKanMetadataPublisher.css' />
|
||||||
|
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
<link type="text/css" rel="stylesheet" href="CKanMetadataPublisher.css">
|
<link type="text/css" rel="stylesheet" href="CKanMetadataPublisher.css">
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="CKanMetadataPublisher/CKanMetadataPublisher.nocache.js"></script>
|
src="CKanMetadataPublisher/CKanMetadataPublisher.nocache.js"></script>
|
||||||
|
<script type="text/javascript"
|
||||||
|
src="/js/showdown.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
/**
|
||||||
|
* Created by Tivie on 06-01-2015.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Private properties
|
||||||
|
var showdown = {},
|
||||||
|
parsers = {},
|
||||||
|
extensions = {},
|
||||||
|
globalOptions = getDefaultOpts(true),
|
||||||
|
flavor = {
|
||||||
|
github: {
|
||||||
|
omitExtraWLInCodeBlocks: true,
|
||||||
|
prefixHeaderId: 'user-content-',
|
||||||
|
simplifiedAutoLink: true,
|
||||||
|
literalMidWordUnderscores: true,
|
||||||
|
strikethrough: true,
|
||||||
|
tables: true,
|
||||||
|
tablesHeaderId: true,
|
||||||
|
ghCodeBlocks: true,
|
||||||
|
tasklists: true
|
||||||
|
},
|
||||||
|
vanilla: getDefaultOpts(true)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper namespace
|
||||||
|
* @type {{}}
|
||||||
|
*/
|
||||||
|
showdown.helper = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO LEGACY SUPPORT CODE
|
||||||
|
* @type {{}}
|
||||||
|
*/
|
||||||
|
showdown.extensions = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a global option
|
||||||
|
* @static
|
||||||
|
* @param {string} key
|
||||||
|
* @param {*} value
|
||||||
|
* @returns {showdown}
|
||||||
|
*/
|
||||||
|
showdown.setOption = function (key, value) {
|
||||||
|
'use strict';
|
||||||
|
globalOptions[key] = value;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a global option
|
||||||
|
* @static
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
showdown.getOption = function (key) {
|
||||||
|
'use strict';
|
||||||
|
return globalOptions[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the global options
|
||||||
|
* @static
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
showdown.getOptions = function () {
|
||||||
|
'use strict';
|
||||||
|
return globalOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset global options to the default values
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
showdown.resetOptions = function () {
|
||||||
|
'use strict';
|
||||||
|
globalOptions = getDefaultOpts(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the flavor showdown should use as default
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
|
showdown.setFlavor = function (name) {
|
||||||
|
'use strict';
|
||||||
|
if (flavor.hasOwnProperty(name)) {
|
||||||
|
var preset = flavor[name];
|
||||||
|
for (var option in preset) {
|
||||||
|
if (preset.hasOwnProperty(option)) {
|
||||||
|
globalOptions[option] = preset[option];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default options
|
||||||
|
* @static
|
||||||
|
* @param {boolean} [simple=true]
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
showdown.getDefaultOptions = function (simple) {
|
||||||
|
'use strict';
|
||||||
|
return getDefaultOpts(simple);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set a subParser
|
||||||
|
*
|
||||||
|
* subParser(name) - Get a registered subParser
|
||||||
|
* subParser(name, func) - Register a subParser
|
||||||
|
* @static
|
||||||
|
* @param {string} name
|
||||||
|
* @param {function} [func]
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
showdown.subParser = function (name, func) {
|
||||||
|
'use strict';
|
||||||
|
if (showdown.helper.isString(name)) {
|
||||||
|
if (typeof func !== 'undefined') {
|
||||||
|
parsers[name] = func;
|
||||||
|
} else {
|
||||||
|
if (parsers.hasOwnProperty(name)) {
|
||||||
|
return parsers[name];
|
||||||
|
} else {
|
||||||
|
throw Error('SubParser named ' + name + ' not registered!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets or registers an extension
|
||||||
|
* @static
|
||||||
|
* @param {string} name
|
||||||
|
* @param {object|function=} ext
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
showdown.extension = function (name, ext) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!showdown.helper.isString(name)) {
|
||||||
|
throw Error('Extension \'name\' must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
name = showdown.helper.stdExtName(name);
|
||||||
|
|
||||||
|
// Getter
|
||||||
|
if (showdown.helper.isUndefined(ext)) {
|
||||||
|
if (!extensions.hasOwnProperty(name)) {
|
||||||
|
throw Error('Extension named ' + name + ' is not registered!');
|
||||||
|
}
|
||||||
|
return extensions[name];
|
||||||
|
|
||||||
|
// Setter
|
||||||
|
} else {
|
||||||
|
// Expand extension if it's wrapped in a function
|
||||||
|
if (typeof ext === 'function') {
|
||||||
|
ext = ext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure extension is an array
|
||||||
|
if (!showdown.helper.isArray(ext)) {
|
||||||
|
ext = [ext];
|
||||||
|
}
|
||||||
|
|
||||||
|
var validExtension = validate(ext, name);
|
||||||
|
|
||||||
|
if (validExtension.valid) {
|
||||||
|
extensions[name] = ext;
|
||||||
|
} else {
|
||||||
|
throw Error(validExtension.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all extensions registered
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
showdown.getAllExtensions = function () {
|
||||||
|
'use strict';
|
||||||
|
return extensions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an extension
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
|
showdown.removeExtension = function (name) {
|
||||||
|
'use strict';
|
||||||
|
delete extensions[name];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all extensions
|
||||||
|
*/
|
||||||
|
showdown.resetExtensions = function () {
|
||||||
|
'use strict';
|
||||||
|
extensions = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate extension
|
||||||
|
* @param {array} extension
|
||||||
|
* @param {string} name
|
||||||
|
* @returns {{valid: boolean, error: string}}
|
||||||
|
*/
|
||||||
|
function validate(extension, name) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
|
||||||
|
ret = {
|
||||||
|
valid: true,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!showdown.helper.isArray(extension)) {
|
||||||
|
extension = [extension];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < extension.length; ++i) {
|
||||||
|
var baseMsg = errMsg + ' sub-extension ' + i + ': ',
|
||||||
|
ext = extension[i];
|
||||||
|
if (typeof ext !== 'object') {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showdown.helper.isString(ext.type)) {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = ext.type = ext.type.toLowerCase();
|
||||||
|
|
||||||
|
// normalize extension type
|
||||||
|
if (type === 'language') {
|
||||||
|
type = ext.type = 'lang';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'html') {
|
||||||
|
type = ext.type = 'output';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type !== 'lang' && type !== 'output' && type !== 'listener') {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'listener') {
|
||||||
|
if (showdown.helper.isUndefined(ext.listeners)) {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext.listeners) {
|
||||||
|
if (typeof ext.listeners !== 'object') {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
for (var ln in ext.listeners) {
|
||||||
|
if (ext.listeners.hasOwnProperty(ln)) {
|
||||||
|
if (typeof ext.listeners[ln] !== 'function') {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
|
||||||
|
' must be a function but ' + typeof ext.listeners[ln] + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext.filter) {
|
||||||
|
if (typeof ext.filter !== 'function') {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else if (ext.regex) {
|
||||||
|
if (showdown.helper.isString(ext.regex)) {
|
||||||
|
ext.regex = new RegExp(ext.regex, 'g');
|
||||||
|
}
|
||||||
|
if (!ext.regex instanceof RegExp) {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (showdown.helper.isUndefined(ext.replace)) {
|
||||||
|
ret.valid = false;
|
||||||
|
ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate extension
|
||||||
|
* @param {object} ext
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
showdown.validateExtension = function (ext) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var validateExtension = validate(ext, null);
|
||||||
|
if (!validateExtension.valid) {
|
||||||
|
console.warn(validateExtension.error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
Loading…
Reference in New Issue