From 28023176cc62f9132ccadbb0898fc815ec01fbbf Mon Sep 17 00:00:00 2001
From: Daniel Fabian
Date: Thu, 31 May 2018 12:46:28 +0200
Subject: [PATCH] Fix build process and merge internal updates.
---
client_side_only_impl/vsaq_main.js | 8 +--
compiler.flags | 4 +-
do.sh | 32 +++++----
download-libs.sh | 65 ++++++++++++++-----
vsaq/static/qpage_base.js | 15 -----
vsaq/static/questionnaire/blockitems.js | 2 +-
vsaq/static/questionnaire/boxitem.js | 10 +--
vsaq/static/questionnaire/boxitem_test.js | 18 +++++
vsaq/static/questionnaire/checkitem.js | 13 ++--
vsaq/static/questionnaire/groupitem.js | 35 ++++++----
vsaq/static/questionnaire/groupitem_test.js | 43 ++++++++++++
vsaq/static/questionnaire/items.js | 18 +++--
vsaq/static/questionnaire/lineitem.js | 10 +--
vsaq/static/questionnaire/lineitem_test.js | 26 ++++++++
vsaq/static/questionnaire/questionnaire.js | 34 +++++-----
.../questionnaire/questionnaire_editor.js | 14 ++--
.../questionnaire/questionnaire_test.js | 12 ++--
vsaq/static/questionnaire/radioitem.js | 12 ++--
vsaq/static/questionnaire/templates.soy | 18 ++---
vsaq/static/questionnaire/tipitem.js | 15 +++--
vsaq/static/questionnaire/tipitem_test.js | 22 +++++++
vsaq/static/questionnaire/uploaditem.js | 11 ++--
vsaq/static/questionnaire/uploaditem_test.js | 14 ++++
vsaq/static/questionnaire/yesnoitem.js | 13 ++--
vsaq/static/questionnaire/yesnoitem_test.js | 21 ++++++
vsaq/static/utils.js | 3 +-
26 files changed, 347 insertions(+), 141 deletions(-)
diff --git a/client_side_only_impl/vsaq_main.js b/client_side_only_impl/vsaq_main.js
index 42456fa..c7afbf5 100644
--- a/client_side_only_impl/vsaq_main.js
+++ b/client_side_only_impl/vsaq_main.js
@@ -159,7 +159,7 @@ vsaq.Qpage.prototype.updateStorage_ = function(data) {
var newStorageData = null;
var storageData = this.readStorage_();
if (storageData) {
- storageData = JSON.parse(storageData);
+ storageData = /** @type {Object|null} */ (JSON.parse(storageData));
goog.object.extend(storageData, data);
newStorageData = goog.json.serialize(storageData);
} else {
@@ -259,7 +259,7 @@ vsaq.Qpage.prototype.loadExtensionThenQuestionnaire = function(
text = vsaq.utils.vsaqonToJson(text);
var extension = {};
try {
- extension = JSON.parse(text);
+ extension = /** @type {Object|null} */ (JSON.parse(text));
} catch (err) {
alert('Loading the extension failed. It does not appear to be ' +
'valid json');
@@ -297,7 +297,7 @@ vsaq.Qpage.prototype.loadQuestionnaire = function(opt_path, opt_extension) {
text = vsaq.utils.vsaqonToJson(text);
var template = {};
try {
- template = JSON.parse(text);
+ template = /** @type {Object|null} */ (JSON.parse(text));
} catch (err) {
alert('Loading the template failed. It does not appear to be ' +
'valid json');
@@ -328,7 +328,7 @@ vsaq.Qpage.prototype.loadQuestionnaire = function(opt_path, opt_extension) {
this.questionnaire.listen(
goog.events.EventType.CHANGE, goog.bind(function(e) {
- goog.structs.forEach(e.changedValues, function(val, key) {
+ goog.object.forEach(e.changedValues, function(val, key) {
this.changes[key] = val;
}, this);
if (goog.structs.getCount(this.changes) > 0) {
diff --git a/compiler.flags b/compiler.flags
index c0e0a05..1b5e751 100644
--- a/compiler.flags
+++ b/compiler.flags
@@ -7,7 +7,7 @@
--jscomp_error=checkVars
--jscomp_error=const
--jscomp_error=constantProperty
---jscomp_error=deprecated
+--jscomp_warning=deprecated
--jscomp_error=duplicate
--jscomp_error=duplicateMessage
--jscomp_error=es5Strict
@@ -24,8 +24,6 @@
--jscomp_error=unknownDefines
--jscomp_error=uselessCode
--jscomp_error=visibility
---externs=third_party/closure-compiler/contrib/externs/chrome_extensions.js
--only_closure_dependencies
--manage_closure_dependencies
---js third_party/closure-library/closure/goog/deps.js
--js build/deps.js
diff --git a/do.sh b/do.sh
index 613442a..9ba20f9 100755
--- a/do.sh
+++ b/do.sh
@@ -17,7 +17,7 @@
#
PYTHON_CMD="python"
-JSCOMPILE_CMD="java -jar third_party/closure-compiler/build/compiler.jar --flagfile=compiler.flags"
+JSCOMPILE_CMD="java -jar third_party/closure-compiler/target/closure-compiler-1.0-SNAPSHOT.jar --flagfile=compiler.flags"
CKSUM_CMD="cksum" # chosen because it's available on most Linux/OS X installations
BUILD_DIR="build"
BUILD_TPL_DIR="$BUILD_DIR/templates"
@@ -35,10 +35,9 @@ vsaq_assert_dependencies() {
fi
# Check if required files are present.
files=(third_party/closure-library \
- third_party/closure-templates-compiler \
- third_party/closure-stylesheets/build/closure-stylesheets.jar \
- third_party/closure-compiler/build/compiler.jar \
- third_party/closure-compiler/contrib/externs/chrome_extensions.js \
+ third_party/closure-templates/target \
+ third_party/closure-stylesheets/target/closure-stylesheets-1.5.0-SNAPSHOT-jar-with-dependencies.jar \
+ third_party/closure-compiler/target/closure-compiler-1.0-SNAPSHOT.jar \
)
for var in "${files[@]}"
do
@@ -62,13 +61,16 @@ vsaq_build_templates() {
set -e
mkdir -p "$BUILD_TPL_DIR"
rm -rf "$BUILD_TPL_DIR/*"
+ mkdir "$BUILD_TPL_DIR/proto"
+ # Compile safe html type proto to JS
+ third_party/protoc/bin/protoc --js_out $BUILD_TPL_DIR/proto \
+ ./third_party/safe-html-types/proto/src/main/protobuf/webutil/html/types/html.proto
# Compile soy templates
echo "Compiling Soy templates..."
rm -f "$BUILD_TPL_DIR/cksum"
vsaq_get_file_cksum '*.soy' > "$BUILD_TPL_DIR/cksum"
- find "vsaq" -name '*.soy' -exec java -jar third_party/closure-templates-compiler/SoyToJsSrcCompiler.jar \
- --shouldProvideRequireSoyNamespaces --shouldGenerateJsdoc --shouldDeclareTopLevelNamespaces --srcs {} \
- --outputPathFormat "$BUILD_TPL_DIR/{INPUT_DIRECTORY}{INPUT_FILE_NAME}.js" \;
+ find "vsaq" -name '*.soy' -exec java -jar third_party/closure-templates/target/soy-2018-03-14-SoyToJsSrcCompiler.jar \
+ --srcs {} --outputPathFormat "$BUILD_TPL_DIR/{INPUT_DIRECTORY}{INPUT_FILE_NAME}.js" \;
echo "Done."
}
@@ -110,9 +112,10 @@ vsaq_build_closure_lib_() {
SRC_DIRS=( \
vsaq \
client_side_only_impl \
+ third_party/closure-templates/target \
third_party/closure-library/closure/goog \
third_party/closure-library/third_party/closure/goog \
- third_party/closure-templates-compiler )
+ third_party/protoc/protobuf-3.5.1/js/binary )
if [ -d "$3" ]; then
SRC_DIRS+=("$3")
fi
@@ -122,13 +125,16 @@ vsaq_build_closure_lib_() {
jscompile_vsaq+=" --js='$var/**.js' --js='!$var/**_test.js' --js='!$var/**_perf.js'"
done
jscompile_vsaq+=" --js='!third_party/closure-library/closure/goog/demos/**.js'"
+ jscompile_vsaq+=" --js='!third_party/closure-templates/javascript/examples/**.js'"
if [ "$4" == "debug" ]; then
jscompile_vsaq+=" --debug --formatting=PRETTY_PRINT -O WHITESPACE_ONLY"
elif [ "$4" == "optimized" ]; then
jscompile_vsaq+=" -O ADVANCED"
fi
+ cmd="$jscompile_vsaq --closure_entry_point "$ENTRY_POINT" --js_output_file "$FNAME""
+ echo $cmd
echo -n "."
- $jscompile_vsaq --closure_entry_point "$ENTRY_POINT" --js_output_file "$FNAME"
+ $cmd
}
vsaq_build_jsmodule() {
@@ -161,7 +167,7 @@ vsaq_build() {
BUILD_DIR_STATIC="$BUILD_DIR/static"
mkdir -p "$BUILD_DIR_STATIC"
- csscompile_vsaq="java -jar third_party/closure-stylesheets/build/closure-stylesheets.jar --allowed-non-standard-function color-stop"
+ csscompile_vsaq="java -jar third_party/closure-stylesheets/target/closure-stylesheets-1.5.0-SNAPSHOT-jar-with-dependencies.jar --allowed-non-standard-function color-stop"
echo "Compiling CSS files..."
$csscompile_vsaq "vsaq/static/vsaq_base.css" "vsaq/static/vsaq.css" > "$BUILD_DIR_STATIC/vsaq.css"
echo "Copying remaining static files..."
@@ -203,7 +209,7 @@ vsaq_generate_jsdeps() {
$PYTHON_CMD third_party/closure-library/closure/bin/build/depswriter.py \
--root_with_prefix="build/templates/ build/templates/" \
--root_with_prefix="vsaq/ vsaq/" \
- --root_with_prefix="third_party/closure-templates-compiler/ third_party/closure-templates-compiler/" \
+ --root_with_prefix="third_party/closure-templates/javascript third_party/closure-templates/javascript/" \
> "$BUILD_DIR/deps.js"
}
@@ -215,7 +221,7 @@ vsaq_run() {
$PYTHON_CMD third_party/closure-library/closure/bin/build/depswriter.py \
--root_with_prefix="build/templates/ ../../../build/templates/" \
--root_with_prefix="vsaq/ ../vsaq/" \
- --root_with_prefix="third_party/closure-templates-compiler/ ../../../../third_party/closure-templates-compiler/" \
+ --root_with_prefix="third_party/closure-templates/javascript/ ../../../../third_party/closure-templates/javascript/" \
> "$BUILD_DIR/deps-runfiles.js"
rm -f "$BUILD_DIR/all_tests.js"
diff --git a/download-libs.sh b/download-libs.sh
index 9394c19..97c6aaf 100755
--- a/download-libs.sh
+++ b/download-libs.sh
@@ -19,10 +19,24 @@
export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
THIRD_PARTY_DIRECTORY="third_party"
+
+
+type unzip >/dev/null 2>&1 || {
+ echo >&2 "Unzip is required to build VSAQ dependencies."
+ exit 1
+}
+type wget >/dev/null 2>&1 || {
+ echo >&2 "Wget is required to build VSAQ dependencies."
+ exit 1
+}
type ant >/dev/null 2>&1 || {
echo >&2 "Ant is required to build VSAQ dependencies."
exit 1
}
+type mvn >/dev/null 2>&1 || {
+ echo >&2 "Apache Maven is required to build VSAQ dependencies."
+ exit 1
+}
type javac >/dev/null 2>&1 || {
echo >&2 "Java compiler is required to build VSAQ dependencies."
exit 1
@@ -52,6 +66,7 @@ if [ ! -d .git ]; then
rm -rf $THIRD_PARTY_DIRECTORY/closure-library
rm -rf $THIRD_PARTY_DIRECTORY/closure-stylesheets
rm -rf $THIRD_PARTY_DIRECTORY/js-dossier
+ rm -rf $THIRD_PARTY_DIRECTORY/closure-templates
fi
if [ ! -d $THIRD_PARTY_DIRECTORY ]; then
@@ -62,41 +77,50 @@ cd $THIRD_PARTY_DIRECTORY
git submodule add -f https://github.com/google/closure-compiler closure-compiler
git submodule add -f https://github.com/google/closure-library closure-library
git submodule add -f https://github.com/google/closure-stylesheets closure-stylesheets
+git submodule add -f https://github.com/google/closure-templates closure-templates
git submodule add -f https://github.com/jleyba/js-dossier js-dossier
+git submodule add -f https://github.com/google/safe-html-types safe-html-types
git submodule init
git submodule update
# Pin submodules to particular commits
cd closure-compiler
-git checkout -b 59b42c9fc8fc752b3ff3aabe04ad89a96f9a7bf7 59b42c9fc8fc752b3ff3aabe04ad89a96f9a7bf7
+git checkout -b 0441c526dc7ed322034d4f708062c00802184e8f 0441c526dc7ed322034d4f708062c00802184e8f
cd ..
cd closure-library
-git checkout -b dc369cde87d7ef6dfb46d3b873f872ebee7d07cd dc369cde87d7ef6dfb46d3b873f872ebee7d07cd
+git checkout -b 26de3253e443d36f64c2ea380faee879dfcf1c54 26de3253e443d36f64c2ea380faee879dfcf1c54
cd ..
cd js-dossier
-git checkout -b 6f2d09ee26925b7417f9f6bd1547dffe700ab60f 6f2d09ee26925b7417f9f6bd1547dffe700ab60f
+git checkout -b e6e55806ea97a4fcf4157661ee809eb8b48fe848 e6e55806ea97a4fcf4157661ee809eb8b48fe848
+cd ..
+cd closure-templates
+git checkout -b 17dad0f13db94ca43a2e4c436658682a0403ced1 17dad0f13db94ca43a2e4c436658682a0403ced1
+cd ..
+cd safe-html-types
+git checkout -b 8507735457ea41a37dfa027fb176d49d5783c4ba 8507735457ea41a37dfa027fb176d49d5783c4ba
cd ..
# build closure compiler
if [ ! -f closure-compiler/build/compiler.jar ] && [ -d closure-compiler ]; then
cd closure-compiler
- ant clean
- ant jar
+# ant clean
+# ant jar
+ mvn -DskipTests -pl externs/pom.xml,pom-main.xml,pom-main-shaded.xml
cd ..
fi
-# checkout closure templates compiler
-if [ ! -d closure-templates-compiler ]; then
- curl https://dl.google.com/closure-templates/closure-templates-for-javascript-latest.zip -O
- unzip closure-templates-for-javascript-latest.zip -d closure-templates-compiler
- rm closure-templates-for-javascript-latest.zip
+# build closure templates compiler
+if [ -d closure-templates ] && [ ! -d closure-templates/target ]; then
+ cd closure-templates
+ mvn -DskipTests package
+ cd ..
fi
# build css compiler
-if [ ! -f closure-stylesheets/build/closure-stylesheets.jar ]; then
+if [ ! -f closure-stylesheets/target/closure-stylesheets-1.5.0-SNAPSHOT-jar-with-dependencies.jar ]; then
cd closure-stylesheets
- ant
+ mvn compile assembly:single
cd ..
fi
@@ -104,12 +128,21 @@ if [ -f chrome_extensions.js ]; then
rm -f chrome_extensions.js
fi
+mkdir protoc; cd protoc
+wget https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-linux-x86_64.zip
+unzip protoc-3.5.1-linux-x86_64.zip
+rm protoc-3.5.1-linux-x86_64.zip
+wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-js-3.5.1.zip
+unzip protobuf-js-3.5.1.zip
+rm protobuf-js-3.5.1.zip
+cd ..
+
# Temporary fix
# Soy file bundled with the compiler does not compile with strict settings:
# lib/closure-templates-compiler/soyutils_usegoog.js:1762: ERROR - element JS_STR_CHARS does not exist on this enum
-cd closure-templates-compiler
-echo $PWD
-curl https://raw.githubusercontent.com/google/closure-templates/0cbc8543c34d3f7727dd83a2d1938672f16d5c20/javascript/soyutils_usegoog.js -O
-cd ..
+#cd closure-templates/javascript
+#echo $PWD
+#curl https://raw.githubusercontent.com/google/closure-templates/0cbc8543c34d3f7727dd83a2d1938672f16d5c20/javascript/soyutils_usegoog.js -O
+#cd ../..
cd ..
diff --git a/vsaq/static/qpage_base.js b/vsaq/static/qpage_base.js
index 6ea551f..9b8bdf6 100644
--- a/vsaq/static/qpage_base.js
+++ b/vsaq/static/qpage_base.js
@@ -28,7 +28,6 @@ goog.require('goog.events.EventType');
goog.require('goog.structs');
goog.require('goog.ui.Tooltip');
goog.require('vsaq.Questionnaire');
-goog.require('vsaq.utils');
@@ -52,10 +51,6 @@ vsaq.QpageBase = function() {
goog.dom.createDom(goog.dom.TagName.SPAN);
this.questionnaire.setReadOnlyMode(this.isReadOnly);
- vsaq.utils.initClickables({
- 'eh-edit': goog.bind(this.makeEditable, this)
- });
-
goog.events.listen(window, [goog.events.EventType.BEFOREUNLOAD],
function() {
if (vsaq.qpageObject_ && vsaq.qpageObject_.unsavedChanges())
@@ -122,16 +117,6 @@ vsaq.QpageBase.prototype.isReadOnly;
vsaq.QpageBase.prototype.statusIndicator;
-/**
- * Make questionnaire editable.
- */
-vsaq.QpageBase.prototype.makeEditable = function() {
- this.isReadOnly = false;
- this.questionnaire.setReadOnlyMode(this.isReadOnly);
- this.questionnaire.render();
-};
-
-
/**
* Attempts to keep track of updates that were done to the current
* questionnaire.
diff --git a/vsaq/static/questionnaire/blockitems.js b/vsaq/static/questionnaire/blockitems.js
index 092e773..5e6a94f 100644
--- a/vsaq/static/questionnaire/blockitems.js
+++ b/vsaq/static/questionnaire/blockitems.js
@@ -43,7 +43,7 @@ goog.require('vsaq.questionnaire.templates');
* for the item to be visible to the user.
* @param {?string} caption The caption of the block.
* @param {?string=} opt_auth The needed authorization to get an item displayed.
- * The auth param on {@code vsaq.questionnaire.items.BlockItem} only
+ * The auth param on `vsaq.questionnaire.items.BlockItem` only
* prevents that items are displayed to the user (hidden by display=none).
* @param {?string=} opt_className Name of a CSS class to add to the block.
* @extends {vsaq.questionnaire.items.ContainerItem}
diff --git a/vsaq/static/questionnaire/boxitem.js b/vsaq/static/questionnaire/boxitem.js
index 4753133..506fb0f 100644
--- a/vsaq/static/questionnaire/boxitem.js
+++ b/vsaq/static/questionnaire/boxitem.js
@@ -49,14 +49,15 @@ goog.require('vsaq.questionnaire.utils');
* @param {number=} opt_maxlength HTML maxlength attribute value for the input
* field. See {@link
* https://html.spec.whatwg.org/multipage/forms.html#attr-fe-maxlength}
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
vsaq.questionnaire.items.BoxItem = function(id, conditions, caption,
opt_placeholder, opt_inputPattern, opt_inputTitle, opt_isRequired,
- opt_maxlength) {
+ opt_maxlength, opt_auth) {
goog.base(this, id, conditions, caption, opt_placeholder, opt_inputPattern,
- opt_inputTitle, opt_isRequired, opt_maxlength);
+ opt_inputTitle, opt_isRequired, opt_maxlength, opt_auth);
/**
* The text area where the user can provide an answer.
@@ -122,13 +123,14 @@ vsaq.questionnaire.items.BoxItem.parse = function(questionStack) {
return new vsaq.questionnaire.items.BoxItem(item.id, item.cond, item.text,
item.placeholder, item.inputPattern, item.inputTitle, item.required,
- item.maxlength);
+ item.maxlength, item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.BoxItem.prototype.setReadOnly = function(readOnly) {
- this.textArea_.readOnly = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.textArea_.readOnly = this.auth == 'readonly' ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/boxitem_test.js b/vsaq/static/questionnaire/boxitem_test.js
index f7129fc..02352ee 100644
--- a/vsaq/static/questionnaire/boxitem_test.js
+++ b/vsaq/static/questionnaire/boxitem_test.js
@@ -88,4 +88,22 @@ function testBoxItemParse() {
assertEquals('placeholder', box.placeholder);
assertTrue(box.required);
assertEquals(0, testStack.length);
+ assertTrue(box.auth != 'readonly');
+
+ testStack = [{
+ 'type': 'box',
+ 'text': CAPTION,
+ 'id': ID,
+ 'required' : true,
+ 'placeholder': 'placeholder',
+ 'auth': 'readonly'
+ }];
+ box = vsaq.questionnaire.items.BoxItem.parse(testStack);
+ assert(box instanceof vsaq.questionnaire.items.BoxItem);
+ assertEquals(ID, box.id);
+ assertEquals(CAPTION, box.text);
+ assertEquals('placeholder', box.placeholder);
+ assertTrue(box.required);
+ assertEquals(0, testStack.length);
+ assertEquals('readonly', box.auth);
}
diff --git a/vsaq/static/questionnaire/checkitem.js b/vsaq/static/questionnaire/checkitem.js
index 19ace81..0b4a9b1 100644
--- a/vsaq/static/questionnaire/checkitem.js
+++ b/vsaq/static/questionnaire/checkitem.js
@@ -37,12 +37,13 @@ goog.require('vsaq.questionnaire.utils');
* @param {?string} conditions A string containing conditions which must be met
* for the item to be visible to the user.
* @param {string} caption The caption to show next to the checkbox.
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
-vsaq.questionnaire.items.CheckItem = function(id, conditions, caption) {
- goog.base(this, id, conditions, caption);
-
+vsaq.questionnaire.items.CheckItem = function(id, conditions, caption, opt_auth) {
+ goog.base(this, id, conditions, caption, undefined, undefined, undefined,
+ undefined, undefined, opt_auth);
/**
* The checkbox that is the actual control behind this question.
* @type {!HTMLInputElement}
@@ -104,13 +105,15 @@ vsaq.questionnaire.items.CheckItem.parse = function(questionStack) {
if (item.type != vsaq.questionnaire.items.CheckItem.TYPE)
throw new vsaq.questionnaire.items.ParseError('Wrong parser chosen.');
- return new vsaq.questionnaire.items.CheckItem(item.id, item.cond, item.text);
+ return new vsaq.questionnaire.items.CheckItem(item.id, item.cond, item.text,
+ item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.CheckItem.prototype.setReadOnly = function(readOnly) {
- this.checkBox_.disabled = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.checkBox_.disabled = this.auth == 'readonly' ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/groupitem.js b/vsaq/static/questionnaire/groupitem.js
index 06c5235..5663c07 100644
--- a/vsaq/static/questionnaire/groupitem.js
+++ b/vsaq/static/questionnaire/groupitem.js
@@ -51,11 +51,12 @@ goog.require('vsaq.questionnaire.templates');
* choices in form of dictionaries.
* @param {?Array.>} choicesConds An array that
* contains all possible conditions in form of dictionaries.
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ContainerItem}
* @constructor
*/
vsaq.questionnaire.items.GroupItem = function(id, conditions, caption,
- defaultChoice, choices, choicesConds) {
+ defaultChoice, choices, choicesConds, opt_auth) {
goog.base(this, id, conditions);
/**
@@ -96,6 +97,10 @@ vsaq.questionnaire.items.GroupItem = function(id, conditions, caption,
*/
this.defaultChoiceItem = null;
+ // items of group obtain readonly status from their parents
+ if (opt_auth == 'readonly')
+ this.auth = opt_auth;
+
// Iterate over all choices and create valid questionnaire items for them.
goog.array.forEach(choices, function(choice) {
// choice is supposed to be a dictionary with exactly one entry.
@@ -118,7 +123,8 @@ vsaq.questionnaire.items.GroupItem = function(id, conditions, caption,
}
var appendNewItem =
- this.createSingleItem(choiceId, choiceCondition, choiceText);
+ this.createSingleItem(choiceId, choiceCondition, choiceText,
+ this.auth);
appendNewItem.parentItemSet(this);
goog.events.listen(appendNewItem.eventDispatcher,
@@ -141,7 +147,7 @@ vsaq.questionnaire.items.GroupItem.prototype.setDefaultChoice = function() {
if (this.defaultChoice && !this.defaultChoiceItem) {
var defaultChoiceId = goog.string.createUniqueString();
this.defaultChoiceItem = this.createSingleItem(defaultChoiceId, null,
- vsaq.questionnaire.items.GroupItem.DEFAULT_CHOICE);
+ vsaq.questionnaire.items.GroupItem.DEFAULT_CHOICE, this.auth);
this.defaultChoiceItem.parentItemSet(this);
goog.events.listen(this.defaultChoiceItem.eventDispatcher,
vsaq.questionnaire.items.Item.CHANGED,
@@ -214,6 +220,8 @@ vsaq.questionnaire.items.GroupItem.prototype.answerChanged_ = function(ev) {
* @param {string} choiceId The choice id
* @param {?string} choiceCondition The choice condition
* @param {string} choiceText The choice text
+ * @param {string=} opt_auth If 'readonly', GroupItem's individual ValueItems
+ * are immutable.
* @return {vsaq.questionnaire.items.Item} The choice item
*/
vsaq.questionnaire.items.GroupItem.prototype.createSingleItem =
@@ -255,9 +263,9 @@ vsaq.questionnaire.items.GroupItem.prototype.exportItem = function() {
* @constructor
* */
vsaq.questionnaire.items.RadiogroupItem = function(id, conditions, caption,
- defaultChoice, choices, choicesConds) {
+ defaultChoice, choices, choicesConds, opt_auth) {
goog.base(this, id, conditions, caption, defaultChoice, choices,
- choicesConds);
+ choicesConds, opt_auth);
/** @inheritDoc */
this.groupItemType = vsaq.questionnaire.items.RadioItem.TYPE;
@@ -268,10 +276,10 @@ goog.inherits(vsaq.questionnaire.items.RadiogroupItem,
/** @inheritDoc */
vsaq.questionnaire.items.RadiogroupItem.prototype.createSingleItem = function(
- choiceId, choiceCondition, choiceText) {
+ choiceId, choiceCondition, choiceText, auth) {
var newRadioItem =
new vsaq.questionnaire.items.RadioItem(choiceId, choiceCondition,
- choiceText);
+ choiceText, auth); // GroupItem passes readonly to ValueItem
newRadioItem.type = vsaq.questionnaire.items.RadioItem.TYPE;
return newRadioItem;
};
@@ -292,7 +300,7 @@ vsaq.questionnaire.items.RadiogroupItem.parse = function(questionStack) {
return new vsaq.questionnaire.items.RadiogroupItem(
item.id, item.cond, item.text, item.defaultChoice, item.choices,
- item.choicesConds);
+ item.choicesConds, item.auth);
};
@@ -312,9 +320,9 @@ vsaq.questionnaire.items.RadiogroupItem.TYPE = 'radiogroup';
* @constructor
* */
vsaq.questionnaire.items.CheckgroupItem = function(id, conditions, caption,
- defaultChoice, choices, choicesConds) {
+ defaultChoice, choices, choicesConds, opt_auth) {
goog.base(this, id, conditions, caption, defaultChoice, choices,
- choicesConds);
+ choicesConds, opt_auth);
/** @inheritDoc */
this.groupItemType = vsaq.questionnaire.items.CheckItem.TYPE;
@@ -325,10 +333,11 @@ goog.inherits(vsaq.questionnaire.items.CheckgroupItem,
/** @inheritDoc */
vsaq.questionnaire.items.CheckgroupItem.prototype.createSingleItem = function(
- choiceId, choiceCondition, choiceText) {
+ choiceId, choiceCondition, choiceText, opt_auth) {
var newCheckItem =
new vsaq.questionnaire.items.CheckItem(choiceId, choiceCondition,
- choiceText);
+ choiceText, opt_auth); // GroupItem passes readonly to ValueItem
+
newCheckItem.type = vsaq.questionnaire.items.CheckItem.TYPE;
return newCheckItem;
};
@@ -358,5 +367,5 @@ vsaq.questionnaire.items.CheckgroupItem.parse = function(questionStack) {
return new vsaq.questionnaire.items.CheckgroupItem(
item.id, item.cond, item.text, item.defaultChoice, item.choices,
- item.choicesConds);
+ item.choicesConds, item.auth);
};
diff --git a/vsaq/static/questionnaire/groupitem_test.js b/vsaq/static/questionnaire/groupitem_test.js
index d614cf5..97d584d 100644
--- a/vsaq/static/questionnaire/groupitem_test.js
+++ b/vsaq/static/questionnaire/groupitem_test.js
@@ -124,10 +124,53 @@ function testGroupItemParse() {
var testStack = [TEST_CHECKGROUP];
checkgroupItem = vsaq.questionnaire.items.CheckgroupItem.parse(testStack);
assert(checkgroupItem instanceof vsaq.questionnaire.items.CheckgroupItem);
+ for (var i = 0; i < checkgroupItem.containerItems.length; ++i)
+ assertFalse('readonly' == checkgroupItem.containerItems[i].auth);
testStack = [TEST_RADIOGROUP];
radiogroupItem = vsaq.questionnaire.items.RadiogroupItem.parse(testStack);
assert(radiogroupItem instanceof vsaq.questionnaire.items.RadiogroupItem);
+ for (var i = 0; i < radiogroupItem.containerItems.length; ++i)
+ assertFalse('readonly' == radiogroupItem.containerItems[i].auth);
+
+ // Verify all items once again
+ testGroupItem();
+
+ // testing readonly functionality
+ var TEST_CHECKGROUP2 = {
+ "type": "checkgroup",
+ "defaultChoice": true,
+ "text": "caption",
+ "choices": [
+ {"choice_id_1": "Text 1"},
+ {"choice_id_2": "Text 2"}
+ ],
+ "choicesConds": [],
+ "auth": "readonly"
+ };
+
+ var TEST_RADIOGROUP2 = {
+ 'type': 'radiogroup',
+ 'text': 'caption',
+ 'defaultChoice': false,
+ 'choices': [
+ {'choice_id_1': 'Text 1'},
+ {'choice_id_2': 'Text 2'}
+ ],
+ 'choicesConds': [],
+ 'auth': 'readonly'
+ };
+ testStack = [TEST_CHECKGROUP2];
+ checkgroupItem = vsaq.questionnaire.items.CheckgroupItem.parse(testStack);
+ assert(checkgroupItem instanceof vsaq.questionnaire.items.CheckgroupItem);
+ for (var i = 0; i < checkgroupItem.containerItems.length; ++i)
+ assertEquals('readonly', checkgroupItem.containerItems[i].auth);
+
+ testStack = [TEST_RADIOGROUP2];
+ radiogroupItem = vsaq.questionnaire.items.RadiogroupItem.parse(testStack);
+ assert(radiogroupItem instanceof vsaq.questionnaire.items.RadiogroupItem);
+ for (var i = 0; i < radiogroupItem.containerItems.length; ++i)
+ assertEquals('readonly', radiogroupItem.containerItems[i].auth);
// Verify all items once again
testGroupItem();
diff --git a/vsaq/static/questionnaire/items.js b/vsaq/static/questionnaire/items.js
index 8c9d782..c1e96de 100644
--- a/vsaq/static/questionnaire/items.js
+++ b/vsaq/static/questionnaire/items.js
@@ -64,7 +64,7 @@ goog.inherits(vsaq.questionnaire.items.ParseError, goog.debug.Error);
/**
* Base class for all questionnaire items.
*
All items derived from this base class need to have a property
- * {@code TYPE}, which holds the identifier that is used for the particular item
+ * `TYPE`, which holds the identifier that is used for the particular item
* kind in the serialized format.
* @param {?string} id An ID uniquely identifying the question.
* @param {?string} conditions A string containing conditions which must be met
@@ -358,7 +358,7 @@ vsaq.questionnaire.items.Item.TYPE;
* a Json structure. This function takes the first element from the passed
* array of serialized questionnaire items, and returns the parsed item.
* If an error is encountered parsing the top item, the function will throw a
- * {@code vsaq.questionnaire.items.ParseError}.
+ * `vsaq.questionnaire.items.ParseError`.
* @param {!Array. | !Array.} questionStack
* Array of serialized questionnaire items.
* @return {!vsaq.questionnaire.items.Item} A single parsed item.
@@ -482,16 +482,17 @@ vsaq.questionnaire.items.Item.prototype.exportItem = function() {
* @param {string=} opt_inputTitle HTML5 title attribute value for the input
* field. See {@link
* https://html.spec.whatwg.org/multipage/forms.html#attr-input-title}.
- * @param {boolean=} opt_isRequired Iff true, the item value is required.
+ * @param {boolean=} opt_isRequired If true, the item value is required.
* @param {number=} opt_maxlength HTML maxlength attribute value for the input
* field. See {@link
* https://html.spec.whatwg.org/multipage/forms.html#attr-fe-maxlength}
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.Item}
* @constructor
*/
vsaq.questionnaire.items.ValueItem = function(id, conditions, text,
opt_placeholder, opt_inputPattern, opt_inputTitle, opt_isRequired,
- opt_maxlength) {
+ opt_maxlength, opt_auth) {
if (!id)
throw new vsaq.questionnaire.items.ParseError('ValueItem must have an ID.');
@@ -538,6 +539,13 @@ vsaq.questionnaire.items.ValueItem = function(id, conditions, text,
* @type {number|undefined}
*/
this.maxlength = opt_maxlength;
+
+ if (opt_auth == 'readonly')
+ /**
+ * If 'readonly', the ValueItem cannot be modified.
+ * @type {string|undefined}
+ */
+ this.auth = 'readonly';
};
goog.inherits(vsaq.questionnaire.items.ValueItem,
vsaq.questionnaire.items.Item);
@@ -545,7 +553,7 @@ goog.inherits(vsaq.questionnaire.items.ValueItem,
/**
* Handles changes to the item and dispatches an
- * {@code vsaq.questionnaire.items.Item.CHANGED} event for this item.
+ * `vsaq.questionnaire.items.Item.CHANGED` event for this item.
* @protected
*/
vsaq.questionnaire.items.ValueItem.prototype.answerChanged = function() {
diff --git a/vsaq/static/questionnaire/lineitem.js b/vsaq/static/questionnaire/lineitem.js
index f47040e..9a5c069 100644
--- a/vsaq/static/questionnaire/lineitem.js
+++ b/vsaq/static/questionnaire/lineitem.js
@@ -50,14 +50,15 @@ goog.require('vsaq.questionnaire.utils');
* @param {number=} opt_maxlength HTML maxlength attribute value for the input
* field. See {@link
* https://html.spec.whatwg.org/multipage/forms.html#attr-fe-maxlength}
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
vsaq.questionnaire.items.LineItem = function(id, conditions, caption,
opt_inputType, opt_placeholder, opt_inputPattern, opt_inputTitle,
- opt_isRequired, opt_maxlength) {
+ opt_isRequired, opt_maxlength, opt_auth) {
goog.base(this, id, conditions, caption, opt_placeholder, opt_inputPattern,
- opt_inputTitle, opt_isRequired, opt_maxlength);
+ opt_inputTitle, opt_isRequired, opt_maxlength, opt_auth);
/**
* The html input element where the user can answer the question.
@@ -131,13 +132,14 @@ vsaq.questionnaire.items.LineItem.parse = function(questionStack) {
return new vsaq.questionnaire.items.LineItem(item.id, item.cond, item.text,
item.inputType, item.placeholder, item.inputPattern, item.inputTitle,
- item.required, item.maxlength);
+ item.required, item.maxlength, item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.LineItem.prototype.setReadOnly = function(readOnly) {
- this.textBox_.readOnly = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.textBox_.readOnly = this.auth == 'readonly' ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/lineitem_test.js b/vsaq/static/questionnaire/lineitem_test.js
index da43420..6744bf5 100644
--- a/vsaq/static/questionnaire/lineitem_test.js
+++ b/vsaq/static/questionnaire/lineitem_test.js
@@ -93,4 +93,30 @@ function testLineItemParse() {
assertEquals('.*', line.inputPattern);
assertEquals('date', line.inputType);
assertTrue(line.required);
+ assertTrue(line.auth != 'readonly');
+
+ testStack = [{
+ 'type': 'line',
+ 'text': CAPTION,
+ 'id': ID,
+ 'required' : true,
+ 'inputPattern': '.*',
+ 'inputTitle': 'input_title',
+ 'inputType': 'date',
+ 'placeholder': 'placeholder',
+ 'maxlength': 100,
+ 'auth': 'readonly',
+ }];
+ line = vsaq.questionnaire.items.LineItem.parse(testStack);
+ assert(line instanceof vsaq.questionnaire.items.LineItem);
+ assertEquals(ID, line.id);
+ assertEquals(CAPTION, line.text);
+ assertEquals(0, testStack.length);
+ assertEquals('input_title', line.inputTitle);
+ assertEquals('placeholder', line.placeholder);
+ assertEquals(100, line.maxlength);
+ assertEquals('.*', line.inputPattern);
+ assertEquals('date', line.inputType);
+ assertTrue(line.required);
+ assertEquals('readonly', line.auth);
}
diff --git a/vsaq/static/questionnaire/questionnaire.js b/vsaq/static/questionnaire/questionnaire.js
index 8b64071..90d04f5 100644
--- a/vsaq/static/questionnaire/questionnaire.js
+++ b/vsaq/static/questionnaire/questionnaire.js
@@ -53,7 +53,6 @@ goog.require('goog.json');
goog.require('goog.log');
goog.require('goog.object');
goog.require('goog.soy');
-goog.require('goog.structs');
goog.require('vsaq.questionnaire.items.BlockItem');
goog.require('vsaq.questionnaire.items.BoxItem');
goog.require('vsaq.questionnaire.items.CheckItem');
@@ -92,19 +91,19 @@ goog.inherits(vsaq.questionnaire.QuestionnaireError, goog.debug.Error);
* An interactive questionnaire.
*
* This class allows to display an interactive questionnaire to the user, under
- * the {@code Element} passed as a parameter to the constructor.
+ * the `Element` passed as a parameter to the constructor.
*
*
After instantiation, the questions and structure of the questionnaire need
- * to be provided by setting an Array of {@code vsaq.questionnaire.items.Item}s
- * with {@code setTemplate}. If previous answers have been recorded, those can
- * be loaded with {@code setValues}.
+ * to be provided by setting an Array of `vsaq.questionnaire.items.Item`s
+ * with `setTemplate`. If previous answers have been recorded, those can
+ * be loaded with `setValues`.
*
- *
Calling {@code render} will display the questionnaire to the user. It
+ *
Calling `render` will display the questionnaire to the user. It
* should be called only after setting a template.
*
*
Any changes the user makes to the questionnaire cause an {@code
* goog.events.EventType.CHANGE} event to be raised. At any given time, the
- * currently selected answers can be exported through {@code getValuesAsJson}
+ * currently selected answers can be exported through `getValuesAsJson`
* in JSON format.
*
* @constructor
@@ -119,7 +118,7 @@ vsaq.Questionnaire = function(rootElement) {
/**
* A dictionary of all items, where their ID is the key.
- * @type {!Object.}
+ * @type {!Object.}
* @private
*/
this.items_ = {};
@@ -133,7 +132,7 @@ vsaq.Questionnaire = function(rootElement) {
/**
* Stores the values of the answers to the questions in a dictionary where
- * the keys are the items' ids (see {@code vsaq.questionnaire.items.Item.id}),
+ * the keys are the items' ids (see `vsaq.questionnaire.items.Item.id`),
* and the values are the answers.
* @type {!Object.}
* @private
@@ -149,7 +148,7 @@ vsaq.Questionnaire = function(rootElement) {
/**
* Whether events are captured or not. This is because while the questionnaire
- * is updated through {@code setValues} no events must be sent.
+ * is updated through `setValues` no events must be sent.
* @type {boolean}
* @private
*/
@@ -320,7 +319,8 @@ vsaq.Questionnaire.prototype.reevaluateConditions_ = function() {
var todos = [];
var todoStatus = {};
// Show and hide items in the questionnaire
- goog.structs.forEach(this.items_, function(item, id, items) {
+ goog.object.forEach(this.items_, function(item, id, items) {
+ if (!items) return;
if (item instanceof vsaq.questionnaire.items.ValueItem)
item.setReadOnly(this.readonlyMode_);
@@ -487,7 +487,7 @@ vsaq.Questionnaire.prototype.done = function() {
/**
* Sets the template object for the questionnaire. If the template is not
- * in a valid format, a {@code vsaq.questionnaire.items.ParseError} is thrown.
+ * in a valid format, a `vsaq.questionnaire.items.ParseError` is thrown.
* @param {!vsaq.questionnaire.items.ItemArray} template The template for
* questionnaire.
* @throws {vsaq.questionnaire.items.ParseError}
@@ -525,7 +525,7 @@ vsaq.Questionnaire.prototype.setTemplate = function(template) {
*
* Note: The order in which template extension are passed matters.
* If the extension templates is not in a valid format, a
- * {@code vsaq.questionnaire.QuestionnaireError} is thrown.
+ * `vsaq.questionnaire.QuestionnaireError` is thrown.
*
* @param {!Object} baseTemplate The base template for the questionnaire.
* @param {...!Object} var_args Template extensions that extend the baseTemplate
@@ -569,7 +569,7 @@ vsaq.Questionnaire.prototype.setMultipleTemplates = function(
* Inserts all items of an extension template into the specified position of the
* baseTemplate.
* If extension templates are not in a valid format, a
- * {@code vsaq.questionnaire.QuestionnaireError} is thrown.
+ * `vsaq.questionnaire.QuestionnaireError` is thrown.
* @param {!Object} baseTemplate The base template where items will be insteted.
* @param {!Object} extensionTemplate Template that extends the baseTemplate
* (e.g. company specific questions).
@@ -644,12 +644,12 @@ vsaq.Questionnaire.prototype.insertItemIntoTemplate_ = function(
// We need to go deeper.
if (item.hasOwnProperty('items')) {
- success |= this.insertItemIntoTemplate_(
+ success = success || this.insertItemIntoTemplate_(
item['items'], newItem, targetItemId, opt_insertAfter);
}
}
- return success;
+ return !!success;
};
@@ -691,7 +691,7 @@ vsaq.Questionnaire.prototype.setValues = function(values, opt_scrollThere) {
// Set the new values. We need to disable events during that time, as
// we don't want to dispatch CHANGE events for change *to* the desired state.
this.isCapturingEvents_ = false;
- goog.structs.forEach(this.values_, function(value, id) {
+ goog.object.forEach(this.values_, function(value, id) {
var item = this.items_[id];
if (!item) {
this.logger_.warning(
diff --git a/vsaq/static/questionnaire/questionnaire_editor.js b/vsaq/static/questionnaire/questionnaire_editor.js
index 28badca..8e920a3 100644
--- a/vsaq/static/questionnaire/questionnaire_editor.js
+++ b/vsaq/static/questionnaire/questionnaire_editor.js
@@ -1183,14 +1183,12 @@ vsaq.QuestionnaireEditor.prototype.addItemEditabilityPrefix = function(
// Remove all properties that are mandatory and can already be modified within
// the rendered item.
- for (var key in knownPropertiesKeys) {
- if (!knownPropertiesKeys.hasOwnProperty(key))
- continue;
- if (knownPropertiesValues[key].mandatory &&
- !knownPropertiesValues[key].metadata &&
- !knownPropertiesValues[key].defaultValues) {
- delete knownPropertiesKeys[key];
- delete knownPropertiesValues[key];
+ for (var i=0; inone
{/if}
- {foreach $defaultTypeKey in keys($propertyInformation.defaultValues)}
+ {for $defaultTypeKey in keys($propertyInformation.defaultValues)}
- {/foreach}
+ {/for}
{else}
{($propertyInformation.value or 'none')}
@@ -104,7 +104,7 @@
{template .editablePrefix}
- {foreach $knownPropertyIndex in keys($knownPropertiesKeys)}
+ {for $knownPropertyIndex in keys($knownPropertiesKeys)}
{$knownPropertiesKeys[$knownPropertyIndex]}
@@ -121,7 +121,7 @@
{/if}
- {/foreach}
+ {/for}
{/template}
@@ -140,9 +140,9 @@
Add
{if $defaultType!='block' and $defaultType!='radiogroup' and $defaultType!='checkgroup'}
@@ -408,14 +408,14 @@
Based on your selections, we have compiled the following todo list
for you:
- {foreach $todo in $todoListItems}
+ {for $todo in $todoListItems}
- {/foreach}
+ {/for}
{else}
Great news, you're all set. There is no todo.
diff --git a/vsaq/static/questionnaire/tipitem.js b/vsaq/static/questionnaire/tipitem.js
index 00ad65d..0471a56 100644
--- a/vsaq/static/questionnaire/tipitem.js
+++ b/vsaq/static/questionnaire/tipitem.js
@@ -33,7 +33,7 @@ goog.require('vsaq.questionnaire.utils');
/**
- * A tip that provides advice to the user. If {@code clarification} is set to
+ * A tip that provides advice to the user. If `clarification` is set to
* true, additionally a text area is shown to the user where they can provide
* additional information.
* @param {string} id An ID uniquely identifying the tip.
@@ -48,12 +48,15 @@ goog.require('vsaq.questionnaire.utils');
* @param {string=} opt_name Name of the issue.
* @param {string=} opt_todo Todo list entry associated with the tip.
* @param {string=} opt_customTitle Title of bubble defined in JSON.
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
vsaq.questionnaire.items.TipItem = function(id, conditions, text, warn,
- opt_severity, opt_clarification, opt_name, opt_todo, opt_customTitle) {
- goog.base(this, id, conditions, text);
+ opt_severity, opt_clarification, opt_name, opt_todo, opt_customTitle,
+ opt_auth) {
+ goog.base(this, id, conditions, text, undefined, undefined, undefined,
+ undefined, undefined, opt_auth);
/**
* Indicating whether the tip is a warning or only informational.
@@ -192,14 +195,16 @@ vsaq.questionnaire.items.TipItem.parse = function(questionStack) {
var isWarn = goog.string.makeSafe(item.warn) == 'yes';
return new vsaq.questionnaire.items.TipItem(item.id, item.cond, item.text,
- isWarn, item.severity, item.why, item.name, item.todo, item.customTitle);
+ isWarn, item.severity, item.why, item.name, item.todo, item.customTitle,
+ item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.TipItem.prototype.setReadOnly = function(readOnly) {
if (this.textArea_)
- this.textArea_.readOnly = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.textArea_.readOnly = this.readonly ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/tipitem_test.js b/vsaq/static/questionnaire/tipitem_test.js
index cea2e10..37fac04 100644
--- a/vsaq/static/questionnaire/tipitem_test.js
+++ b/vsaq/static/questionnaire/tipitem_test.js
@@ -133,5 +133,27 @@ function testTipItemParse() {
assertEquals(0, testStack.length);
assertEquals(TODO, tip.todo);
assertEquals(CUSTOMTITLE_TEXT, tip.customTitle);
+ assertTrue(tip.auth != 'readonly');
+
+ testStack = [{
+ 'type': 'tip',
+ 'text': CAPTION,
+ 'id': TIP_ID,
+ 'warn': 'yes',
+ 'why': WHY_TEXT,
+ 'todo': TODO,
+ 'customTitle' : CUSTOMTITLE_TEXT,
+ 'auth': 'readonly',
+ }];
+ tip = vsaq.questionnaire.items.TipItem.parse(testStack);
+ assert(tip instanceof vsaq.questionnaire.items.TipItem);
+ assertEquals(TIP_ID, tip.id);
+ assertEquals(CAPTION, tip.text);
+ assertEquals(true, tip.warn);
+ assertEquals(WHY_TEXT, tip.clarification);
+ assertEquals(0, testStack.length);
+ assertEquals(TODO, tip.todo);
+ assertEquals(CUSTOMTITLE_TEXT, tip.customTitle);
+ assertEquals('readonly', tip.auth);
}
diff --git a/vsaq/static/questionnaire/uploaditem.js b/vsaq/static/questionnaire/uploaditem.js
index 8f78e0b..dca947e 100644
--- a/vsaq/static/questionnaire/uploaditem.js
+++ b/vsaq/static/questionnaire/uploaditem.js
@@ -44,11 +44,13 @@ goog.require('vsaq.questionnaire.utils');
* @param {?string} conditions A string containing conditions which must be met
* for the item to be visible to the user.
* @param {string} caption The caption to show above the file upload.
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
-vsaq.questionnaire.items.UploadItem = function(id, conditions, caption) {
- goog.base(this, id, conditions, caption);
+vsaq.questionnaire.items.UploadItem = function(id, conditions, caption, opt_auth) {
+ goog.base(this, id, conditions, caption, undefined, undefined, undefined,
+ undefined, undefined, opt_auth);
/**
* The form through which the file is uploaded.
@@ -258,13 +260,14 @@ vsaq.questionnaire.items.UploadItem.parse = function(questionStack) {
if (item.type != vsaq.questionnaire.items.UploadItem.TYPE)
throw new vsaq.questionnaire.items.ParseError('Wrong parser chosen.');
- return new vsaq.questionnaire.items.UploadItem(item.id, item.cond, item.text);
+ return new vsaq.questionnaire.items.UploadItem(item.id, item.cond, item.text, item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.UploadItem.prototype.setReadOnly = function(readOnly) {
- this.fileInput_.readOnly = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.fileInput_.readOnly = this.auth == 'readonly' ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/uploaditem_test.js b/vsaq/static/questionnaire/uploaditem_test.js
index fc9f461..02dbfec 100644
--- a/vsaq/static/questionnaire/uploaditem_test.js
+++ b/vsaq/static/questionnaire/uploaditem_test.js
@@ -132,6 +132,20 @@ function testUploadItemParse() {
assertEquals(ID, upload.id);
assertEquals(CAPTION, upload.text);
assertEquals(0, testStack.length);
+ assertTrue(upload.auth != 'readonly');
+
+ testStack = [{
+ 'type': 'upload',
+ 'text': CAPTION,
+ 'id': ID,
+ 'auth': 'readonly'
+ }];
+ upload = vsaq.questionnaire.items.UploadItem.parse(testStack);
+ assert(upload instanceof vsaq.questionnaire.items.UploadItem);
+ assertEquals(ID, upload.id);
+ assertEquals(CAPTION, upload.text);
+ assertEquals(0, testStack.length);
+ assertEquals('readonly', upload.auth);
}
diff --git a/vsaq/static/questionnaire/yesnoitem.js b/vsaq/static/questionnaire/yesnoitem.js
index a0b644a..30d4c5f 100644
--- a/vsaq/static/questionnaire/yesnoitem.js
+++ b/vsaq/static/questionnaire/yesnoitem.js
@@ -40,12 +40,14 @@ goog.require('vsaq.questionnaire.utils');
* @param {string} caption The caption to show next to the radio button.
* @param {string} yes String shown as label for the first option.
* @param {string} no String shown as label for the second option.
+ * @param {string=} opt_auth If "readonly", this ValueItem cannot be modified.
* @extends {vsaq.questionnaire.items.ValueItem}
* @constructor
*/
vsaq.questionnaire.items.YesNoItem = function(id, conditions, caption, yes,
- no) {
- goog.base(this, id, conditions, caption);
+ no, opt_auth) {
+ goog.base(this, id, conditions, caption, undefined, undefined, undefined,
+ undefined, undefined, opt_auth);
/**
* The text for the yes choice.
@@ -151,14 +153,15 @@ vsaq.questionnaire.items.YesNoItem.parse = function(questionStack) {
throw new vsaq.questionnaire.items.ParseError('Wrong parser chosen.');
return new vsaq.questionnaire.items.YesNoItem(item.id, item.cond, item.text,
- item.yes, item.no);
+ item.yes, item.no, item.auth);
};
/** @inheritDoc */
vsaq.questionnaire.items.YesNoItem.prototype.setReadOnly = function(readOnly) {
- this.yesRadio_.disabled = readOnly;
- this.noRadio_.disabled = readOnly;
+ // if item marked readonly, always keep it readonly
+ this.yesRadio_.disabled = this.auth == 'readonly' ? true : readOnly;
+ this.noRadio_.disabled = this.auth == 'readonly' ? true : readOnly;
};
diff --git a/vsaq/static/questionnaire/yesnoitem_test.js b/vsaq/static/questionnaire/yesnoitem_test.js
index d911232..6d21c9c 100644
--- a/vsaq/static/questionnaire/yesnoitem_test.js
+++ b/vsaq/static/questionnaire/yesnoitem_test.js
@@ -100,6 +100,27 @@ function testYesNoItemParse() {
assertEquals(YES, yesno.yes);
assertEquals(NO, yesno.no);
assertEquals(0, testStack.length);
+ assertTrue(yesno.auth != 'readonly');
+
+ assert(yesno.yesRadio_ instanceof HTMLInputElement);
+ assert(yesno.noRadio_ instanceof HTMLInputElement);
+
+ var testStack2 = [{
+ 'type': 'yesno',
+ 'text': CAPTION,
+ 'id': ID,
+ 'yes': YES,
+ 'no': NO,
+ 'auth': 'readonly'
+ }];
+ yesno = vsaq.questionnaire.items.YesNoItem.parse(testStack2);
+ assert(yesno instanceof vsaq.questionnaire.items.YesNoItem);
+ assertEquals(ID, yesno.id);
+ assertEquals(CAPTION, yesno.text);
+ assertEquals(YES, yesno.yes);
+ assertEquals(NO, yesno.no);
+ assertEquals(0, testStack.length);
+ assertEquals('readonly', yesno.auth);
assert(yesno.yesRadio_ instanceof HTMLInputElement);
assert(yesno.noRadio_ instanceof HTMLInputElement);
diff --git a/vsaq/static/utils.js b/vsaq/static/utils.js
index 4098d5b..1f0b604 100644
--- a/vsaq/static/utils.js
+++ b/vsaq/static/utils.js
@@ -29,7 +29,6 @@ goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.string.format');
-goog.require('goog.structs');
/**
@@ -62,7 +61,7 @@ vsaq.utils.addClickHandler = function(elementId, callback) {
vsaq.utils.initClickables = function(handlers) {
goog.events.listen(goog.dom.getDocument(), [goog.events.EventType.CLICK],
function(e) {
- goog.structs.forEach(handlers, function(handler, className) {
+ goog.object.forEach(handlers, function(handler, className) {
var clickable = goog.dom.getAncestorByClass(e.target, className);
if (clickable &&
!goog.dom.classlist.contains(clickable, 'maia-button-disabled')) {