Skip to content

Instantly share code, notes, and snippets.

@mkopinsky
Created February 26, 2018 00:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkopinsky/3424d56b96ce751b3d67230f9e5ae8a9 to your computer and use it in GitHub Desktop.
Save mkopinsky/3424d56b96ce751b3d67230f9e5ae8a9 to your computer and use it in GitHub Desktop.
Survey Editor overrides for usability
/**
* Attach the surveyjs editor to a div on the page
*
* @param string el jquery selector for the place to attach the editor
* @param object initialValue the current schema for the survey
* @param function saveSchemaCallback Callback to be called each time the survey schema is modified
*/
function attachSurveyEditor(el, initialValue, saveSchemaCallback) {
var editor = new SurveyEditor.SurveyEditor(el, editorOptions);
editor.text = JSON.stringify(initialValue);
editor.onModified.add(function() {
saveSchemaCallback(editor.getSurveyJSON());
});
// Call the callback right away as well
saveSchemaCallback(editor.getSurveyJSON());
// Add our user-defined questions, and clear out the prior items
editor.toolbox.addItems(getQuestionTypes(editor), true);
// Hide the apply button
editor.showApplyButtonInEditors = false;
// Get rid of the 'Add to toolbox' menu item
// https://github.com/surveyjs/editor/issues/195
editor.onDefineElementMenuItems.add(function(editor, options) {
options.items.splice(0, 1);
});
// Prevent users from creating multiple questions with the same name
editor.onPropertyValidationCustomError.add(function(editor, options) {
if(options.propertyName != "name") return;
var otherQuestionNames = editor.getAllQuestions().filter(function(question) {
return question != options.obj;
}).map(function(question) {
return question.name;
});
if (otherQuestionNames.indexOf(options.value) != -1) {
options.error = 'Question IDs must be unique in the survey. You already have a question named '+options.value;
}
});
// Prevent users from creating a question with too long a name
editor.onPropertyValidationCustomError.add(function(editor, options) {
console.log(options.propertyName);
if(options.propertyName != "name") return;
var questionName = options.value;
if (questionName.length > 60) {
options.error = 'The question ID is limited to 60 characters. Please use the question text below if you need more space.'
return;
}
if (options.obj.choices) {
var longestChoiceValue = Math.max.apply(null,
options.obj.choices.map(function(choice) {
return choice.itemValue.length;
})
);
if (longestChoiceValue > 60) {
options.error = 'Choice coding values are limited to 60 characters. Please use the display value if you need more space.'
return;
}
}
if (options.obj.rowsValue) {
var longestMatrixRow = Math.max.apply(null,
options.obj.rowsValue.map(function(row) {
return row.itemValue.length;
})
);
if (longestMatrixRow > 60) {
options.error = 'Matrix row codings are limited to 60 characters. Please use the display value if you need more space.'
return;
}
}
if (options.obj.columnsValue) {
var longestMatrixColumn = Math.max.apply(null,
options.obj.columnsValue.map(function(row) {
return row.itemValue.length;
})
);
if (longestMatrixColumn > 60) {
options.error = 'Matrix column IDs are limited to 60 characters. Please use the question text if you need more space.'
return;
}
}
});
}
// Set various SurveyEditor constants
Survey.Survey.cssType = "bootstrap";
SurveyEditor.defaultStrings.pe.isRequired = 'Required';
SurveyEditor.defaultStrings.pe.startWithNewLine = 'Start on new line';
SurveyEditor.defaultStrings.pe.visible = 'Visible';
SurveyEditor.defaultStrings.pe.tabs.html = 'Editor';
SurveyEditor.defaultStrings.pe.tabs.visibleIf = 'Display Logic';
SurveyEditor.defaultStrings.pe.name = 'Question ID *';
SurveyEditor.defaultStrings.pe.title = 'Question text';
SurveyEditor.defaultStrings.pe.value = 'Coding *';
SurveyEditor.defaultStrings.pe.text = 'Display';
SurveyEditor.defaultStrings.pe.hasOther = 'Add option for \'Other\'';
SurveyEditor.defaultStrings.pe.optionsCaption = 'Dropdown label (e.g. \'Choose...\')';
// Change the question type strings globally. This affects how they show up in the
// toolbox, as well as in the "Convert to X" option in the question menu
SurveyEditor.defaultStrings.qt.text = "Text Box";
SurveyEditor.defaultStrings.qt.comment = "Free Text Entry";
SurveyEditor.defaultStrings.qt.html = "Instruction text";
SurveyEditor.defaultStrings.qt.dropdown = "Multiple choice - Drop down";
SurveyEditor.defaultStrings.qt.radiogroup = "Multiple choice - Radio buttons";
SurveyEditor.defaultStrings.qt.checkbox = "Checkboxes (Multiple Answers)";
SurveyEditor.defaultStrings.qt.rating = "Numeric Scale";
SurveyEditor.defaultStrings.qt.matrix = "Matrix - Radio Buttons";
SurveyEditor.defaultStrings.qt.panel = "Section";
SurveyEditor.defaultStrings.survey.dropQuestion = "Please drop a question here from the toolbox on the left.";
// Get rid of choicesByUrl tab
Object.keys(SurveyEditor.SurveyQuestionEditorDefinition.definition).forEach(function(key) {
var section = SurveyEditor.SurveyQuestionEditorDefinition.definition[key];
if (section.tabs) {
var tabIndex = section.tabs.findIndex(function (tab) {
return tab.name=='choicesByUrl';
});
if (tabIndex > -1) {
section.tabs.splice(tabIndex, 1);
}
}
});
Survey.JsonObject.metaData.removeProperty("questionbase", "visible");
Survey.JsonObject.metaData.removeProperty("questionbase", "startWithNewLine");
var editorOptions = {
showEmbededSurveyTab : false,
showTestSurveyTab : true,
showJSONEditorTab : false,
showOptions: false,
showPropertyGrid: false,
};
// Set up the ckeditor for HTML (aka instruction text questions)
var CkEditor_ModalEditor = {
afterRender: function(modalEditor, htmlElement) {
var editor = CKEDITOR.replace(htmlElement);
editor.on('change', function() {
modalEditor.editingValue = editor.getData();
});
editor.setData(modalEditor.editingValue);
},
destroy: function(modalEditor, htmlElement) {
var instance = CKEDITOR.instances[htmlElement.id];
if (instance){
instance.removeAllListeners();
CKEDITOR.remove(instance);
}
}
};
SurveyEditor.SurveyPropertyModalEditor.registerCustomWidget("html", CkEditor_ModalEditor);
// Get the customized list of question types
function getQuestionTypes(editor) {
// The list of question types, most of which are just title overrides from the default
var questionTypes = [
{
name: 'panel',
},
{
name: 'html',
},
{
name: 'text',
},
{
name: 'comment',
},
{
name: 'dropdown',
},
{
name: 'radiogroup',
},
{
name: 'checkbox',
},
{
name: 'yesno',
title: 'Yes/No',
iconName: 'icon-dropdown',
json: {
type: 'dropdown',
name: 'q1',
choices: ['Yes', 'No']
}
},
{
name: 'truefalse',
title: 'True/False',
iconName: 'icon-dropdown',
json: {
type: 'dropdown',
name: 'q1',
choices: ['True', 'False']
}
},
{
name: 'rating',
},
{
name: 'matrix',
},
{
name: 'matrixdropdown'
}
];
function getDefaultQuestion(name) {
var question = editor.toolbox.itemsValue.filter(function(item) {
return item.name === name;
});
return question ? question[0] : null;
}
// Assemble a list of question types with all the relevant properties, by combining surveyjs's
// defaults with our overrides
var questions = questionTypes.map(function (questionType) {
var question = getDefaultQuestion(questionType.name) || {};
// This would be easier with Object.assign, but it's not available in IE
Object.keys(questionType).forEach(function (prop) {
question[prop] = questionType[prop];
});
return question;
});
return questions;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment