////////////////////// /* HELPER FUNCTIONS */ ////////////////////// function hasClass(ele,cls) { if (ele.className) return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); } function addClass(ele,cls) { if (!this.hasClass(ele,cls)) ele.className += " "+cls; } function removeClass(ele,cls) { if (hasClass(ele,cls)) { var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); ele.className=ele.className.replace(reg,' '); } } ////////////////////////// /* END HELPER FUNCTIONS */ ////////////////////////// ////////////////////// /* CREATE FUNCTIONS */ ////////////////////// function createQuestionEditor() { // Outer div var editorElement = ce("div"); this.className = "smallFrame questionEditor"; editorElement.id = sequencer.state.selectedObject.uid; // Header var titleDiv = ce("div"); titleDiv.className = "smallTitle"; var numberDiv = ce("div"); numberDiv.className = "listNumber"; numberDiv.innerHTML = "4"; var nameSpan = ce("span"); nameSpan.innerHTML = "New question"; titleDiv.appendChild(numberDiv); titleDiv.innerHTML += "Editing: "; titleDiv.appendChild(nameSpan); editorElement.appendChild(titleDiv); //Content area var contentDiv = ce("div"); contentDiv.className = "content"; var bodyText = createNewElement("textarea", null, "qBodyTextField", "qBodyTextField", null); bodyText.value = "Question body text goes here"; // The dynamic questionParams div, where all the control elements and inputs will be located var questionParams = ce("div"); questionParams.className = "questionParams"; contentDiv.appendChild(bodyText); var qIdentField = createNewElement("input", "text", "qIdentField", "questionParamField", null); var qIdentField_lbl = createNewInputLabel("Question code:","qIdentField", "l"); questionParams.appendChild(qIdentField_lbl); questionParams.appendChild(qIdentField); var qTypeField = createNewElement("select", null, "qTypeField", "questionParamField", null); var qTypeField_lbl = createNewInputLabel("Answer type:","qTypeField", "l"); questionParams.appendChild(qTypeField_lbl); questionParams.appendChild(qTypeField); qTypeField.addEventListener("change", function(){ debugger; selectAnswerType(); }, false); // Add the select options. Do this in a block scope to prevent the o1 var from messing things up. // Also helps in structuring code. { var o1 = ce("option"); o1.value = null; o1.text = ""; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "int"; o1.text = "Integer"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "scale"; o1.text = "Scale"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "choice"; o1.text = "Multiple choice"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "text"; o1.text = "Text"; qTypeField.appendChild(o1); } contentDiv.appendChild(questionParams); editorElement.appendChild(contentDiv); // Controls bar var controlsDiv = ce("div"); controlsDiv.className = "controls"; var btnDiscard = createNewElement("input", "button", "btnDiscard", null, "Discard"); var btnSave = createNewElement("input", "button", "btnSave", null, "Save"); controlsDiv.appendChild(btnDiscard); controlsDiv.appendChild(btnSave); btnSave.addEventListener("click", function(){ swapQuestionState(true); }, false); btnDiscard.addEventListener("click", function(){ swapQuestionState(false); }, false); editorElement.appendChild(controlsDiv); return editorElement; } function swapQuestionState(save) { // Function that replaces a question display with the question editor, or vice versa. if (sequencer.state.editing == false) { // Start editing sequencer.state.editing = true; var questionElement = ge(sequencer.state.selectedObject.uid); // test var editor = new QuestionEditor(); editor.init(); // end test //var editorElement = createQuestionEditor(); var content = ge("seqContentWrapper"); content.replaceChild(editor.element, questionElement); } else { if (save) { if (save == true) { alert("Saving shit yo!"); // User is done editing // 1. Create the edited question in db (createObject.php), then set the proper properties (saveObject.php) // 2. Revert back to question display } else { // Anders discard gewoon alles en haal de question display weg. ge("seqContentWrapper").removeChild(ge(sequencer.state.selectedObject.uid)); } } } } ////////////////////////// /* END CREATE FUNCTIONS */ ////////////////////////// var qUID, parentObjectUID, qName, qTag, qType, qAnswerLength; function selectAnswerType(){ var selectBox = document.getElementById("qTypeField"); if (selectBox.value != undefined && selectBox.value != "") { qType = selectBox.value; } else { return; } removeWrongAnswerFields(selectBox); switch (qType) { case "int": selectIntType(); break; case "scale": selectScaleType(); break; case "choice": //selectChoiceType(); break; case "text": //selectTextType(); break; default: alert("Invalid answer type selected!"); break; } } function createNewElement(tag, type, id, cl, value) { // This is a double of the ce() alias function in generalScripts.js. // It allows for more specific creation of elements on one line, // instead of 5 subsequent lines of code defining tag, id, class, value, etc... // This is handy when doing creation-heavy operations such as adding inputs //!!! Since this is defined in questionEditorScripts.js, it should only be used in this context. //!!! Use ce() whenever possible, since it's included on every page and works faster. var newElement = document.createElement(tag); if (type != undefined) newElement.type = type; if (id != undefined) newElement.id = id; if (cl != undefined) newElement.className = cl; if (value != undefined) { newElement.value = value; newElement.text = value; } return newElement; } function createNewInputLabel(text, target, align) { var newLabel = document.createElement("label"); if (target) newLabel.setAttribute("for",target); if (align) newLabel.className = "questionParamLabel "+align+"Align"; else newLabel.className="questionParamLabel"; newLabel.innerHTML = text; return newLabel; } function removeWrongAnswerFields(el) { while (el.nextSibling) { el.parentNode.removeChild(el.nextSibling); } } function updateIdentifier() { var identField = document.getElementById("questionIdentifierField"); if (identField.value == undefined && identField.value == "") { return; } var headerField = document.getElementById("header_identifier"); headerField.innerHTML = identField.value; } /////////////////// /* INT SELECTION */ /////////////////// function selectIntType() { var selectBox = document.getElementById("questionType"); var content = document.getElementById("questionEditor_questionParams"); // Add minimum value input var minValueBox = createNewElement("input","text","minValueBox", "questionParamField", null); var minValueBoxLabel = createNewInputLabel("Minimum value:", "minValueBox"); addClass(minValueBoxLabel, "formLineBreak"); content.appendChild(minValueBoxLabel); content.appendChild(minValueBox); // Add maximum value input var maxValueBox = createNewElement("input", "text", "maxValueBox", "questionParamField", null); var maxValueBoxLabel = createNewInputLabel("Maximum value:","maxValueBox"); addClass(maxValueBoxLabel, "formLineBreak"); content.appendChild(maxValueBoxLabel); content.appendChild(maxValueBox); } ///////////////////// /* SCALE SELECTION */ ///////////////////// function selectScaleType() { // I heard you like walls of text! var content = document.getElementById("questionEditor_questionParams"); // Add number of choices input var numChoicesBox = createNewElement("select", null, "numChoicesBox","questionParamField",null); var numChoicesBoxLabel = createNewInputLabel("Scale size:","numChoicesBox"); for (var i = 0; i < 10; i++) { var option = createNewElement("option"); option.text = i+1; option.value = i+1; numChoicesBox.appendChild(option); } addClass(numChoicesBoxLabel, "formLineBreak"); content.appendChild(numChoicesBoxLabel); content.appendChild(numChoicesBox); // Add legends enabled input var legendsEnabledCheckBox = createNewElement("input","checkbox","legendsEnabledCheckbox","questionParamField",null); var legendsEnabledCheckBoxLabel = createNewInputLabel("Enable legends","legendsEnabledCheckBox"); addClass(legendsEnabledCheckBoxLabel, "formLineBreak"); content.appendChild(legendsEnabledCheckBoxLabel); content.appendChild(legendsEnabledCheckBox); // Add legend labels boxes var upperLegendBox = createNewElement("input","text","upperLegendBox","questionParamField"); var lowerLegendBox = createNewElement("input","text","lowerLegendBox","questionParamField"); var lowerLegendBoxLabel = createNewInputLabel("Lower legend","lowerLegendBox"); var upperLegendBoxLabel = createNewInputLabel("Upper legend","upperLegendBox"); addClass(lowerLegendBoxLabel,"formLineBreak"); content.appendChild(lowerLegendBoxLabel); content.appendChild(lowerLegendBox); addClass(upperLegendBoxLabel,"formLineBreak"); content.appendChild(upperLegendBoxLabel); content.appendChild(upperLegendBox); // Disable these boxes, since the checkbox is unchecked by default lowerLegendBox.disabled = true; upperLegendBox.disabled = true; if (legendsEnabledCheckBox.addEventListener) { legendsEnabledCheckBox.addEventListener("click", toggleScaleLegends, true); } } function toggleScaleLegends() { var content = document.getElementById("questionEditor_questionParams"); var checkbox = document.getElementById("legendsEnabledCheckbox"); var upperLegendBox = document.getElementById("upperLegendBox"); var lowerLegendBox = document.getElementById("lowerLegendBox"); if (checkbox.checked == true) { upperLegendBox.disabled = false; lowerLegendBox.disabled = false; } else { upperLegendBox.disabled = true; lowerLegendBox.disabled = true; } } /////////////////////////////// /* MULTIPLE CHOICE SELECTION */ /////////////////////////////// function selectChoiceType() { var selectionBox = document.getElementById("questionType"); var content = document.getElementById("questionEditor_questionParams"); } function resizeTextArea() { var textArea = document.getElementById("questionEditor_bodyText"); if (document.getElementById("hiddenScalingDiv")) { var hiddenDiv = document.getElementById("hiddenScalingDiv"); } else { var hiddenDiv = document.createElement("div"); hiddenDiv.style.visibility = "hidden"; textArea.appendChild(hiddenDiv); } debugger; hiddenDiv.innerHTML = ""; var userText = textArea.firstChild; alert(userText); } //TEST FUNCTIONS /* * These functions are an attempt at making editors class based, for easier organisation and parameter storage and access. * It prevents having to add more question-specific clutter to the sequencer object */ function QuestionEditor() { // Properties this.uid = null; this.element = null; this.paramsElement = null; // Basic functionality this.setValues = function(arguments) { // Query question information from database, then fill element fields with correct information. } this.init = function() { // Outer div this.element = ce("div"); this.element.className = "smallFrame questionEditor"; this.element.id = sequencer.state.selectedObject.uid; this.uid = sequencer.state.selectedObject.uid; // Header var titleDiv = ce("div"); titleDiv.className = "smallTitle"; var numberDiv = ce("div"); numberDiv.className = "listNumber"; numberDiv.innerHTML = "4"; var nameSpan = ce("span"); nameSpan.id = "qTitleField"; nameSpan.innerHTML = "New question"; titleDiv.appendChild(numberDiv); titleDiv.innerHTML += "Editing: "; titleDiv.appendChild(nameSpan); this.element.appendChild(titleDiv); //Content area var contentDiv = ce("div"); contentDiv.className = "content"; var bodyText = createNewElement("textarea", null, "qBodyTextField", "qBodyTextField", null); bodyText.value = "Question body text goes here"; // The dynamic questionParams div, where all the control elements and inputs will be located var questionParams = ce("div"); this.paramsElement = questionParams; questionParams.className = "questionParams"; contentDiv.appendChild(bodyText); var qIdentField = createNewElement("input", "text", "qIdentField", "questionParamField", null); var qIdentField_lbl = createNewInputLabel("Question code:","qIdentField", "l"); questionParams.appendChild(qIdentField_lbl); questionParams.appendChild(qIdentField); var qTypeField = createNewElement("select", null, "qTypeField", "questionParamField", null); var qTypeField_lbl = createNewInputLabel("Answer type:","qTypeField", "l"); questionParams.appendChild(qTypeField_lbl); questionParams.appendChild(qTypeField); qTypeField.addEventListener("change", function(){ debugger; selectAnswerType(); }, false); // Add the select options. Do this in a block scope to prevent the o1 var from messing things up. // Also helps in structuring code. { var o1 = ce("option"); o1.value = null; o1.text = ""; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "int"; o1.text = "Integer"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "scale"; o1.text = "Scale"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "choice"; o1.text = "Multiple choice"; qTypeField.appendChild(o1); o1 = ce("option"); o1.value = "text"; o1.text = "Text"; qTypeField.appendChild(o1); } contentDiv.appendChild(questionParams); this.element.appendChild(contentDiv); // Controls bar var controlsDiv = ce("div"); controlsDiv.className = "controls"; var btnDiscard = createNewElement("input", "button", "btnDiscard", null, "Discard"); var btnSave = createNewElement("input", "button", "btnSave", null, "Save"); controlsDiv.appendChild(btnDiscard); controlsDiv.appendChild(btnSave); btnSave.addEventListener("click", function(){ swapQuestionState(true); }, false); btnDiscard.addEventListener("click", function(){ swapQuestionState(false); }, false); this.element.appendChild(controlsDiv); var request = { "uid": this.uid, "type": "Question" } var requestString = "args="+JSON.stringify(request); newAjaxRequest(requestString, "returnObjectDisplay.php", function(result){ // Fill in the element with the correct values // Result is sent to setValues in object form already, perhaps better idea to send in string format and parse within the target method? this.setValues(JSON.parse(result.responseText)); }, true); } this.submit = function() { var request = { "title": ge("qTitleField").value, "type": ge("qTypeField").value } newAjaxRequest(requestString, "createObject.php", function(result){ // Display a success message, or throw an error. }, true); } // Updating input fields this.selectAnswertype = function () { // Switch statement, call this.type_x where x is the relevant answer type. // For all this.type_X funtions: // Use the createNewElement and createNewInputLabel methods to add controls or input fields. // Input field convention: class = questionParamField, id = qTypeField / qScaleSize, etc... // Input label class: "l" or "r" depending on alignment with respect to parent ("for") input element. // Important: use the this.paramsElement to access the questionParams div! // To fully make use of this class-based approach, the editor should be added to a global variable. This global variable should be removed on page unload! } this.type_Scale = function () { } this.type_Integer = function () { } this.type_Text = function () { } this.type_Choice = function() { } } function newEditor() { // Get variables, ofc not null... var arguments = null; var editor = new QuestionEditor(arguments); editor.setValues(arguments); ge("seqContentWrapper").appendChild(editor.element); // Etc. We can put the switchModes() command in here as well, I'd say... // Or should that be in the QuestionEditor class? That's probably better, since it has direct access to all the internal variables. } function startEditingQuestion(uid) { if (sequencer.state.editing == true) return; var element = ge(uid); var editor = new QuestionEditor(); var newElement = editor.createElement(); // Query parameters editor.setValues(parameters); element.parentNode.replaceChild(newElement, element); sequencer.state.editing = true; }