NIHVIVO-2343 First shot at the Manage Proxies page.

This commit is contained in:
j2blake 2011-11-03 23:20:22 +00:00
parent 23329bd5fc
commit d1ecaccc5b
12 changed files with 604 additions and 5 deletions

View file

@ -38,6 +38,7 @@ public abstract class AbstractPageHandler {
protected final VitroRequest vreq; protected final VitroRequest vreq;
protected final ServletContext ctx; protected final ServletContext ctx;
protected final OntModel userAccountsModel; protected final OntModel userAccountsModel;
protected final OntModel unionModel;
protected final UserAccountsDao userAccountsDao; protected final UserAccountsDao userAccountsDao;
protected final VClassDao vclassDao; protected final VClassDao vclassDao;
protected final IndividualDao indDao; protected final IndividualDao indDao;
@ -48,8 +49,9 @@ public abstract class AbstractPageHandler {
this.vreq = vreq; this.vreq = vreq;
this.ctx = vreq.getSession().getServletContext(); this.ctx = vreq.getSession().getServletContext();
OntModelSelector oms = ModelContext.getBaseOntModelSelector(ctx); OntModelSelector oms = ModelContext.getUnionOntModelSelector(ctx);
userAccountsModel = oms.getUserAccountsModel(); userAccountsModel = oms.getUserAccountsModel();
unionModel = oms.getFullModel();
WebappDaoFactory wdf = (WebappDaoFactory) this.ctx WebappDaoFactory wdf = (WebappDaoFactory) this.ctx
.getAttribute("webappDaoFactory"); .getAttribute("webappDaoFactory");

View file

@ -0,0 +1,43 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageProxies;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
/**
* Parcel out the different actions required of the ManageProxies GUI.
*/
public class ManageProxiesController extends FreemarkerHttpServlet {
private static final Log log = LogFactory
.getLog(ManageProxiesController.class);
@Override
protected Actions requiredActions(VitroRequest vreq) {
return new Actions(new ManageProxies());
}
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
if (log.isDebugEnabled()) {
dumpRequestParameters(vreq);
}
String action = vreq.getPathInfo();
log.debug("action = '" + action + "'");
return handleListRequest(vreq);
}
private ResponseValues handleListRequest(VitroRequest vreq) {
ManageProxiesListPage page = new ManageProxiesListPage(vreq);
return page.showPage();
}
}

View file

@ -0,0 +1,166 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies;
import static edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies.ProxyRelationshipSelectionCriteria.DEFAULT_RELATIONSHIPS_PER_PAGE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.AbstractPageHandler;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies.ProxyRelationshipSelectionCriteria.ProxyRelationshipView;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies.ProxyRelationshipSelector.Context;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
/**
* TODO
*/
public class ManageProxiesListPage extends AbstractPageHandler {
private static final Log log = LogFactory
.getLog(ManageProxiesListPage.class);
public static final String PARAMETER_RELATIONSHIPS_PER_PAGE = "relationshipsPerPage";
public static final String PARAMETER_PAGE_INDEX = "pageIndex";
public static final String PARAMETER_VIEW_TYPE = "viewType";
public static final String PARAMETER_SEARCH_TERM = "searchTerm";
private static final String TEMPLATE_NAME = "manageProxies-list.ftl";
private static final String DEFAULT_IMAGE_URL = UrlBuilder
.getUrl("/images/placeholders/person.thumbnail.jpg");
private final Context selectorContext;
private ProxyRelationshipSelectionCriteria criteria = ProxyRelationshipSelectionCriteria.DEFAULT_CRITERIA;
public ManageProxiesListPage(VitroRequest vreq) {
super(vreq);
selectorContext = new Context(userAccountsModel, unionModel,
getMatchingProperty());
parseParameters();
}
private String getMatchingProperty() {
return ConfigurationProperties.getBean(vreq).getProperty(
"selfEditing.idMatchingProperty", "");
}
/**
* Build the criteria from the request parameters.
*/
private void parseParameters() {
int relationshipsPerPage = getIntegerParameter(
PARAMETER_RELATIONSHIPS_PER_PAGE,
DEFAULT_RELATIONSHIPS_PER_PAGE);
int pageIndex = getIntegerParameter(PARAMETER_PAGE_INDEX, 1);
ProxyRelationshipView viewType = ProxyRelationshipView.fromKeyword(vreq
.getParameter(PARAMETER_VIEW_TYPE));
String searchTerm = getStringParameter(PARAMETER_SEARCH_TERM, "");
criteria = new ProxyRelationshipSelectionCriteria(relationshipsPerPage,
pageIndex, viewType, searchTerm);
log.debug("selection criteria is: " + criteria);
}
public ResponseValues showPage() {
ProxyRelationshipSelection selection = ProxyRelationshipSelector
.select(selectorContext, criteria);
Map<String, Object> body = buildTemplateBodyMap(selection);
return new TemplateResponseValues(TEMPLATE_NAME, body);
}
private Map<String, Object> buildTemplateBodyMap(
ProxyRelationshipSelection selection) {
Map<String, Object> body = new HashMap<String, Object>();
body.put("relationshipsPerPage", criteria.getRelationshipsPerPage());
body.put("pageIndex", criteria.getPageIndex());
body.put("viewType", criteria.getViewBy());
body.put("searchTerm", criteria.getSearchTerm());
body.put("relationships", wrapProxyRelationships(selection));
body.put("total", selection.getTotalResultCount());
body.put("page", buildPageMap(selection));
body.put("matchingProperty", getMatchingProperty());
body.put("formUrls", buildUrlsMap());
return body;
}
private List<ProxyRelationship> wrapProxyRelationships(
ProxyRelationshipSelection selection) {
List<ProxyRelationship> wrapped = new ArrayList<ProxyRelationship>();
for (ProxyRelationship r : selection.getProxyRelationships()) {
wrapped.add(new ProxyRelationship(wrapItemList(r.getProxyInfos()),
wrapItemList(r.getProfileInfos())));
}
return wrapped;
}
private List<ProxyItemInfo> wrapItemList(List<ProxyItemInfo> items) {
List<ProxyItemInfo> wrapped = new ArrayList<ProxyItemInfo>();
for (ProxyItemInfo item : items) {
wrapped.add(wrapItem(item));
}
return wrapped;
}
private ProxyItemInfo wrapItem(ProxyItemInfo item) {
if (item.getImageUrl().isEmpty()) {
return new ProxyItemInfo(item.getUri(), item.getLabel(),
item.getClassLabel(), DEFAULT_IMAGE_URL);
} else {
return new ProxyItemInfo(item.getUri(), item.getLabel(),
item.getClassLabel(), UrlBuilder.getUrl(item.getImageUrl()));
}
}
private Map<String, Integer> buildPageMap(
ProxyRelationshipSelection selection) {
int currentPage = selection.getCriteria().getPageIndex();
float pageCount = ((float) selection.getTotalResultCount())
/ selection.getCriteria().getRelationshipsPerPage();
int lastPage = (int) Math.ceil(pageCount);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("current", currentPage);
map.put("first", 1);
map.put("last", lastPage);
if (currentPage < lastPage) {
map.put("next", currentPage + 1);
}
if (currentPage > 1) {
map.put("previous", currentPage - 1);
}
return map;
}
protected Map<String, String> buildUrlsMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("list", UrlBuilder.getUrl("/manageProxies/list"));
map.put("edit", UrlBuilder.getUrl("/manageProxies/edit"));
map.put("sparqlQueryAjax", UrlBuilder.getUrl("/ajax/sparqlQuery"));
map.put("defaultImageUrl", DEFAULT_IMAGE_URL);
return map;
}
}

