From b713635c01c62c837eb1803aafe47752ffa7309d Mon Sep 17 00:00:00 2001 From: hjkhjk54 Date: Sat, 19 May 2012 01:38:54 +0000 Subject: [PATCH] updates for page management - javascript, freemarker, and n3 editing/generator changes --- .../n3editing/VTwo/EditConfigurationVTwo.java | 19 + .../generators/ManagePageGenerator.java | 3 + .../preprocessors/ManagePagePreprocessor.java | 31 +- .../utils/ProcessDataGetterN3.java | 3 +- .../utils/ProcessSparqlDataGetterN3.java | 28 +- webapp/web/js/json2.js | 487 ++++++++++++++++++ webapp/web/js/menupage/pageManagementUtils.js | 243 ++++++++- .../freemarker/edit/forms/pageManagement.ftl | 15 + 8 files changed, 807 insertions(+), 22 deletions(-) create mode 100644 webapp/web/js/json2.js diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java index ef3fd9293..190768a83 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java @@ -503,6 +503,15 @@ public class EditConfigurationVTwo { public void setUrisOnForm(String ... strs){ this.urisOnform = Arrays.asList( strs ); } + //This doesn't overwrite or set but adds to existing list + public void addUrisOnForm(List urisOnform) { + this.urisOnform.addAll(urisOnform); + } + + public void addUrisOnForm(String ... strs){ + this.urisOnform.addAll(Arrays.asList( strs )); + } + public void setFilesOnForm(List filesOnForm){ this.filesOnForm = filesOnForm; @@ -1089,6 +1098,16 @@ public class EditConfigurationVTwo { fields.put( field.getName(), field); } + public void addFields(List fields) { + if( fields != null ) + { + for(FieldVTwo f: fields) { + this.addField(f); + } + } + + } + @Override public String toString(){ return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java index bb0b454c9..0919ce4e2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java @@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManagePagePreprocessor; import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils; import edu.cornell.mannlib.vitro.webapp.utils.menuManagement.MenuManagementDataUtils; @@ -59,6 +60,8 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen //Adding additional data, specifically edit mode addFormSpecificData(conf, vreq); + //Add preprocessor + conf.addEditSubmissionPreprocessor(new ManagePagePreprocessor(conf)); //Prepare prepare(vreq, conf); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java index 639534655..6c71ff934 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java @@ -114,6 +114,27 @@ public class ManagePagePreprocessor extends private void addInputsToSubmission(ProcessDataGetterN3 pn, int counter, JSONObject jsonObject) { List literalLabels = pn.getLiteralVarNamesBase(); List uriLabels = pn.getUriVarNamesBase(); + + for(String literalLabel:literalLabels) { + //TODO: Deal with multiple submission values + //This retrieves the value for this particular json object + String literalValue = jsonObject.getString(literalLabel); + //Var names will depend on which data getter object this is on the page, so depends on counter + String submissionLiteralName = pn.getVarName(literalLabel, counter); + //This adds literal, connecting the field with + submission.addLiteralToForm(editConfiguration, editConfiguration.getField(submissionLiteralName), submissionLiteralName, new String[]{literalValue}); + } + + for(String uriLabel:uriLabels) { + //TODO: Deal with multiple submission values + //This retrieves the value for this particular json object + String uriValue = jsonObject.getString(uriLabel); + //Var names will depend on which data getter object this is on the page, so depends on counter + String submissionUriName = pn.getVarName(uriLabel, counter); + //This adds literal, connecting the field with + submission.addLiteralToForm(editConfiguration, editConfiguration.getField(submissionUriName), submissionUriName, new String[]{uriValue}); + + } //this needs to be different //Get the literals directly from the processor - which you can get based on counter //Problem then is we know what the connection is - some way to put that logic within the processor itself? @@ -150,7 +171,8 @@ public class ManagePagePreprocessor extends private void addFields(ProcessDataGetterN3 pn, int counter) { - + List fields = pn.retrieveFields(counter); + editConfiguration.addFields(fields); } @@ -158,7 +180,10 @@ public class ManagePagePreprocessor extends //original literals on form: label, uris on form: conceptNode and conceptSource //This will overwrite the original values in the edit configuration private void addLiteralsAndUrisOnForm(ProcessDataGetterN3 pn, int counter) { - + List literalsOnForm = pn.retrieveLiteralsOnForm(counter); + editConfiguration.addLiteralsOnForm(literalsOnForm); + List urisOnForm = pn.retrieveUrisOnForm(counter); + editConfiguration.addUrisOnForm(urisOnForm); } // N3 being reproduced @@ -200,6 +225,8 @@ public class ManagePagePreprocessor extends //Each JSON Object will indicate the type of the data getter within it private String getDataGetterClass(JSONObject jsonObject) { return jsonObject.getString("dataGetterClass"); + + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java index c213c6847..912f8722b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java @@ -15,9 +15,10 @@ public interface ProcessDataGetterN3 { public ListretrieveLiteralsOnForm(int counter); - public List retrieveUrissOnForm(int counter); + public List retrieveUrisOnForm(int counter); public List retrieveFields(int counter); public List getLiteralVarNamesBase(); public List getUriVarNamesBase(); + public String getVarName(String base, int counter); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java index 3e0797ec5..57f9c0aed 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java @@ -58,26 +58,37 @@ public class ProcessSparqlDataGetterN3 implements ProcessDataGetterN3 { */ public List retrieveLiteralsOnForm(int counter) { List literalsOnForm = new ArrayList(); - literalsOnForm.add("saveToVar" + counter); - literalsOnForm.add("query" + counter); + literalsOnForm.add(getVarName("saveToVar",counter)); + literalsOnForm.add(getVarName("query", counter)); return literalsOnForm; } - public List retrieveUrissOnForm(int counter) { + public List retrieveUrisOnForm(int counter) { List urisOnForm = new ArrayList(); //We have no uris as far as I know.. well query Model is a uri - urisOnForm.add("queryModel" + counter); + urisOnForm.add(getVarName("queryModel", counter)); return urisOnForm; } public List retrieveFields(int counter) { List fields = new ArrayList(); - fields.add(new FieldVTwo().setName("queryModel" + counter)); - fields.add(new FieldVTwo().setName("saveToVar" + counter)); - fields.add(new FieldVTwo().setName("query" + counter)); + + //An alternative way of doing this + /* + List allFieldsBase = new ArrayList(); + allFieldsBase.addAll(getLiteralVarNamesBase()); + allFieldsBase.addAll(getUriVarNamesBase()); + + for(String varName: allFieldsBase) { + fields.add(new FieldVTwo().setName(getVarName(varName, counter))); + } */ + + fields.add(new FieldVTwo().setName(getVarName("queryModel", counter))); + fields.add(new FieldVTwo().setName(getVarName("saveToVar", counter))); + fields.add(new FieldVTwo().setName(getVarName("query", counter))); return fields; } @@ -90,6 +101,9 @@ public class ProcessSparqlDataGetterN3 implements ProcessDataGetterN3 { return Arrays.asList("queryModel"); } + public String getVarName(String base, int counter) { + return base + counter; + } } diff --git a/webapp/web/js/json2.js b/webapp/web/js/json2.js new file mode 100644 index 000000000..ab769faf9 --- /dev/null +++ b/webapp/web/js/json2.js @@ -0,0 +1,487 @@ +/* + json2.js + 2011-10-19 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, regexp: true */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +var JSON; +if (!JSON) { + JSON = {}; +} + +(function () { + 'use strict'; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) + ? this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' + : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' + ? c + : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 + ? '[]' + : gap + ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' + : '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 + ? '{}' + : gap + ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' + : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' + ? walk({'': j}, '') + : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); diff --git a/webapp/web/js/menupage/pageManagementUtils.js b/webapp/web/js/menupage/pageManagementUtils.js index 43e303cdd..ecee84e15 100644 --- a/webapp/web/js/menupage/pageManagementUtils.js +++ b/webapp/web/js/menupage/pageManagementUtils.js @@ -40,6 +40,20 @@ var pageManagementUtils = { this.contentTypeSelectOptions = $('select#typeSelect option'); this.classGroupSection = $("section#classGroup"); this.nonClassGroupSection = $("section#nonClassGroup"); + //From original menu management edit + this.defaultTemplateRadio = $('input.default-template'); + this.customTemplateRadio = $('input.custom-template'); + this.customTemplate = $('#custom-template'); + //In this version, these don't exist but we can consider this later + // this.changeContentType = $('#changeContentType'); + this.selectContentType = $('#selectContentType'); + // this.existingContentType = $('#existingContentType'); + this.selectClassGroupDropdown = $('#selectClassGroup'); + this.classesForClassGroup = $('#classesInSelectedGroup'); + this.selectedGroupForPage = $('#selectedContentTypeValue'); + this.allClassesSelectedCheckbox = $('#allSelected'); + this.displayInternalMessage = $('#internal-class label em'); + this.pageContentSubmissionInputs = $("#pageContentSubmissionInputs"); }, initDisplay: function(){ //right side components @@ -86,7 +100,7 @@ var pageManagementUtils = { //Resets the content to be cloned to default settings $("input#moreContent").click( function() { var selectedType = pageManagementUtils.contentTypeSelect.val(); - var selectedTypeText = $("#typeSelect :select").text(); + var selectedTypeText = $("#typeSelect option:selected").text(); //Not sure why selected group here? This won't always be true for more content //var selectedGroup = $('select#selectClassGroup').val(); @@ -97,7 +111,7 @@ var pageManagementUtils = { //Reset class group pageManagementUtils.resetClassGroupSection(); - pageManagementUtils.contentTyeSelectOptions.eq(0).attr('selected', 'selected'); + pageManagementUtils.contentTypeSelectOptions.eq(0).attr('selected', 'selected'); $("input#moreContent").hide(); if ( $("div#leftSide").css("height") != undefined ) { $("div#leftSide").css("height",""); @@ -112,6 +126,11 @@ var pageManagementUtils = { pageManagementUtils.contentTypeSelect.focus(); }); + //replacing with menu management edit version which is extended with some of the logic below + this.selectClassGroupDropdown.change(function() { + pageManagementUtils.chooseClassGroup(); + }); + /* $("select#selectClassGroup").change( function() { if ( $("select#selectClassGroup").val() == "" ) { $("section#classesInSelectedGroup").addClass('hidden'); @@ -126,21 +145,21 @@ var pageManagementUtils = { $("div#leftSide").css("height",$("div#rightSide").height() + "px"); } } - }); + });*/ $("select#typeSelect").change( function() { $('input#variable').val(""); $('textarea#textArea').val(""); - if ( $("#typeSelect").val() == "Browse Class Group" ) { + if ( $("#typeSelect").val() == "browseClassGroup" ) { $("section#classGroup").show(); $("section#nonClassGroup").hide(); $("input#moreContent").hide(); $("section#headerBar").text("Browse Class Group - "); $("section#headerBar").show(); } - if ( $("#typeSelect").val() == "Fixed HTML" || $("#typeSelect").val() == "SPARQL Query Results" ) { + if ( $("#typeSelect").val() == "fixedHtml" || $("#typeSelect").val() == "sparqlQuery" ) { $("section#classGroup").hide(); - if ( $("#typeSelect").val() == "Fixed HTML" ) { + if ( $("#typeSelect").val() == "fixedHtml" ) { $('span#taSpan').text("Enter fixed HTML here"); $("section#headerBar").text("Fixed HTML - "); } @@ -165,6 +184,30 @@ var pageManagementUtils = { } pageManagementUtils.adjustSaveButtonHeight(); }); + + /* + // Listeners for vClass switching + this.changeContentType.click(function() { + pageManagementUtils.showClassGroups(); + + return false; + });*/ + + //Submission: validate as well as create appropriate hidden json inputs + $("form").submit(function () { + var validationError = pageManagementUtils.validateMenuItemForm(); + if (validationError == "") { + //Create the appropriate json objects + pageManagementUtils.createPageContentForSubmission(); + $(this).submit(); + } else{ + $('#error-alert').removeClass('hidden'); + $('#error-alert p').html(validationError); + //TODO: Check why scrolling appears to be a problem + $.scrollTo({ top:0, left:0}, 500) + return false; + } + }); }, //Clone content area @@ -174,8 +217,9 @@ var pageManagementUtils = { var varOrClas; - if ( contentType == "fixedHTML" || contentType == "sparqlResults" ) { - + if ( contentType == "fixedHTML" || contentType == "sparqlQuery" ) { + var taValue = $('textarea#textArea').val(); + alert("original text area value is " + taValue); var $newContentObj = $('section#nonClassGroup').clone(); $newContentObj.addClass("pageContent"); varOrClass = $newContentObj.find('input').val(); @@ -185,15 +229,16 @@ var pageManagementUtils = { $newContentObj.attr("id", contentType + counter); $newContentObj.find('input#variable').attr("id","variable" + counter); $newContentObj.find('textarea#textArea').attr("id","textArea" + counter); - $newContentObj.find('input#variable').attr("name","variable" + counter); - $newContentObj.find('textarea#textArea').attr("name","textArea" + counter); $newContentObj.find('label#variableLabel').attr("id","variableLabel" + counter); $newContentObj.find('label#taLabel').attr("id","taLabel" + counter); + + //Keep the name of the inputs the same + // $newContentObj.find('input#variable').attr("name","variable" + counter); + // $newContentObj.find('textarea#textArea').attr("name","textArea" + counter); // There's a jquery bug when cloning textareas: the value doesn't // get cloned. So // copy the value "manually." - var taValue = $('textarea#textArea').val(); - $newContentObj.find('textarea').val(taValue); + $newContentObj.find("textarea[name='textArea']").val(taValue); } else if ( contentType == "browseClassGroup" ) { @@ -286,6 +331,180 @@ var pageManagementUtils = { $("div#leftSide").css("height",$("div#rightSide").height() + "px"); } } + }, + /************************************/ + //Copied from menu management edit javascript + chooseClassGroup: function() { + var url = "dataservice?getVClassesForVClassGroup=1&classgroupUri="; + var vclassUri = this.selectClassGroupDropdown.val(); + url += encodeURIComponent(vclassUri); + //Make ajax call to retrieve vclasses + $.getJSON(url, function(results) { + + if ( results.classes.length == 0 ) { + + } else { + //update existing content type with correct class group name and hide class group select again + var _this = pageManagementUtils; + // pageManagementUtils.hideClassGroups(); + + pageManagementUtils.selectedGroupForPage.html(results.classGroupName); + //update content type in message to "display x within my institution" + pageManagementUtils.updateInternalClassMessage(results.classGroupName); + //retrieve classes for class group and display with all selected + var selectedClassesList = pageManagementUtils.classesForClassGroup.children('ul#selectedClasses'); + + selectedClassesList.empty(); + selectedClassesList.append('
  • '); + + $.each(results.classes, function(i, item) { + var thisClass = results.classes[i]; + var thisClassName = thisClass.name; + //When first selecting new content type, all classes should be selected + appendHtml = '
  • ' + + '' + + '' + + '
  • '; + selectedClassesList.append(appendHtml); + }); + pageManagementUtils.toggleClassSelection(); + + + //From NEW code + if (pageManagementUtils.selectClassGroupDropdown.val() == "" ) { + $("section#classesInSelectedGroup").addClass('hidden'); + $("div#leftSide").css("height",""); + $("input#moreContent").hide(); + + } + else { + $("section#classesInSelectedGroup").removeClass('hidden'); + $("input#moreContent").show(); + if ( $("div#leftSide").height() < $("div#rightSide").height() ) { + $("div#leftSide").css("height",$("div#rightSide").height() + "px"); + } + } + + + } + + }); + }, + /* + showClassGroups: function() { //User has clicked change content type + //Show the section with the class group dropdown + this.selectContentType.removeClass("hidden"); + //Hide the "change content type" section which shows the selected class group + this.existingContentType.addClass("hidden"); + //Hide the checkboxes for classes within the class group + this.classesForClassGroup.addClass("hidden"); + }, + hideClassGroups: function() { //User has selected class group/content type, page should show classes for class group and 'existing' type with change link + //Hide the class group dropdown + this.selectContentType.addClass("hidden"); + //Show the "change content type" section which shows the selected class group + this.existingContentType.removeClass("hidden"); + //Show the classes in the class group + this.classesForClassGroup.removeClass("hidden"); + + },*/ + toggleClassSelection: function() { + // Check/unckeck all classes for selection + $('input:checkbox[name=allSelected]').click(function(){ + if ( this.checked ) { + // if checked, select all the checkboxes + $('input:checkbox[name=classInClassGroup]').attr('checked','checked'); + + } else { + // if not checked, deselect all the checkboxes + $('input:checkbox[name=classInClassGroup]').removeAttr('checked'); + } + }); + + $('input:checkbox[name=classInClassGroup]').click(function(){ + $('input:checkbox[name=allSelected]').removeAttr('checked'); + }); + }, //This is SPECIFIC to VIVO so should be moved there + updateInternalClassMessage:function(classGroupName) { //User has changed content type + //Set content type within internal class message + this.displayInternalMessage.filter(":first").html(classGroupName); + }, + validateMenuItemForm: function() { + var validationError = ""; + + // Check menu name + if ($('input[type=text][name=menuName]').val() == "") { + validationError += "You must supply a name
    "; + } + // Check pretty url + if ($('input[type=text][name=prettyUrl]').val() == "") { + validationError += "You must supply a pretty URL
    "; + } + if ($('input[type=text][name=prettyUrl]').val().charAt(0) != "/") { + validationError += "The pretty URL must begin with a leading forward slash
    "; + } + + // Check custom template + if ($('input:radio[name=selectedTemplate]:checked').val() == "custom") { + if ($('input[name=customTemplate]').val() == "") { + validationError += "You must supply a template
    "; + } + } + + //the different types of error will depend on the specific type of data getter/page content + /* + + // if no class group selected, this is an error + if ($('#selectClassGroup').val() =='-1') { + validationError += "You must supply a content type
    "; + } else { + //class group has been selected, make sure there is at least one class selected + var allSelected = $('input[name="allSelected"]:checked').length; + var noClassesSelected = $('input[name="classInClassGroup"]:checked').length; + if (allSelected == 0 && noClassesSelected == 0) { + //at least one class should be selected + validationError += "You must select the type of content to display
    "; + } + } + */ + + //check select class group + + return validationError; + }, + createPageContentForSubmission: function() { + //Iterate through the page content and create the appropriate json object and save + var pageContentSections = $("section[class='pageContent']"); + $.each(pageContentSections, function(i) { + var id = $(this).attr("id"); + var jo = pageManagementUtils.processPageContentSection($(this)); + var jsonObjectString = JSON.stringify(jo); + //Create a new hidden input with a specific name and assign value per page content + pageManagementUtils.createPageContentInputForSubmission(jsonObjectString); + }); + //in this case it's a sparql data getter, but what about the others + /* + var len = pageContentSections.length; + var i; + for(i = 0; i < len; i++) { + var pageContentSection = $(pageContentSections[i]); + var pageContentSectionId = pageContentSection.attr("id"); + var jsonObject = pageManagementUtils.processPageContentSection(pageContentSection); + var jsonObjectString = JSON.stringify(jsonObject); + //Create a new hidden input with a specific name and assign value per page content + pageManagementUtils.createPageContentInputForSubmission(jsonObjectString); + }*/ + + }, + createPageContentInputForSubmission: function(inputValue) { + $("").appendTo(pageManagementUtils.pageContentSubmissionInputs); + }, + processPageContentSection:function(pageContentSection) { + + var variableValue = pageContentSection.find("input[name='variable']").val(); + var queryValue = pageContentSection.find("textarea[name='textArea']").val(); + var returnObject = {saveToVar:variableValue, query:queryValue, dataGetterClass:pageManagementUtils.dataGetterLabelToURI["sparqlDataGetter"], queryModel:"vitro:contextDisplayModel"}; + return returnObject; } }; diff --git a/webapp/web/templates/freemarker/edit/forms/pageManagement.ftl b/webapp/web/templates/freemarker/edit/forms/pageManagement.ftl index c8d6a68e0..090c76655 100644 --- a/webapp/web/templates/freemarker/edit/forms/pageManagement.ftl +++ b/webapp/web/templates/freemarker/edit/forms/pageManagement.ftl @@ -31,6 +31,11 @@ <#--class group section has associated page uri, but that depends on editing a current page or if one is selected later-->
    + <#--form method="POST" action="${formUrls}" role="${menuAction} menu item"--> +
    + + +

    Add Page

    @@ -47,8 +52,11 @@
    +
    +
    +
    + +
    <#-- Select classes in a class group -->

    Select content to display *

    @@ -129,8 +139,13 @@

    * required fields

    + + +
    +