'+
- '
'+
+ '
'+
'
Please enter a valid float.
'+
'
Please enter a larger float.
'+
@@ -185,15 +195,16 @@ export default
ngShow: 'type.type==="float" ',
addRequired: true,
editRequired: true,
- column: 2
+ column: 2,
+ class: 'Form-formGroup--singleColumn'
},
default:{
realName: 'default_answer',
type: 'custom' ,
control: '
',
column: 2,
- ngShow: 'type.type === "text" || type.type === "multiplechoice" '
+ ngShow: 'type.type === "text" || type.type === "multiplechoice" ',
+ class: 'Form-formGroup--singleColumn'
},
default_multiselect: {
realName: 'default_answer' ,
type: 'custom',
control: '
',
column: 2,
- ngShow: 'type.type==="multiselect" '
+ ngShow: 'type.type==="multiselect" ',
+ class: 'Form-formGroup--singleColumn'
},
default_int: {
realName: 'default_answer',
type: 'custom',
control: '
'+
- '
'+
- '
'+
+ '
'+
+ '
'+
'
Please enter a valid integer.
'+
'
Please enter a value in the range of {{int_min}} to {{int_max}}.
'+
'
',
column: 2,
- ngShow: 'type.type === "integer" '
+ ngShow: 'type.type === "integer" ',
+ class: 'Form-formGroup--singleColumn'
},
default_float: {
realName: 'default_answer',
type: 'custom',
control: '
'+
- '
'+
- '
'+
+ '
'+
+ '
'+
'
Please enter a valid float.
'+
'
Please enter a value in the range of {{float_min}} to {{float_max}}!
'+
'
',
column: 2,
- ngShow: 'type.type=== "float" '
+ ngShow: 'type.type=== "float" ',
+ class: 'Form-formGroup--singleColumn'
},
default_textarea: {
realName: "default_answer" ,
type: 'custom',
- control: '
'+
- '
'+
+ control: '
',
- column : 2,
- ngShow: 'type.type === "textarea" '
+ column : 2,
+ ngShow: 'type.type === "textarea" ',
+ class: 'Form-formGroup--singleColumn'
},
default_password: {
realName: 'default_answer' ,
type: 'custom' ,
control: '
',
column: 2,
- ngShow: 'type.type === "password" '
+ ngShow: 'type.type === "password" ',
+ class: 'Form-formGroup--singleColumn'
},
required: {
realName: 'required_answer',
@@ -282,20 +299,22 @@ export default
type: 'checkbox',
addRequired: false,
editRequired: false,
- column: 2
+ column: 2,
+ class: 'Form-formGroup--singleColumn'
}
},
buttons: {
- question_cancel : {
- label: 'Cancel',
- 'class' : 'btn btn-default',
- ngClick: 'cancelQuestion($event)'
- },
submit_question: {
ngClick: 'submitQuestion($event)',
ngDisabled: true,
- 'class': 'btn btn-sm btn-primary',
- label: 'Add Question'
+ 'class': 'btn btn-sm Form-saveButton',
+ label: '{{editQuestionIndex === null ? "ADD" : "UPDATE"}}'
+ },
+ question_cancel : {
+ label: 'Cancel',
+ 'class' : 'btn btn-default Form-cancelButton',
+ ngClick: 'generateAddQuestionForm()',
+ ngDisabled: 'survey_question_form.$pristine'
}
}
diff --git a/awx/ui/client/src/job-templates/survey-maker/survey-maker.block.less b/awx/ui/client/src/job-templates/survey-maker/survey-maker.block.less
new file mode 100644
index 0000000000..53ff0e746d
--- /dev/null
+++ b/awx/ui/client/src/job-templates/survey-maker/survey-maker.block.less
@@ -0,0 +1,212 @@
+@import "awx/ui/client/src/shared/branding/colors.default.less";
+
+.SurveyMaker-dialog {
+ padding: 0px;
+
+ .ui-dialog-buttonpane, .ui-dialog-titlebar {
+ display:none;
+ }
+}
+.SurveyMaker-header {
+ display: flex;
+ align-items: center;
+}
+.SurveyMaker-title {
+ align-items: center;
+ flex: 1 0 auto;
+ display: flex;
+}
+.SurveyMaker-titleText {
+ color: @list-title-txt;
+ font-size: 14px;
+ font-weight: bold;
+ margin-right: 10px;
+ text-transform: uppercase;
+}
+.SurveyMaker-titleLockup {
+ margin-left: 4px;
+ margin-right: 6px;
+ display: inline-block;
+ margin-top: 0px;
+ padding-bottom: 2px;
+ vertical-align: bottom;
+}
+.SurveyMaker-titleLockup:before {
+ content: "\007C";
+ color: @default-icon-hov;
+ display: block;
+ font-size: 13px;
+}
+.SurveyMaker-close {
+ justify-content: flex-end;
+ display: flex;
+}
+.SurveyMaker-exit{
+ cursor:pointer;
+ padding:0px;
+ border: none;
+ height:20px;
+ font-size: 20px;
+ background-color:@default-bg;
+ color:@default-second-border;
+ transition: color 0.2s;
+ line-height:1;
+}
+.SurveyMaker-exit:hover{
+ color:@default-icon;
+}
+.SurveyMaker-content {
+ display: flex;
+ margin-top: 25px;
+}
+.SurveyMaker-questionPanel {
+ display: flex;
+ flex: 0 0 475px;
+}
+.SurveyMaker-previewPanel {
+ display: flex;
+ flex: 0 0 637px;
+}
+.SurveyMaker-separatorPanel {
+ display: flex;
+ flex: 0 0 51px;
+}
+.SurveyMaker-contentSeparator {
+ width: 1px;
+ background-color: @default-list-header-bg;
+ margin: 0px 25px;
+}
+.SurveyMaker-panelHeader {
+ color: @default-icon;
+ padding-bottom: 20px;
+ min-height: 40px;
+ flex: 0 0 auto;
+ text-transform: uppercase;
+ font-size: 14px;
+ font-weight: bold;
+ white-space: nowrap;
+}
+.SurveyMaker-panelBody {
+ flex: 1 0 auto;
+ padding-bottom: 20px;
+}
+.SurveyMaker-panelFooter {
+ flex: 0 0 auto;
+}
+.SurveyMaker-noQuestions {
+ color: @default-icon;
+}
+.SurveyMaker-deleteButton {
+ font-size: 16px;
+ height: 30px;
+ min-width: 30px;
+ color: @list-action-icon;
+ background-color: @list-actn-bg;
+ border: none;
+ border-radius: 50%;
+ margin-right: 15px;
+}
+
+.SurveyMaker-deleteButton:hover {
+ background-color: @list-actn-del-bg-hov !important;
+ color: @list-actn-icn-hov;
+}
+.SurveyMaker-previewLabel {
+ text-transform: uppercase;
+ color: @default-interface-txt;
+ font-weight: normal;
+ font-size: small;
+ width: 100%;
+}
+.SurveyMaker-deleteOverlay {
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: rgba(0,0,0,0.3);
+ z-index: 3;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+}
+.SurveyMaker-deleteModal {
+ height: 200px;
+ width: 600px;
+ background-color: @default-bg;
+ border-radius: 5px;
+}
+.SurveyMaker-previewInputRow {
+ display: flex;
+ margin-bottom: 20px;
+}
+.SurveyMaker-previewInput {
+ flex: 1 0 523px;
+ max-width: 523px;
+}
+.SurveyMaker-previewActions {
+ display: flex;
+ align-items: center;
+ margin-left: 20px;
+}
+.SurveyMaker-previewActions--selected {
+ background-color: @default-link !important;
+ color: @default-bg;
+}
+.SurveyMaker-previewRows {
+ position: relative;
+ min-height: 42px;
+ padding-left: 0px;
+
+ /* These classes are dynamically added via the angular-drag-and-drop-lists directive */
+ .dndPlaceholder {
+ display: block;
+ background-color: @default-tertiary-bg;
+ padding: 10px 15px;
+ min-height: 42px;
+ margin-bottom: 20px;
+ border-radius: 4px;
+ color: @default-interface-txt;
+ }
+
+ .dndDraggingSource {
+ display: none;
+ }
+}
+.SurveyMaker-previewRow {
+ position: relative;
+ display: block;
+
+ /* Disable text selection if item is not draggable */
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.SurveyMaker-reorderButton {
+ color: @default-icon;
+ margin-right: 10px;
+ display: flex;
+ align-items: center;
+ cursor: -moz-grab;
+ cursor: -webkit-grab;
+ cursor: grab;
+}
+.SurveyMaker-reorderButton:hover {
+ color: @default-interface-txt;
+}
+.SurveyMaker-previewPasswordButton {
+ padding: 7px 15px!important;
+}
+.SurveyMaker-previewInput {
+ .select2-container--disabled {
+ opacity: inherit!important;
+ }
+}
+.SurveyMaker-previewMultiSelect {
+ background-color: #EEEEEE!important;
+ cursor: not-allowed!important;
+}
diff --git a/awx/ui/client/src/job-templates/survey-maker/surveys/add.factory.js b/awx/ui/client/src/job-templates/survey-maker/surveys/add.factory.js
index 0bb42dd274..1c9fba3ba5 100644
--- a/awx/ui/client/src/job-templates/survey-maker/surveys/add.factory.js
+++ b/awx/ui/client/src/job-templates/survey-maker/surveys/add.factory.js
@@ -3,17 +3,19 @@ export default
return function(params) {
var scope = params.scope;
+ // This variable controls the survey on/off toggle beside the create survey
+ // modal title. We want this toggle to be on by default
+ scope.survey_enabled = true;
+
if (scope.removeDialogReady) {
scope.removeDialogReady();
}
scope.removeDialogReady = scope.$on('DialogReady', function() {
$('#survey-modal-dialog').dialog('open');
- scope.addQuestion();
+ scope.generateAddQuestionForm();
});
Wait('start');
- $('#form-container').empty();
- scope.resetForm();
- ShowSurveyModal({ title: "Add Survey", scope: scope, callback: 'DialogReady' });
+ ShowSurveyModal({ scope: scope, callback: 'DialogReady' });
};
}
diff --git a/awx/ui/client/src/job-templates/survey-maker/surveys/delete.factory.js b/awx/ui/client/src/job-templates/survey-maker/surveys/delete.factory.js
index 4c753816c6..0dbe5b4c94 100644
--- a/awx/ui/client/src/job-templates/survey-maker/surveys/delete.factory.js
+++ b/awx/ui/client/src/job-templates/survey-maker/surveys/delete.factory.js
@@ -4,7 +4,6 @@
* DeleteSurvey({
* scope: $scope containing list of survey form fields
* id: id of job template that survey is attached to
- * callback: $scope.$emit label to call when delete is completed
* })
*
*/
@@ -14,7 +13,6 @@ export default
var scope = params.scope,
id = params.id,
- // callback = params.callback,
url;
@@ -25,11 +23,9 @@ export default
scope.survey_name = "";
scope.survey_description = "";
scope.survey_questions = [];
+ scope.closeSurvey('survey-modal-dialog');
Wait('stop');
scope.survey_exists = false;
- $('#job_templates_delete_survey_btn').hide();
- $('#job_templates_edit_survey_btn').hide();
- $('#job_templates_create_survey_btn').show();
});
diff --git a/awx/ui/client/src/job-templates/survey-maker/surveys/edit.factory.js b/awx/ui/client/src/job-templates/survey-maker/surveys/edit.factory.js
index b303a2f470..7ac32857ea 100644
--- a/awx/ui/client/src/job-templates/survey-maker/surveys/edit.factory.js
+++ b/awx/ui/client/src/job-templates/survey-maker/surveys/edit.factory.js
@@ -1,10 +1,8 @@
export default
- function EditFactory($stateParams, SchedulerInit, ShowSurveyModal, Wait, Rest, ProcessErrors, GetBasePath, GenerateForm,
- Empty, AddSurvey) {
+ function EditFactory(ShowSurveyModal, Wait, Rest, ProcessErrors, GetBasePath, Empty, AddSurvey) {
return function(params) {
var scope = params.scope,
id = params.id,
- tempSurv = {},
url = GetBasePath('job_templates') + id + '/survey_spec/', i;
if (scope.removeDialogReady) {
@@ -12,24 +10,13 @@ export default
}
scope.removeDialogReady = scope.$on('DialogReady', function() {
$('#survey-modal-dialog').dialog('open');
+ scope.generateAddQuestionForm();
});
- scope.resetForm();
Wait('start');
//for adding a job template:
if(scope.mode === 'add'){
- tempSurv.survey_name = scope.survey_name;
- tempSurv.survey_description = scope.survey_description;
- tempSurv.survey_questions = scope.survey_questions;
-
ShowSurveyModal({ title: "Edit Survey", scope: scope, callback: 'DialogReady' });
-
- // scope.survey_name = tempSurv.survey_name;
- // scope.survey_description = tempSurv.survey_description;
-
- for(i=0; i
= 0; i--) {
+ if (scope.survey_questions[i].new_question) {
+ scope.survey_questions.splice(i, 1);
+ }
+ }
}
else {
+ // Clear out the whole array, this data gets pulled in each time the modal is opened
scope.survey_questions = [];
}
- $(me).dialog('close');
+ $('#' + id).dialog('destroy');
+ }
+
+ // Gets called when a user actually hits the save button. Functionality differs
+ // based on the mode. scope.mode="add" cleans up scope.survey_questions and
+ // destroys the modal, holding the survey questions in memory. scope.mode="edit"
+ // actually fires off the necessary server call(s) to add/update a survey.
+ scope.saveSurvey = function() {
+ Wait('start');
+ if(scope.mode ==="add"){
+ // Loop across the survey questions and remove any new_question flags
+ angular.forEach(scope.survey_questions, function(question, key) {
+ delete question['new_question'];
+ });
+
+ $('#survey-modal-dialog').dialog('destroy');
+ scope.survey_name = "";
+ scope.survey_description = "";
+ scope.$emit('SurveySaved');
+ }
+ else {
+
+ scope.survey_name = "";
+ scope.survey_description = "";
+
+ var updateSurveyQuestions = function() {
+ Rest.setUrl(GetBasePath('job_templates') + id + '/survey_spec/');
+ return Rest.post({name: scope.survey_name, description: scope.survey_description, spec: scope.survey_questions })
+ .success(function (data) {
+
+ })
+ .error(function (data, status) {
+ ProcessErrors(scope, data, status, null, { hdr: 'Error!',
+ msg: 'Failed to add new survey. POST returned status: ' + status });
+ });
+ }
+
+ var updateSurveyEnabled = function() {
+ Rest.setUrl(GetBasePath('job_templates') + id+ '/');
+ return Rest.patch({"survey_enabled": scope.survey_enabled})
+ .success(function (data) {
+
+ })
+ .error(function (data, status) {
+ ProcessErrors(scope, data, status, form, {
+ hdr: 'Error!',
+ msg: 'Failed to retrieve save survey_enabled: ' + $routeParams.template_id + '. GET status: ' + status
+ });
+ });
+ }
+
+ updateSurveyQuestions()
+ .then(function() {
+ return updateSurveyEnabled();
+ })
+ .then(function() {
+ scope.closeSurvey('survey-modal-dialog');
+ scope.$emit('SurveySaved');
+ })
+
+ }
};
- scope.addQuestion = function(){
+ // Gets called when the user clicks the on/off toggle beside the survey modal title.
+ scope.toggleSurveyEnabled = function() {
+ scope.survey_enabled = !scope.survey_enabled;
+ };
+
+ /* END SURVEY RELATED FUNCTIONS */
+
+ /* QUESTION RELATED FUNCTIONS */
+
+ // This injects the Add Question form into survey_maker_question_form
+ scope.generateAddQuestionForm = function(){
+ // This tmpMode logic is necessary because form generator seems to set scope.mode to match the mode that you pass it.
+ // So if a user is editing a job template (scope.mode='edit') but the JT doesn't have a survey then when we open the
+ // modal we need to make sure that scope.mode is still 'edit' after the Add Question form is injected.
+ // To avoid having to do this we'd need to track the job template mode in a variable other than scope.mode.
var tmpMode = scope.mode;
- GenerateForm.inject(form, { id:'new_question', mode: 'add' , scope: scope, related: false});
+ GenerateForm.inject(form, { id:'survey_maker_question_form', mode: 'add' , scope: scope, related: false});
scope.mode = tmpMode;
- scope.required = true; //set the required checkbox to true via the ngmodel attached to scope.required.
- scope.text_min = null;
- scope.text_max = null;
- scope.int_min = null;
- scope.int_max = null;
- scope.float_min = null;
- scope.float_max = null;
- scope.duplicate = false;
- scope.invalidChoice = false;
- scope.minTextError = false;
- scope.maxTextError = false;
+ scope.clearQuestion();
};
- scope.addNewQuestion = function(){
- // $('#add_question_btn').on("click" , function(){
- scope.addQuestion();
- $('#survey_question_question_name').focus();
- $('#add_question_btn').attr('disabled', 'disabled');
- $('#add_question_btn').hide();
- $('#survey-save-button').attr('disabled' , 'disabled');
- // });
- };
+ // This gets called when a users clicks the pencil icon beside a question preview in order to edit it.
scope.editQuestion = function(index){
scope.duplicate = false;
+ // The edit question factory injects the edit form and fills the form with the question data from memory.
EditQuestion({
index: index,
scope: scope,
- question: (scope.mode==='add') ? questions[index] : scope.survey_questions[index]
+ question: scope.survey_questions[index]
});
};
+ // Gets called when a user clicks the delete icon on a question in the survey preview
+ scope.showDeleteQuestion = function(deleteIndex) {
+ // Keep track of the question to be deleted on scope
+ scope.questionToBeDeleted = deleteIndex;
+ // Show the delete overlay with mode='question'
+ scope.showDeleteOverlay('question');
+ }
+
+ // Called after a user confirms question deletion (hitting the DELETE button on the delete question overlay).
scope.deleteQuestion = function(index){
- element = $('.question_final:eq('+index+')');
- element.remove();
- if(scope.mode === 'add'){
- questions.splice(index, 1);
- scope.reorder();
- if(questions.length<1){
- $('#survey-save-button').attr('disabled', 'disabled');
- }
- }
- else {
- scope.survey_questions.splice(index, 1);
- scope.reorder();
- if(scope.survey_questions.length<1){
- $('#survey-save-button').attr('disabled', 'disabled');
+ // Move the edit question index down by one if this question came before the
+ // one being edited in the array. This makes sure that our pointer to the question
+ // currently being edited gets updated independently from a deleted question.
+ if(GenerateForm.mode === 'edit' && !isNaN(scope.editQuestionIndex)){
+ if(scope.editQuestionIndex == index) {
+ // The user is deleting the question being edited - need to roll back to Add Question mode
+ scope.editQuestionIndex = null;
+ scope.generateAddQuestionForm();
+ }
+ else if(scope.editQuestionIndex > index) {
+ scope.editQuestionIndex--;
}
}
+ // Remove the question from the array
+ scope.survey_questions.splice(index, 1);
+ // Hide the delete overlay
+ scope.hideDeleteOverlay();
};
- scope.cancelQuestion = function(event){
- var elementID, key;
- if(event.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.id==="new_question"){
- $('#new_question .aw-form-well').remove();
- $('#add_question_btn').show();
- $('#add_question_btn').removeAttr('disabled');
- if(scope.mode === 'add' && questions.length>0){
- $('#survey-save-button').removeAttr('disabled');
- }
- if(scope.mode === 'edit' && scope.survey_questions.length>0 && scope.can_edit===true){
- $('#survey-save-button').removeAttr('disabled');
- }
-
- } else {
- elementID = event.target.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.id;
- key = elementID.split('_')[1];
- $('#'+elementID).empty();
- if(scope.mode === 'add'){
- if(questions.length>0){
- $('#survey-save-button').removeAttr('disabled');
- }
- scope.finalizeQuestion(questions[key], Number(key));
- }
- else if(scope.mode=== 'edit' ){
- if(scope.survey_questions.length>0 && scope.can_edit === true){
- $('#survey-save-button').removeAttr('disabled');
- }
- scope.finalizeQuestion(scope.survey_questions[key] , Number(key));
- }
- }
- };
-
- scope.questionUp = function(index){
- var animating = false,
- clickedDiv = $('#question_'+index),
- prevDiv = clickedDiv.prev(),
- distance = clickedDiv.outerHeight();
-
- if (animating) {
- return;
- }
-
- if (prevDiv.length) {
- animating = true;
- $.when(clickedDiv.animate({
- top: -distance
- }, 600),
- prevDiv.animate({
- top: distance
- }, 600)).done(function () {
- prevDiv.css('top', '0px');
- clickedDiv.css('top', '0px');
- clickedDiv.insertBefore(prevDiv);
- animating = false;
- if ( scope.mode === 'add'){
- i = questions[index];
- questions[index] = questions[index-1];
- questions[index-1] = i;
- } else {
- i = scope.survey_questions[index];
- scope.survey_questions[index] = scope.survey_questions[index-1];
- scope.survey_questions[index-1] = i;
- }
- scope.reorder();
- });
- }
- };
-
- scope.questionDown = function(index){
- var clickedDiv = $('#question_'+index),
- nextDiv = clickedDiv.next(),
- distance = clickedDiv.outerHeight(),
- animating = false;
-
- if (animating) {
- return;
- }
-
- if (nextDiv.length) {
- animating = true;
- $.when(clickedDiv.animate({
- top: distance
- }, 600),
- nextDiv.animate({
- top: -distance
- }, 600)).done(function () {
- nextDiv.css('top', '0px');
- clickedDiv.css('top', '0px');
- nextDiv.insertBefore(clickedDiv);
- animating = false;
- if(scope.mode === 'add'){
- i = questions[index];
- questions[index] = questions[Number(index)+1];
- questions[Number(index)+1] = i;
- } else {
- i = scope.survey_questions[index];
- scope.survey_questions[index] = scope.survey_questions[Number(index)+1];
- scope.survey_questions[Number(index)+1] = i;
- }
- scope.reorder();
- });
- }
- };
-
- scope.reorder = function(){
- if(scope.mode==='add'){
- for(i=0; i'+
- ''+
- ''+
- ''+
- ''+
- ''+
- ''+
- '
';
- $('#survey-modal-dialog').html(html);
- element = angular.element(document.getElementById('add_question_btn'));
- $compile(element)(scope);
- };
- scope.saveSurvey = function() {
- Wait('start');
- if(scope.mode ==="add"){
- $('#survey-modal-dialog').dialog('close');
- if(questions.length>0){
- scope.survey_questions = questions;
+ // This function is bound to the dnd-drop directive. When a question is dragged and
+ // dropped, this is the function that gets called.
+ scope.surveyQuestionDropped = function(dropIndex, question) {
+
+ // Handle moving the question to its new slot in scope.survey_questions
+ for(var i=0; i
i && dropIndex >= scope.editQuestionIndex) {
+ // An element that was ahead of the edit question is now behind it
+ scope.editQuestionIndex--;
+ }
+ }
+ }
+
+ // Break out of the for loop
+ break;
}
- scope.survey_name = "";
- scope.survey_description = "";
- questions = [] ;
- scope.$emit('SurveySaved');
- }
- else{
- scope.survey_name = "";
- scope.survey_description = "";
- url = GetBasePath('job_templates') + id + '/survey_spec/';
- Rest.setUrl(url);
- Rest.post({ name: scope.survey_name, description: scope.survey_description, spec: scope.survey_questions })
- .success(function () {
- // Wait('stop');
- $('#survey-modal-dialog').dialog('close');
- scope.$emit('SurveySaved');
- })
- .error(function (data, status) {
- ProcessErrors(scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to add new survey. POST returned status: ' + status });
- });
- }
- };
- //for toggling the input on password inputs
+ };
+
+ // return true here signals that the drop is allowed, but that we've already taken care of inserting the element
+ return true;
+ }
+
+ // Gets called when a user is creating/editing a question that has a password
+ // field. The password field in the form has a SHOW/HIDE button that calls this.
scope.toggleInput = function(id) {
+ // Note that the id string passed into this function will have a "#" prepended
var buttonId = id + "_show_input_button",
inputId = id,
buttonInnerHTML = $(buttonId).html();
- if (buttonInnerHTML.indexOf("Show") > -1) {
- $(buttonId).html("Hide");
+ if (buttonInnerHTML.indexOf("SHOW") > -1) {
+ $(buttonId).html("HIDE");
$(inputId).attr("type", "text");
} else {
- $(buttonId).html("Show");
+ $(buttonId).html("SHOW");
$(inputId).attr("type", "password");
}
};
+ /* END QUESTION RELATED FUNCTIONS */
+
+ /* DELETE OVERLAY RELATED FUNCTIONS */
+
+ // This handles setting the delete mode and flipping the boolean used to show the delete overlay
+ scope.showDeleteOverlay = function(mode) {
+ // Set the delete mode (question or survey) so that the overlay knows
+ // how to phrase the prompt
+ scope.deleteMode = mode;
+ // Flip the deleteOverlayVisible flag so that the overlay becomes visible via ng-show
+ scope.deleteOverlayVisible = true;
+ }
+
+ // Called by the cancel/close buttons on the delete overlay. Also called after deletion has been confirmed.
+ scope.hideDeleteOverlay = function() {
+ // Clear out the delete mode for next time
+ scope.deleteMode = null;
+ // Clear out the index variable for next time
+ scope.questionToBeDeleted = null;
+ // Hide the delete overlay
+ scope.deleteOverlayVisible = false;
+ }
+
+ /* END DELETE OVERLAY RELATED FUNCTIONS */
+
+ // Watcher that updates the survey enabled/disabled tooltip based on scope.survey_enabled
+ scope.$watch('survey_enabled', function(newVal, oldVal) {
+ scope.surveyEnabledTooltip = (newVal) ? "Disable survey" : "Enable survey";
+ })
+
};
}
Init.$inject =
- [ '$location',
- 'deleteSurvey',
+ [ 'deleteSurvey',
'editSurvey',
'addSurvey',
'GenerateForm',
@@ -554,7 +542,6 @@ Init.$inject =
'Rest',
'ProcessErrors',
'$compile',
- 'finalizeQuestion',
'editQuestion',
- '$sce'
+ 'CreateSelect2'
];
diff --git a/awx/ui/client/src/job-templates/survey-maker/surveys/show.factory.js b/awx/ui/client/src/job-templates/survey-maker/surveys/show.factory.js
index 829884c662..45f8b150f3 100644
--- a/awx/ui/client/src/job-templates/survey-maker/surveys/show.factory.js
+++ b/awx/ui/client/src/job-templates/survey-maker/surveys/show.factory.js
@@ -8,60 +8,26 @@ export default
mode = (params.mode) ? params.mode : "survey-maker",
title = params.title,
element,
- target = (mode==='survey-taker') ? 'password-modal' : "survey-modal-dialog",
- buttons = [{
- "label": "Cancel",
- "onClick": function() {
- scope.cancelSurvey(this);
- },
- "icon": "fa-times",
- "class": "btn btn-default",
- "id": "survey-close-button"
- },{
- "label": (mode==='survey-taker') ? "Launch" : "Save" ,
- "onClick": function() {
- setTimeout(function(){
- scope.$apply(function(){
- if(mode==='survey-taker'){
- scope.$emit('SurveyTakerCompleted');
- } else{
- scope.saveSurvey();
- }
- });
- });
- },
- "icon": (mode==='survey-taker') ? "fa-rocket" : "fa-check",
- "class": "btn btn-primary",
- "id": "survey-save-button"
- }];
+ target = (mode==='survey-taker') ? 'password-modal' : "survey-modal-dialog";
CreateDialog({
id: target,
title: title,
scope: scope,
- buttons: buttons,
- width: 700,
- height: 725,
+ width: 1200,
minWidth: 400,
+ draggable: false,
+ dialogClass: 'SurveyMaker-dialog',
onClose: function() {
$('#'+target).empty();
},
onOpen: function() {
Wait('stop');
- if(mode!=="survey-taker"){
- // if(scope.mode === 'add'){
- // $('#survey-save-button').attr('disabled' , true);
- // } else
- if(scope.can_edit === false){
- $('#survey-save-button').attr('disabled', "disabled");
- }
- else {
- $('#survey-save-button').attr('ng-disabled', "survey_questions.length<1 ");
- }
- element = angular.element(document.getElementById('survey-save-button'));
- $compile(element)(scope);
- }
+ // Let the modal height be variable based on the content
+ // and set a uniform padding
+ $('#'+target).css({'height': 'auto', 'padding': '20px'});
+
if(mode==="survey-taker"){
$('#survey-save-button').attr('ng-disabled', "survey_taker_form.$invalid");
element = angular.element(document.getElementById('survey-save-button'));
diff --git a/awx/ui/client/src/partials/survey-maker-modal.html b/awx/ui/client/src/partials/survey-maker-modal.html
new file mode 100644
index 0000000000..df2097962f
--- /dev/null
+++ b/awx/ui/client/src/partials/survey-maker-modal.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+
Are you sure you want to delete this {{deleteMode}}?
+
{{survey_questions[questionToBeDeleted].question_name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
PLEASE ADD A QUESTION ON THE LEFT
+
+ -
+
+
+
+
+
+
+ {{question.question_description}}
+
+
+
+ -
+ Drop question here to reorder
+
+
+
+
+
+
+
+
+
diff --git a/awx/ui/client/src/partials/survey_maker.html b/awx/ui/client/src/partials/survey_maker.html
deleted file mode 100644
index 72398bc08f..0000000000
--- a/awx/ui/client/src/partials/survey_maker.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
diff --git a/awx/ui/client/src/shared/Modal.js b/awx/ui/client/src/shared/Modal.js
index 37ae34f97a..ad5b4e541b 100644
--- a/awx/ui/client/src/shared/Modal.js
+++ b/awx/ui/client/src/shared/Modal.js
@@ -60,6 +60,8 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
beforeDestroy = params.beforeDestroy,
closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape,
resizable = (params.resizable === undefined) ? true : params.resizable,
+ draggable = (params.draggable === undefined) ? true : params.draggable,
+ dialogClass = params.dialogClass,
forms = _.chain([params.form]).flatten().compact().value(),
buttons,
id = params.id,
@@ -104,6 +106,8 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
title: title,
closeOnEscape: closeOnEscape,
resizable: resizable,
+ draggable: draggable,
+ dialogClass: dialogClass,
create: function () {
// Fix the close button
$('.ui-dialog[aria-describedby="' + id + '"]').find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).html('');
diff --git a/awx/ui/client/src/shared/Utilities.js b/awx/ui/client/src/shared/Utilities.js
index ee2e3b1d9d..44fe9ab2ee 100644
--- a/awx/ui/client/src/shared/Utilities.js
+++ b/awx/ui/client/src/shared/Utilities.js
@@ -615,7 +615,8 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
var element = params.element,
options = params.opts,
multiple = (params.multiple!==undefined) ? params.multiple : true,
- placeholder = params.placeholder;
+ placeholder = params.placeholder,
+ customDropdownAdapter = (params.customDropdownAdapter!==undefined) ? params.customDropdownAdapter : true;
$.fn.select2.amd.require([
'select2/utils',
@@ -632,14 +633,22 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
return Utils.Decorate(Adapter, Decorator);
}, Dropdown);
- $(element).select2({
+ var config = {
placeholder: placeholder,
multiple: multiple,
containerCssClass: 'Form-dropDown',
width: '100%',
minimumResultsForSearch: Infinity,
- dropdownAdapter: CustomAdapter
- });
+ }
+
+ // multiple-choice directive calls select2 but needs to do so without this custom adapter
+ // to allow the element to be draggable on survey preview.
+ if(customDropdownAdapter) {
+ config.dropdownAdapter = CustomAdapter;
+ }
+
+ $(element).select2(config);
+
if(options){
for (var d = 0; d < $(element + " option").length; d++) {
var item = $(element + " option")[d];
diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js
index 0f3ea7445a..42f3567f58 100644
--- a/awx/ui/client/src/shared/form-generator.js
+++ b/awx/ui/client/src/shared/form-generator.js
@@ -261,7 +261,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
$('.form-control[required], input[type="radio"][required]').each(function () {
var label, span;
if (Empty($(this).attr('aw-required-when'))) {
- label = $(this).parent().parent().find('label').first();
+ label = $(this).closest('.form-group').find('label').first();
if ($(this).attr('type') === 'radio') {
label = $(this).parent().parent().parent().find('label').first();
}
@@ -568,7 +568,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
}
html += "\n";
return html;
},
@@ -674,7 +673,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += "id=\"" + form.name + "_" + fld + "_chbox\" ";
html += (idx !== undefined) ? "_" + idx : "";
html += "class=\"";
- html += (field['class']) ? field['class'] + " " : "";
html += "\"";
html += (field.trueValue !== undefined) ? Attr(field, 'trueValue') : "";
html += (field.falseValue !== undefined) ? Attr(field, 'falseValue') : "";
@@ -737,7 +735,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += "\">\n";
html += "\n";
@@ -783,7 +780,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += buildId(field, fld, this.form);
html += (field.controlNGClass) ? "ng-class=\"" + field.controlNGClass + "\" " : "";
html += "class=\"form-control Form-textInput ";
- html += (field['class']) ? " " + this.attr(field, 'class') : "";
html += "\" ";
html += (field.placeholder) ? this.attr(field, 'placeholder') : "";
html += (options.mode === 'edit' && field.editRequired) ? "required " : "";
@@ -915,7 +911,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += (field.controlNGClass) ? "ng-class='" + field.controlNGClass + "' " : "";
html += "class='form-control Form-textInput";
- html += (field['class']) ? " " + this.attr(field, 'class') : "";
html += "' ";
html += (field.chkPass) ? "chk-pass " : "";
@@ -1044,7 +1039,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += "class=\"form-control Form-textArea";
- html += (field['class']) ? " " + field['class'] : "";
html += (field['elementClass']) ? " " + field['elementClass'] : "";
html += "\" ";
html += (field.ngChange) ? this.attr(field, 'ngChange') : "";
@@ -1083,7 +1077,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += "class=\"form-control Form-dropDown";
- html += (field['class']) ? " " + field['class'] : "";
html += "\" ";
html += (field.ngOptions) ? this.attr(field, 'ngOptions') : "" ;
html += (field.ngChange) ? this.attr(field, 'ngChange') : "";
@@ -1138,7 +1131,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
if (!field.slider && !field.spinner) {
html += "form-control";
}
- html += (field['class']) ? " " + field['class'] : "";
html += "\" ";
html += (field.slider) ? "aw-slider=\"" + fld + "\" " : "";
html += (field.spinner) ? "aw-spinner=\"" + fld + "\" " : "";
@@ -1387,14 +1379,16 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
// title and exit button
html += "\n"; //end of Form-header
-
-
+ html += "
\n"; //end of Form-header
if (this.form.tabs) {
var collection;