View file

@ -2,6 +2,7 @@
package edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies; package edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies;
/** /**
* On what basis are we selecting proxy relationships? * On what basis are we selecting proxy relationships?
* *
@ -23,6 +24,21 @@ public class ProxyRelationshipSelectionCriteria {
BY_PROXY, BY_PROFILE; BY_PROXY, BY_PROFILE;
public static ProxyRelationshipView DEFAULT_VIEW = BY_PROXY; public static ProxyRelationshipView DEFAULT_VIEW = BY_PROXY;
public static ProxyRelationshipView fromKeyword(String keyword) {
if (keyword == null) {
return DEFAULT_VIEW;
}
for (ProxyRelationshipView v : ProxyRelationshipView.values()) {
if (v.toString().equals(keyword)) {
return v;
}
}
return DEFAULT_VIEW;
}
} }
/** How many relationships should we bring back, at most? */ /** How many relationships should we bring back, at most? */

View file

@ -21,6 +21,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditIndivi
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOntology; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOntology;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditSiteInformation; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditSiteInformation;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageMenus; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageMenus;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageOwnProxies;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.SeeSiteAdminPage; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.SeeSiteAdminPage;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.SeeStartupStatus; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.SeeStartupStatus;
@ -131,6 +132,10 @@ public class BaseSiteAdminController extends FreemarkerHttpServlet {
data.put("userAccounts", UrlBuilder.getUrl("/accountsAdmin")); data.put("userAccounts", UrlBuilder.getUrl("/accountsAdmin"));
} }
if (PolicyHelper.isAuthorizedForActions(vreq, new ManageOwnProxies())) {
data.put("manageProxies", UrlBuilder.getUrl("/manageProxies"));
}
if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) { if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) {
data.put("siteInfo", UrlBuilder.getUrl("/editForm", "controller", "ApplicationBean")); data.put("siteInfo", UrlBuilder.getUrl("/editForm", "controller", "ApplicationBean"));
} }

