diff --git a/productMods/templates/freemarker/edit/forms/css/manageWebpagesForIndividual.css b/productMods/templates/freemarker/edit/forms/css/manageWebpagesForIndividual.css
new file mode 100644
index 00000000..1975a818
--- /dev/null
+++ b/productMods/templates/freemarker/edit/forms/css/manageWebpagesForIndividual.css
@@ -0,0 +1,49 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+#webpageList {
+ margin-left: 0;
+}
+
+#webpageList li {
+ list-style: none;
+ margin-bottom: .75em;
+}
+
+/* Use class dd rather than jQuery UI's class ui-sortable, so that we can remove
+the class if there's fewer than one author. We don't want to remove the ui-sortable
+class, in case we want to re-enable DD without a page reload. */
+#webpageList.dd li {
+ padding-left: 1em;
+ background: url("../images/sortable_icon.png") no-repeat left center;
+ cursor: move;
+}
+
+#webpageList .webpageName {
+ display: inline-block;
+ width: 15em;
+}
+
+#addAndCancelLinks {
+ margin-top: 1.5em;
+}
+
+#returnToIndividual {
+ margin-left: 2em;
+}
+
+#showAddForm a:hover.cancel {
+ color: #fff;
+ background: #f70;
+}
+
+#showAddForm a:hover.cancel {
+ color: #fff;
+ background: #f70;
+}
+
+#webpageList a:link.remove,
+#webpageList a:visited.remove,
+#webpageList a:hover.remove {
+ color: #f70;
+ background: #fff;
+}
diff --git a/productMods/templates/freemarker/edit/forms/images/sortable_icon.png b/productMods/templates/freemarker/edit/forms/images/sortable_icon.png
new file mode 100644
index 00000000..8cae70f7
Binary files /dev/null and b/productMods/templates/freemarker/edit/forms/images/sortable_icon.png differ
diff --git a/productMods/templates/freemarker/edit/forms/js/manageWebpagesForIndividual.js b/productMods/templates/freemarker/edit/forms/js/manageWebpagesForIndividual.js
new file mode 100644
index 00000000..6c9479ab
--- /dev/null
+++ b/productMods/templates/freemarker/edit/forms/js/manageWebpagesForIndividual.js
@@ -0,0 +1,226 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+var manageWebpages = {
+
+ /* *** Initial page setup *** */
+
+ onLoad: function() {
+
+ this.mixIn();
+ this.initPage();
+ },
+
+ mixIn: function() {
+
+ // Get the custom form data from the page
+ $.extend(this, customFormData);
+ },
+
+ // Initial page setup. Called only at page load.
+ initPage: function() {
+
+ this.initWebpageData();
+
+ this.bindEventListeners();
+
+ this.initDragAndDrop();
+
+ if ($('.webpage').length) { // make sure we have at least one webpage
+ // Reorder web pages on page load so that previously unranked items get a rank. Otherwise,
+ // when we add a new web page, it will get put ahead of any previously unranked web pages, instead
+ // of at the end of the list. (It is also helpful to normalize the data before we get started.)
+ this.reorder();
+ }
+ },
+
+ // On page load, associate data with each list item. Then we don't
+ // have to keep retrieving data from or modifying the DOM as we manipulate the
+ // items.
+ initWebpageData: function() {
+ $('.webpage').each(function(index) {
+ $(this).data(webpageData[index]);
+
+ // RY We might still need position to put back an element after reordering
+ // failure. Rank might already have been reset? Check.
+ $(this).data('position', index+1);
+ });
+ },
+
+ bindEventListeners: function() {
+
+ $('.remove').click(function() {
+ manageWebpages.removeWebpage(this);
+ return false;
+ });
+
+ },
+
+ /* *** Ajax initializations *** */
+
+ /* Drag-and-drop */
+ initDragAndDrop: function() {
+
+ var webpages = $('#webpageList');
+
+ // No DD if < 2 items
+ if (webpages.children('li') < 2) {
+ return;
+ }
+
+ $('.webpageName').each(function() {
+ $(this).attr('title', 'Drag and drop to reorder web pages');
+ });
+
+ webpages.sortable({
+ cursor: 'move',
+ update: function(event, ui) {
+ manageWebpages.reorder(event, ui);
+ }
+ });
+ },
+
+ // Reorder webpages. Called on page load and after drag-and-drop and remove.
+ // Event and ui parameters are defined only in the case of drag-and-drop.
+ reorder: function(event, ui) {
+ var webpages = $('li.webpage').map(function(index, el) {
+ return $(this).data('webpageUri');
+ }).get();
+
+ $.ajax({
+ url: manageWebpages.reorderUrl,
+ data: {
+ predicate: manageWebpages.rankPredicate,
+ individuals: webpages
+ },
+ traditional: true, // serialize the array of individuals for the server
+ dataType: 'json',
+ type: 'POST',
+ success: function(data, status, request) {
+ var pos;
+ $('.webpage').each(function(index){
+ pos = index + 1;
+ // Set the new position for this element. The only function of this value
+ // is so we can reset an element to its original position in case reordering fails.
+ manageWebpages.setPosition(this, pos);
+ });
+ },
+ error: function(request, status, error) {
+ // ui is undefined on page load and after a webpage removal.
+ if (ui) {
+ // Put the moved item back to its original position.
+ // Seems we need to do this by hand. Can't see any way to do it with jQuery UI. ??
+ var pos = manageWebpages.getPosition(ui.item),
+ nextpos = pos + 1,
+ webpages = $('#webpageList'),
+ next = manageWebpages.findWebpage('position', nextpos);
+
+ if (next.length) {
+ ui.item.insertBefore(next);
+ }
+ else {
+ ui.item.appendTo(webpages);
+ }
+
+ alert('Reordering of web pages failed.');
+ }
+ }
+ });
+ },
+
+ getPosition: function(webpage) {
+ return $(webpage).data('position');
+ },
+
+ setPosition: function(webpage, pos) {
+ $(webpage).data('position', pos);
+ },
+
+ findWebpage: function(key, value) {
+ var matchingWebpage = $(); // if we don't find one, return an empty jQuery set
+
+ $('.webpage').each(function() {
+ var webpage = $(this);
+ if ( webpage.data(key) === value ) {
+ matchingWebpage = webpage;
+ return false; // stop the loop
+ }
+ });
+
+ return matchingWebpage;
+ },
+
+ removeWebpage: function(link) {
+ // RY Upgrade this to a modal window
+ var removeLast = false,
+ message = 'Are you sure you want to remove this web page?';
+
+ if (!confirm(message)) {
+ return false;
+ }
+
+ if ($(link)[0] === $('.remove:last')[0]) {
+ removeLast = true;
+ }
+
+ $.ajax({
+ url: $(link).attr('href'),
+ type: 'POST',
+ data: {
+ deletion: $(link).parents('.webpage').data('webpageUri')
+ },
+ dataType: 'json',
+ context: link, // context for callback
+ complete: function(request, status) {
+ var webpage;
+
+ if (status === 'success') {
+
+ webpage = $(this).parents('.webpage');
+
+ webpage.fadeOut(400, function() {
+ var numWebpages;
+
+ // Remove from the DOM
+ $(this).remove();
+
+ // Actions that depend on the webpage having been removed from the DOM:
+ numWebpages = $('.webpage').length; // retrieve the new length after removing webpage from the DOM
+
+ // If removed item not last, reorder to remove any gaps
+ if (numWebpages > 0 && ! removeLast) {
+ manageWebpages.reorder();
+ }
+
+ // If fewer than two webpages remaining, disable drag-drop
+ if (numWebpages < 2) {
+ manageWebpages.disableDD();
+ }
+ });
+
+ } else {
+ alert('Error processing request: web page not removed');
+ }
+ }
+ });
+ },
+
+ // Disable DD and associated cues if only one item remains
+ disableDD: function() {
+ var webpages = $('#webpageList');
+
+ $('#webpageList').sortable({ disable: true } )
+ /* Use class dd rather than jQuery UI's class ui-sortable, so that we can remove
+ * the class if there's fewer than one webpage. We don't want to remove the ui-sortable
+ * class, in case we want to re-enable DD without a page reload (e.g., if implementing
+ * adding a webpage via Ajax request).
+ */
+ .removeClass('dd');
+
+ $('.webpageName').removeAttr('title');
+ }
+
+};
+
+$(document).ready(function() {
+ manageWebpages.onLoad();
+});
diff --git a/productMods/templates/freemarker/edit/forms/manageWebpagesForIndividual.ftl b/productMods/templates/freemarker/edit/forms/manageWebpagesForIndividual.ftl
index 6983f1f5..aaec2f41 100644
--- a/productMods/templates/freemarker/edit/forms/manageWebpagesForIndividual.ftl
+++ b/productMods/templates/freemarker/edit/forms/manageWebpagesForIndividual.ftl
@@ -2,10 +2,10 @@
<#-- Custom form for managing web pages for individuals -->
-<#if (editConfiguration.pageData.webpages?size > 0) >
- <#assign ulClass="">
-<#else>
+<#if (editConfiguration.pageData.webpages?size > 1) >
<#assign ulClass="class='dd'">
+<#else>
+ <#assign ulClass="">
#if>
<#assign baseEditWebpageUrl=editConfiguration.pageData.baseEditWebpageUrl!"baseEditWebpageUrl is undefined">
@@ -46,9 +46,9 @@
+
#list>
@@ -70,8 +70,10 @@ var customFormData = {
${stylesheets.add('',
- '')}
+ '',
+ '')}
${scripts.add('',
+ '',
'',
'')}
\ No newline at end of file