From 75ae0fa994916a41b7fac96f50946a5cc0038e1e Mon Sep 17 00:00:00 2001 From: Phil Eichinski Date: Mon, 1 Jul 2019 16:36:33 +1000 Subject: [PATCH] feat(citSci): added ability to have text fields in questions --- .../citizenScience/citizenScienceCommon.js | 28 ---- src/app/citizenScience/examples/example.js | 3 - .../labels/_citizenScienceLabels.scss | 12 ++ .../labels/citizenScienceLabels.js | 17 ++- src/app/citizenScience/labels/labels.tpl.html | 11 +- ...zenScienceLabels.scss => _textLabels.scss} | 6 +- .../citizenScience/labels/textLabels/label.js | 2 - .../labels/textLabels/labelCheck.js | 5 +- .../labels/textLabels/labels.js | 4 +- .../labels/textLabels/labels.tpl.html | 2 +- .../labels/thumbLabels/_thumbs.scss | 6 +- .../labels/thumbLabels/examples.js | 3 +- .../labels/thumbLabels/label.js | 22 +-- .../labels/thumbLabels/label.tpl.html | 10 -- .../labels/thumbLabels/labels.js | 2 +- .../labels/userInput/_userInput.scss | 22 +++ .../labels/userInput/userInput.js | 45 ++++++ .../labels/userInput/userInput.tpl.html | 7 + src/app/citizenScience/listen/listen.js | 2 - .../responses/citizenScienceSampleLabels.js | 131 ++++++++---------- src/app/citizenScience/responses/responses.js | 6 - 21 files changed, 193 insertions(+), 153 deletions(-) create mode 100644 src/app/citizenScience/labels/_citizenScienceLabels.scss rename src/app/citizenScience/labels/textLabels/{_citizenScienceLabels.scss => _textLabels.scss} (95%) create mode 100644 src/app/citizenScience/labels/userInput/_userInput.scss create mode 100644 src/app/citizenScience/labels/userInput/userInput.js create mode 100644 src/app/citizenScience/labels/userInput/userInput.tpl.html diff --git a/src/app/citizenScience/citizenScienceCommon.js b/src/app/citizenScience/citizenScienceCommon.js index c052ac77..caaa970c 100644 --- a/src/app/citizenScience/citizenScienceCommon.js +++ b/src/app/citizenScience/citizenScienceCommon.js @@ -49,22 +49,6 @@ citizenScienceCommon.factory("CitizenScienceCommon", [ self.mediaModel = null; - /** - * Checks if a tag or array of tags is the same - * @param tags1 mixed string or array of strings - * @param tags2 mixed string or array of strings - */ - self.compareTags = function (tags1, tags2) { - if (Array.isArray(tags1)) { - tags1 = tags1.sort().join(""); - } - if (Array.isArray(tags2)) { - tags2 = tags2.sort().join(""); - } - return tags1 === tags2; - }; - - self.functions = { @@ -88,17 +72,6 @@ citizenScienceCommon.factory("CitizenScienceCommon", [ return labelObject; }, - /** - * Encode the array of labels as json - * @TODO: rename this to tags. Each label can have multiple tags. - * so this will be 2d array, outer array is labels and each label is an array of tags. - * @param labels array - * @returns String - */ - labelsAsString: function (labels) { - return JSON.stringify(labels); - }, - /** * Returns a function that sets the media member of the scope to the @@ -128,7 +101,6 @@ citizenScienceCommon.factory("CitizenScienceCommon", [ } ); - // do not block, do not wait for Media requests to finish return; }; diff --git a/src/app/citizenScience/examples/example.js b/src/app/citizenScience/examples/example.js index 8ea01b22..d500fa99 100644 --- a/src/app/citizenScience/examples/example.js +++ b/src/app/citizenScience/examples/example.js @@ -10,8 +10,6 @@ angular.module("bawApp.components.citizenScienceExample", ["bawApp.citizenScienc "baw.models.AudioEvent", function ($scope, $http, CitizenScienceCommon, libraryCommon, AudioEventService, AudioEvent) { - console.log("hello example"); - $scope.myName = "example"; var self = this; @@ -46,7 +44,6 @@ angular.module("bawApp.components.citizenScienceExample", ["bawApp.citizenScienc position: 0 }; - }, function annotationShowError(httpResponse) { console.error("Failed to load citizen science example item response.", httpResponse); diff --git a/src/app/citizenScience/labels/_citizenScienceLabels.scss b/src/app/citizenScience/labels/_citizenScienceLabels.scss new file mode 100644 index 00000000..f29ec022 --- /dev/null +++ b/src/app/citizenScience/labels/_citizenScienceLabels.scss @@ -0,0 +1,12 @@ + +.citizen-science { + + .labels-wrapper { + + background: rgba(0,0,0,0.7); + padding-top: 10px; + + } + +} + diff --git a/src/app/citizenScience/labels/citizenScienceLabels.js b/src/app/citizenScience/labels/citizenScienceLabels.js index 05433e3c..092b5144 100644 --- a/src/app/citizenScience/labels/citizenScienceLabels.js +++ b/src/app/citizenScience/labels/citizenScienceLabels.js @@ -2,7 +2,8 @@ var csLabels = angular.module("bawApp.citizenScience.csLabels", [ "bawApp.citizenScience.common", "bawApp.components.citizenScienceThumbLabels", "bawApp.components.citizenScienceTextLabels", - "bawApp.citizenScience.sampleLabels" + "bawApp.citizenScience.sampleLabels", + "bawApp.components.citizenScienceUserInput" ]); @@ -13,10 +14,13 @@ csLabels.component("citizenScienceLabels", { "SampleLabels", function ($scope, SampleLabels) { - var self = this; - console.log(self); + $scope.question = SampleLabels.question; + /** + * When the labels are updated (question data retrieved from the server) + * set up the labels and userInput UI + */ $scope.$watch(SampleLabels.getLabels, function (newVal, oldVal) { if (typeof(newVal) === "object") { @@ -31,13 +35,20 @@ csLabels.component("citizenScienceLabels", { $scope.labelType = "text"; } + + // // assume that when labels change fields also changes. + // $scope.fields = SampleLabels.getFields(); + $scope.labels = newVal; } }, true); + + }], bindings: { } }); + diff --git a/src/app/citizenScience/labels/labels.tpl.html b/src/app/citizenScience/labels/labels.tpl.html index d93c1573..59e46c0f 100644 --- a/src/app/citizenScience/labels/labels.tpl.html +++ b/src/app/citizenScience/labels/labels.tpl.html @@ -1,11 +1,10 @@ +
+ + - - - - - - + +
diff --git a/src/app/citizenScience/labels/textLabels/_citizenScienceLabels.scss b/src/app/citizenScience/labels/textLabels/_textLabels.scss similarity index 95% rename from src/app/citizenScience/labels/textLabels/_citizenScienceLabels.scss rename to src/app/citizenScience/labels/textLabels/_textLabels.scss index e7c98a02..8df534ae 100644 --- a/src/app/citizenScience/labels/textLabels/_citizenScienceLabels.scss +++ b/src/app/citizenScience/labels/textLabels/_textLabels.scss @@ -1,8 +1,8 @@ .citizen-science { - #label-buttons { - background: rgba(0, 0, 0, 0.6); + + #text-label-wrapper { width: 400px; margin: 0px auto 0px auto; text-align: center; @@ -10,7 +10,7 @@ padding: 0px 20px 20px 20px; } - #label-buttons, .label-check { + .label-check { padding-top: 8px; diff --git a/src/app/citizenScience/labels/textLabels/label.js b/src/app/citizenScience/labels/textLabels/label.js index 8f62d4b7..aefd2b1d 100644 --- a/src/app/citizenScience/labels/textLabels/label.js +++ b/src/app/citizenScience/labels/textLabels/label.js @@ -17,9 +17,7 @@ angular.module("bawApp.components.citizenScienceTextLabels.label", $scope.state = "empty"; - $scope.$watch("state", function (newVal, oldVal) { - console.log(newVal); SampleLabels.setValue($scope.state, self.label.id); }); diff --git a/src/app/citizenScience/labels/textLabels/labelCheck.js b/src/app/citizenScience/labels/textLabels/labelCheck.js index 5b00e8f1..4dbd0aa4 100644 --- a/src/app/citizenScience/labels/textLabels/labelCheck.js +++ b/src/app/citizenScience/labels/textLabels/labelCheck.js @@ -11,7 +11,7 @@ angular.module("bawApp.components.citizenScienceLabelCheck", ["bawApp.citizenSci * There are 4 possible states for the label, yes, no, maybe and empty. * Empty a bit like no. With no, it's been explicitly set as no, * whereas with empty it is the default state, not yet explicitly set. Once the state is changed from - * empty it can never be empty again. + * empty it can never be empty again, except when the bound $ctrl.state changes (e.g. on new segment). * There are two view variations for this: expanded or not * With expanded, the label will have 'yes', 'no' and 'maybe' checkboxes separately * With not expanded, there is one checkbox that cycles between yes, maybe and no @@ -26,8 +26,6 @@ angular.module("bawApp.components.citizenScienceLabelCheck", ["bawApp.citizenSci */ $scope.toggleLabel = function (stateIndex) { - console.log(self.state); - if (typeof stateIndex !== "number") { // no new stateIndex supplied so cycle through the states, excluding zero stateIndex = ($scope.stateIndex + 1); @@ -59,6 +57,7 @@ angular.module("bawApp.components.citizenScienceLabelCheck", ["bawApp.citizenSci $scope.stateIndexes = [1,2,3]; + // watch the state so that we can empty it when $scope.$watch(function () { return self.state; }, function (newVal, oldVal) { diff --git a/src/app/citizenScience/labels/textLabels/labels.js b/src/app/citizenScience/labels/textLabels/labels.js index 6fd78791..3c3f0998 100644 --- a/src/app/citizenScience/labels/textLabels/labels.js +++ b/src/app/citizenScience/labels/textLabels/labels.js @@ -13,7 +13,9 @@ angular.module("bawApp.components.citizenScienceTextLabels", onboardingService.addSteps([ { element: "label-check:first-of-type div", - intro: `Make your selection about whether ${this.labels[0].name} is in the recording`, + // TODO: fix this + // intro: `Make your selection about whether ${this.labels[0].name} is in the recording`, + intro: `Make your selection about whether this thing is in the recording`, order: 5 } diff --git a/src/app/citizenScience/labels/textLabels/labels.tpl.html b/src/app/citizenScience/labels/textLabels/labels.tpl.html index 190376ac..301b73d8 100644 --- a/src/app/citizenScience/labels/textLabels/labels.tpl.html +++ b/src/app/citizenScience/labels/textLabels/labels.tpl.html @@ -1,4 +1,4 @@ -
+
'; +$triangle: ''; + .thumb-labels-container { text-align: center; margin-top: 10px; - background: rgba(0, 0, 0, 0.3); position: relative; /* flexbox layout of thumbs */ @@ -78,7 +78,7 @@ $triangle: ' -
- - - { return SampleLabels.getFields(); }, (newVal, oldVal) => { + // if (angular.isArray(newVal)) { + // + // $scope.fieldDefinitions = newVal; + // + // newVal.forEach(f => { + // $scope.fields[f.name] = ""; + // }); + // + // // i want this to be assign by reference...but I don't think it is + // SampleLabels.data.fields = $scope.fields; + // } + // }, true); + + + // $scope.$watch("fields", function (newVal, oldVal) { + // SampleLabels.setFieldValues($scope.fields); + // }, true); + + + + + + }], + bindings: { + } + }); \ No newline at end of file diff --git a/src/app/citizenScience/labels/userInput/userInput.tpl.html b/src/app/citizenScience/labels/userInput/userInput.tpl.html new file mode 100644 index 00000000..91112ac5 --- /dev/null +++ b/src/app/citizenScience/labels/userInput/userInput.tpl.html @@ -0,0 +1,7 @@ + +
+ + + +
+ diff --git a/src/app/citizenScience/listen/listen.js b/src/app/citizenScience/listen/listen.js index dfc17ae0..52092d0d 100644 --- a/src/app/citizenScience/listen/listen.js +++ b/src/app/citizenScience/listen/listen.js @@ -126,8 +126,6 @@ class CitizenScienceListenController { //$scope.nextLink = null; $scope.$on(ngAudioEvents.ended, function navigate(event) { - console.log(event); - if (event.targetScope.audioElementModel === $scope.audioElementModel && $scope.audioElementModel.autoPlay) { $scope.$broadcast("autoNextTrigger"); } diff --git a/src/app/citizenScience/responses/citizenScienceSampleLabels.js b/src/app/citizenScience/responses/citizenScienceSampleLabels.js index c1a42d0f..3ad8324b 100644 --- a/src/app/citizenScience/responses/citizenScienceSampleLabels.js +++ b/src/app/citizenScience/responses/citizenScienceSampleLabels.js @@ -13,11 +13,23 @@ sampleLabels.factory("SampleLabels", [ var self = this; // the data for questionResponses. Each question will have a unique key - self.data = {}; - self.hasResponse = false; - self.allowEmpty = true; - self.allowMulti = true; - self.labels = false; + // self.data = {}; + //self.hasResponse = false; + + + self.question = { + allowEmpty: true, + allowMulti: true, + labels: [], + fields: [] + }; + + self.data = { + labels: {}, + fields: {}, + hasResponse: false + }; + /** @@ -31,36 +43,46 @@ sampleLabels.factory("SampleLabels", [ self.data.studyId = studyId; } if (question !== false) { + + // TODO: update to handle multiple questions + self.data.questionId = question.id; - self.labels = question.questionData.labels; + self.question.labels = question.questionData.labels; + + // set defaults if (question.questionData.hasOwnProperty("allowEmpty")) { - self.allowEmpty = question.questionData.allowEmpty; + self.question.allowEmpty = question.questionData.allowEmpty; } if (question.questionData.hasOwnProperty("allowMulti")) { - self.allowMulti = question.questionData.allowMulti; + self.question.allowMulti = question.questionData.allowMulti; } if (question.questionData.labels.length === 1) { // for binary yes/no there is only one label, therefore no multi select - self.allowMulti = false; + self.question.allowMulti = false; } // if label ids are not supplied, add them in. - if (!self.labels.every(l => l.hasOwnProperty("id"))) { + if (!self.question.labels.every(l => l.hasOwnProperty("id"))) { // if only some but not all label ids are supplied, error - if (self.labels.some(l => l.hasOwnProperty("id"))) { + if (self.question.labels.some(l => l.hasOwnProperty("id"))) { console.error("Invalid question data: Some but not all labels have ids"); } - self.labels = self.labels.map((l,i) => { + self.question.labels = self.question.labels.map((l,i) => { l.id = i+1; return(l); }); } + if (question.questionData.hasOwnProperty("fields")) { + // this holds field definitions, including field type + self.question.fields = question.questionData.fields; + } + } return self.data; @@ -68,49 +90,21 @@ sampleLabels.factory("SampleLabels", [ }; - /** - * adds or removes a label id from the list of true labels ids. This is now deprecated and - * here only for reference, since we now allow 'yes' and 'maybe' for a label. - * @param labelId int; may be omitted if it is a binary (only one label) task. - * @param value int [0,1] - */ - self.setValueOld = function (value, labelId) { - - if (labelId === undefined && self.labels.length === 1) { - labelId = 1; - } - - if (labelId !== undefined) { - self.hasResponse = true; - if (value) { - if (!self.allowMulti) { - self.data.labels.clear(); - } - self.data.labels.add(labelId); - } else { - self.data.labels.delete(labelId); - } - } else { - console.warn("Label id not defined"); - } - - }; - /** - * updates the + * updates the labels object to set the value for the given key * @param value String * @param labelId Int */ self.setValue = function (value, labelId) { - if (labelId === undefined && self.labels.length === 1) { + if (labelId === undefined && self.question.labels.length === 1) { labelId = 1; } if (labelId !== undefined) { - self.hasResponse = true; - if (value === "yes" && !self.allowMulti) { + self.data.hasResponse = true; + if (value === "yes" && !self.question.allowMulti) { self.data.labels = {}; } @@ -123,20 +117,10 @@ sampleLabels.factory("SampleLabels", [ }; - - /** - * Looks up the data to see if there is a boolean value stored for a given labelId - * and if so, returns it. - * @param labelId - * @returns {boolean} - */ - self.getValueOld = function (labelId) { - - if (labelId === undefined && self.labels.length === 1) { - labelId = 1; - } - return self.data.labels.has(labelId); - }; + // todo: check if we need this + // self.setFieldValues = function (fields) { + // self.data.fields = fields; + // }; /** * Looks up the data to see if there is a value stored for a given labelId @@ -146,7 +130,7 @@ sampleLabels.factory("SampleLabels", [ */ self.getValue = function (labelId) { - if (labelId === undefined && self.labels.length === 1) { + if (labelId === undefined && self.question.labels.length === 1) { labelId = 1; } @@ -164,6 +148,7 @@ sampleLabels.factory("SampleLabels", [ init : self.init, getValue : self.getValue, setValue : self.setValue, + setFieldValues: self.setFieldValues, setValueBinary : self.setValueBinary, /** @@ -171,7 +156,7 @@ sampleLabels.factory("SampleLabels", [ * @param notes string optional; message about the state when the response was submitted, e.g. autoplay on * @param userNotes string optional; message that the user entered */ - sendResponse : function (notes, userNotes) { + sendResponse : function (notes) { if (self.data.datasetItemId) { @@ -184,9 +169,9 @@ sampleLabels.factory("SampleLabels", [ if (notes) { userResponseData.notes = notes; } - if (userNotes) { - userResponseData.userNotes = userNotes; - } + + Object.assign(userResponseData, self.data.fields); + QuestionResponse.createQuestionResponse(self.data.questionId, self.data.datasetItemId, self.data.studyId, userResponseData); } @@ -200,9 +185,11 @@ sampleLabels.factory("SampleLabels", [ self.data.datasetItemId = newDatasetItemId; self.data.labels = {}; + self.data.fields = {}; + self.question.fields.forEach(f => self.data.fields[f.name] = ""); // hasResponse will be stay true if a value has been added and then removed // until this init function is called. - self.hasResponse = false; + self.data.hasResponse = false; }, @@ -210,12 +197,12 @@ sampleLabels.factory("SampleLabels", [ * returns an object that holds all the labels that have been applied to * the given sample and their values. (if a label has been removed then it will be stored * as false. If it has never been applied, it will not be present). - * @param sampleId - * @returns {*} + * @returns {*} object */ + // todo: do we need this? getLabelsForSample : function () { - return [...self.data.labels]; + return self.data.labels; }, /** @@ -223,15 +210,19 @@ sampleLabels.factory("SampleLabels", [ * @param sampleId */ hasResponse : function () { - return self.hasResponse; + return self.data.hasResponse; }, + // todo: do we need this? allowEmpty : function () { - return self.allowEmpty; + return self.question.allowEmpty; }, - getLabels: function () { return self.labels; } + // todo: do we need this? + getLabels: function () { return self.question.labels; }, + question: self.question, + data: self.data }; return self.functions; diff --git a/src/app/citizenScience/responses/responses.js b/src/app/citizenScience/responses/responses.js index 92bd9692..3ace3886 100644 --- a/src/app/citizenScience/responses/responses.js +++ b/src/app/citizenScience/responses/responses.js @@ -4,12 +4,6 @@ class ResponsesController { SampleLabels, Question) { - var self = this; - - // todo: display table of responses. - - console.log(self); - } }