View file

@ -657,6 +657,15 @@
<url-pattern>/accounts/*</url-pattern> <url-pattern>/accounts/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>ManageProxies</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.manageproxies.ManageProxiesController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ManageProxies</servlet-name>
<url-pattern>/manageProxies/*</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>ShowAuth</servlet-name> <servlet-name>ShowAuth</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.admin.ShowAuthController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.admin.ShowAuthController</servlet-class>

View file

@ -4,6 +4,72 @@
* A collection of building blocks for the proxy-management UI. * A collection of building blocks for the proxy-management UI.
*/ */
/*
* ----------------------------------------------------------------------------
* itemElement
* ----------------------------------------------------------------------------
* Display information about an entity according to the template. The entity
* can be either:
* a profile -- Individual to be edited.
* a proxy -- User Account to do the editing, optionally with info from a
* profile associated with that individual.
*
* You provide:
* template -- the HTML text that determines how the element should look.
* The template must be a single HTML element, which may contain
* any number of sub-elements. It needs to have a single outer
* wrapper, however.
* uri, label, classLabel, imageUrl -- as described below
* remove -- a function that we can call when the user clicks on the remove
* link or button. We will pass a reference to this struct.
* ----------------------------------------------------------------------------
* The template must inlude a link or button with attribute templatePart="remove"
*
* The template may include tokens to be replaced, from the following:
* %uri% -- the URI of the individual being displayed
* %label& -- the label of the individual.
* %classLabel% -- the label of the most specific class of the individual.
* %imageUrl% -- the URL that will fetch the image of the individual,
* or a placeholder image.
* ----------------------------------------------------------------------------
* This relies on magic names for the styles:
* existingProxyItem -- for an item that was present when the page was loaded
* newProxyItem -- for an item that was added since the page was loaded
* removedProxyItem -- added to an item when the "remove" link is cheked.
* ----------------------------------------------------------------------------
*/
function itemElement(template, uri, label, classLabel, imageUrl, removeInfo) {
var self = this;
this.uri = uri;
this.label = label;
this.classLabel = classLabel;
this.imageUrl = (imageUrl) ? imageUrl : imageUrl="../images/placeholders/person.thumbnail.jpg";
this.removeInfo = removeInfo;
this.toString = function() {
return "proxyInfoElement: " + content;
}
this.element = function() {
var content = template.replace(/%uri%/g, this.uri)
.replace(/%label%/g, this.label)
.replace(/%classLabel%/g, this.classLabel)
.replace(/%imageUrl%/g, this.imageUrl);
var element = $(content);
element.addClass("proxyInfoElement");
var removeLink = $("[templatePart='remove']", element).first();
removeLink.click(function(event) {
self.removeInfo(self);
return false;
});
return element;
}
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* proxyInfoElement * proxyInfoElement
@ -53,8 +119,6 @@ function proxyInfoElement(template, uri, label, classLabel, imageUrl, removeInfo
.replace(/%classLabel%/g, this.classLabel) .replace(/%classLabel%/g, this.classLabel)
.replace(/%imageUrl%/g, this.imageUrl); .replace(/%imageUrl%/g, this.imageUrl);
var element = $("<div class='proxyInfoElement' name='proxyInfoElement'>" + content + "</div>"); var element = $("<div class='proxyInfoElement' name='proxyInfoElement'>" + content + "</div>");
var removeLink = $("[templatePart='remove']", element).first(); var removeLink = $("[templatePart='remove']", element).first();

View file

@ -0,0 +1,180 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
/*
* ----------------------------------------------------------------------------
* proxyItemsPanel
* ----------------------------------------------------------------------------
* Display an AJAX-enabled list of proxy-related items (either proxies or
* profiles).
*
* The list may start out with a population of items. items may be added by
* selecting them in the auto-complete box. Items may be removed by clicking
* the "remove" link next to that item.
*
* A hidden field will hold the URI for each item, so when the form is submitted,
* the controller can determine the list of items.
* ----------------------------------------------------------------------------
* You provide:
* p -- the DOM element that contains the template and the data.
* It also contains the autocomplete field.
* ----------------------------------------------------------------------------
*/
function proxyItemsPanel(panel, contextInfo) {
var self = this;
this.itemData = [];
var excludedUris = contextInfo.excludedUris;
var dataContainerElement = $("[name='proxyData']", panel).first();
var autoCompleteField = $("input[name='proxySelectorAC']", panel).first();
var searchStatusField = $("span[name='proxySelectorSearchStatus']", panel).first();
var parseTemplate = function(dataContainer) {
var templateDiv = $("div[name='template']", dataContainer)
var templateHtml = templateDiv.html();
templateDiv.remove();
return templateHtml;
};
var templateHtml = parseTemplate(dataContainerElement);
var displayItemData = function() {
$(".proxyInfoElement", dataContainerElement).remove();
for (i = 0; i < self.itemData.length; i++) {
self.itemData[i].element().appendTo(dataContainerElement);
}
}
var getItemData = function() {
return self.itemData;
}
/* callback function */
var addItemData = function(selection) {
var imageUrl = contextInfo.defaultImageUrl;
if (selection.imageUrl) {
imageUrl = contextInfo.baseUrl + selection.imageUrl;
}
var info = new itemElement(templateHtml, selection.uri, selection.label, selection.classLabel,
imageUrl, removeItem);
self.itemData.unshift(info);
displayItemData();
}
var removeItem = function(info) {
var idx = self.itemData.indexOf(info);
if (idx != -1) {
self.itemData.splice(idx, 1);
}
displayItemData();
}
var parseOriginalData = function() {
var dataDivs = $("div[name='data']", dataContainerElement)
var data = [];
for (i = 0; i < dataDivs.length; i++) {
var dd = dataDivs[i];
var uri = $("p[name='uri']", dd).text();
var label = $("p[name='label']", dd).text();
var classLabel = $("p[name='classLabel']", dd).text();
var imageUrl = $("p[name='imageUrl']", dd).text();
data.push(new itemElement(templateHtml, uri, label, classLabel, imageUrl, removeItem));
}
return data;
}
this.itemData = parseOriginalData();
var setupAutoCompleteFields = function() {
var parms = {
query: contextInfo.query,
model: contextInfo.model,
url: contextInfo.sparqlQueryUrl
};
var updateStatus = new statusFieldUpdater(searchStatusField, 3).setText;
var autocompleteInfo = new proxyAutocomplete(parms, excludedUris, getItemData, addItemData, updateStatus)
autoCompleteField.autocomplete(autocompleteInfo);
}
setupAutoCompleteFields();
displayItemData();
}
function statusFieldUpdater(element, minLength) {
var emptyText = element.text();
var moreCharsText = element.attr('moreCharsText');
var noMatchText = element.attr('noMatchText');
this.setText = function(searchTermLength, numberOfResults) {
if (numberOfResults > 0) {
element.text('');
} else if (searchTermLength == 0) {
element.text(emptyText);
} else if (searchTermLength < minLength) {
element.text(moreCharsText);
} else {
element.text(noMatchText);
}
}
}
var profileQuery = ""
+ "PREFIX fn: <http://www.w3.org/2005/xpath-functions#> \n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/> \n"
+ "PREFIX vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#> \n"
+ "PREFIX vpublic: <http://vitro.mannlib.cornell.edu/ns/vitro/public#> \n"
+ "PREFIX auth: <http://vitro.mannlib.cornell.edu/ns/vitro/authorization#> \n"
+ "\n"
+ "SELECT DISTINCT ?uri ?label ?classLabel ?imageUrl \n"
+ "WHERE { \n"
+ " ?uri a foaf:Person ; \n"
+ " rdfs:label ?label ; \n"
+ " OPTIONAL { \n"
+ " ?uri vitro:mostSpecificType ?type. \n"
+ " ?type rdfs:label ?classLabel \n"
+ " } \n"
+ " OPTIONAL { \n"
+ " ?uri vpublic:mainImage ?imageUri. \n"
+ " ?imageUri vpublic:thumbnailImage ?thumbUri. \n"
+ " ?thumbUri vpublic:downloadLocation ?thumbstreamUri. \n"
+ " ?thumbstreamUri vpublic:directDownloadUrl ?imageUrl. \n"
+ " } \n"
+ " FILTER (REGEX(str(?label), '^%term%', 'i')) \n"
+ "} \n"
+ "ORDER BY ASC(?label) \n"
+ "LIMIT 25 \n";
$(document).ready(function() {
var disableFormInUnsupportedBrowsers = function() {
var disableWrapper = $('#ie67DisableWrapper');
// Check for unsupported browsers only if the element exists on the page
if (disableWrapper.length) {
if (vitro.browserUtils.isIELessThan8()) {
disableWrapper.show();
$('.noIE67').hide();
return true;
}
}
return false;
};
if (disableFormInUnsupportedBrowsers()) {
return;
}
$("div[name='proxyProfilesPanel']").each(function(i) {
var context = {
excludedUris: [],
baseUrl: proxyContextInfo.baseUrl,
sparqlQueryUrl: proxyContextInfo.sparqlQueryUrl,
defaultImageUrl: proxyContextInfo.defaultImageUrl,
query: profileQuery,
model: ''
}
var ppp = new proxyItemsPanel(this, context);
this["ppp"]=ppp;
});
});

View file

@ -168,7 +168,7 @@ function searchStatusField(element, minLength) {
this.setText = function(searchTermLength, numberOfResults) { this.setText = function(searchTermLength, numberOfResults) {
if (numberOfResults > 0) { if (numberOfResults > 0) {
element.text = ''; element.text('');
} else if (searchTermLength == 0) { } else if (searchTermLength == 0) {
element.text(emptyText); element.text(emptyText);
} else if (searchTermLength < minLength) { } else if (searchTermLength < minLength) {

View file

@ -60,4 +60,5 @@ var proxyMechanism = {
${scripts.add('<script type="text/javascript" src="${urls.base}/js/account/proxyUtils.js"></script>', ${scripts.add('<script type="text/javascript" src="${urls.base}/js/account/proxyUtils.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/sparqlUtils.js"></script>', '<script type="text/javascript" src="${urls.base}/js/sparqlUtils.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/account/accountProxyCommon.js"></script>', '<script type="text/javascript" src="${urls.base}/js/account/accountProxyCommon.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/account/accountProxyProxiesPanel.js"></script>')} '<script type="text/javascript" src="${urls.base}/js/account/accountProxyProxiesPanel.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>')}

View file

@ -0,0 +1,109 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for displaying list of user accounts -->
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/account/account.css" />')}
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/autocomplete.css" />')}
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/js/jquery-ui/css/smoothness/jquery-ui-1.8.9.custom.css" />')}
<p>
<#if page.previous??>
<a href="${formUrls.list}?pageIndex='${page.previous}'">Previous</a>
</#if>
${page.current} of ${page.last}
<#if page.next??>
<a href="${formUrls.list}?pageIndex='${page.next}'">Next</a>
</#if>
</p>
<#list relationships as r>
<form action="${formUrls.edit} method="POST">
<table style="width: 100%;">
<tr>
<td style="border: thin solid black; width: 50%;">
<#assign p = r.proxyInfos[0]>
<table><tr>
<td>
<img class="photo-profile" width="90" src="${p.imageUrl}" alt="${p.label}">
</td>
<td class="proxyInfoElement">
${p.label}} |
<span class="class-label">${p.classLabel}</span>
<br>
<input type="hidden" value="${p.uri}" name="proxyUri">
</td>
</tr></table>
<input type="submit" name="deleteProxy" value="Delete this proxy" />
</td>
<td style="border: thin solid black">
<div id="edit-myProxy" name="proxyProfilesPanel">
<p>Add profile</p>
<p><input type="text" name="proxySelectorAC" class="acSelector" size="35" value="Select an existing last name"></p>
<p class="search-status">
<span name='proxySelectorSearchStatus'
moreCharsText='type more characters'
noMatchText='no match'>&nbsp;</span>
</p>
<p class="selected-editors">Selected profiles:</p>
<#-- Magic div thst holds all of the proxy data and the template that shows how to display it. -->
<div name="proxyData">
<#list r.profileInfos as p>
<div name="data" style="display: none">
<p name="uri">${p.uri}</p>
<p name="label">${p.label}</p>
<p name="classLabel">${p.classLabel}</p>
<p name="imageUrl">${p.imageUrl}</p>
</div>
</#list>
<#--
Each proxy will be shown using the HTML inside this element.
It must contain at least:
-- a link with templatePart="remove"
-- a hidden input field with templatePart="uriField"
-->
<div name="template" style="display: none">
<table>
<tr>
<td>
<img class="photo-profile" width="90" alt="%label%" src="%imageUrl%">
</td>
<td class="proxy-info">
%label% | <span class="class-label">%classLabel%</span>
<br />
<a class='remove-proxy' href="." templatePart="remove">Remove selection</a>
</td>
</tr>
</table>
<input type="hidden" name="proxyUri" value="%uri%" >
</div>
</div>
</div>
<input type="submit" name="modifyProfileList" value="Save changes to profiles" />
</td>
</tr>
</table>
</form>
</#list>
<script type="text/javascript">
var proxyContextInfo = {
baseUrl: '${urls.base}',
sparqlQueryUrl: '${formUrls.sparqlQueryAjax}',
defaultImageUrl: '${formUrls.defaultImageUrl}',
matchingProperty: '${matchingProperty}',
};
</script>
${scripts.add('<script type="text/javascript" src="${urls.base}/js/jquery.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>')}
${scripts.add('<script type="text/javascript" src="${urls.base}/js/account/proxyUtils.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/sparqlUtils.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/account/accountProxyCommon.js"></script>',
'<script type="text/javascript" src="${urls.base}/js/account/accountProxyItemsPanel.js"></script>')}

View file

@ -23,6 +23,10 @@
<li><a href="${siteConfig.userAccounts}">User accounts</a></li> <li><a href="${siteConfig.userAccounts}">User accounts</a></li>
</#if> </#if>
<#if siteConfig.manageProxies?has_content>
<li><a href="${siteConfig.manageProxies}">Manage Proxies</a></li>
</#if>
<#if siteConfig.startupStatus?has_content> <#if siteConfig.startupStatus?has_content>
<li> <li>
<a href="${siteConfig.startupStatus}">Startup Status</a> <a href="${siteConfig.startupStatus}">Startup Status</a>