Changeset 183 for Dev/trunk/js/sequencerScripts.js
- Timestamp:
- 12/12/11 17:24:41 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
Dev/trunk/js/sequencerScripts.js
r182 r183 15 15 } 16 16 }, 17 survey: { // Properties of the loaded survey, if applicable (either this or the session tree above is filled in!) [THIS IS NOT CURRENTLY USED AND I SHOULD DELIBERATE ON WHAT VARIABLES TO PUT IN THIS TREE TO MAKE A FUNCTIONAL EDITOR THAT ALSO MATCHES THE DB FORMAT!] 18 title: "", // Title or the name of the survey 19 uid: "", // Uid of the survey 20 questions: { // Properties of the questions contained within this survey 21 uids: [], // An array of uids of the questions, in the order that they appear in the survey 22 upToDate: [] // Whether or not a certain question needs an update 23 } 24 }, 17 25 state: { // Operating state of the sequencer 18 26 editing: false, // Whether or not one of the contained child objects is currently being edited or in edit mode. Which one can be determined from the selectedStep property. … … 21 29 selectedStep: { // Properties of the currently selected step 22 30 uid: "", // UID of this step (STRING) 23 index: null 31 index: null // The 'index' of this step in the current sequencer view (NOT the pipeline!) (INTEGER) 24 32 } 25 33 }, 26 34 settings: { // Various settings to determine the workings of the sequencer 27 35 content: { // Properties related to the content view of the sequencer 28 contentType: "session", // Type of the loaded parent object 36 contentType: "session", // Type of the loaded parent object (STRING) 29 37 width: null, // Width of the viewing area (INTEGER) 30 38 height: null, // Height of the viewing area (INTEGER) … … 139 147 140 148 /* 141 * Description:142 * This function updates the visual elements in the sequencer content view to match the current state of the sequencer.session.pipeline property.143 * It queries the database for object properties via AJAX (returnStep/Display/.php), then inserts divider div's in between where needed.144 */149 * Description: 150 * This function updates the visual elements in the sequencer content view to match the current state of the sequencer.session.pipeline property. 151 * It queries the database for object properties via AJAX (returnStep/Display/.php), then inserts divider div's in between where needed. 152 */ 145 153 var content = document.getElementById("seqContentWrapper"); 154 var requestString, needsUpdating; 155 var args; 146 156 if (sequencer.state.loaded == false || sequencer.settings.efficientUpdating == false) { // This is the first update of the sequencer since page load, therefore it contains no previous steps 157 // Stop running this function if the pipeline does not contain any elements to draw 158 if (sequencer.session.pipeline.uids.length == 0 || !sequencer.session.pipeline.uids.length) return; 147 159 // First clear the entire content wrapper, just for safety and in case efficientUpdating is off 148 160 while (content.firstChild) { 149 161 content.removeChild(content.firstChild); 150 162 } 151 // Compose a request string - "uids=1,2,3&types=a,b,c"152 var requestString = "uids=";163 args = []; 164 needsUpdating = []; 153 165 for (var i = 0; i < sequencer.session.pipeline.uids.length; i++) { 154 requestString += sequencer.session.pipeline.uids[i]+","; 155 sequencer.state.numSteps++; 156 } 157 158 requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas 159 requestString += "&types="; 160 for (var j = 0; j < sequencer.session.pipeline.types.length; j++) { 161 requestString += sequencer.session.pipeline.types[j]+","; 162 } 163 requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas 164 newAjaxRequest(requestString, "returnStep.php", function(result) { 165 content.innerHTML = result.responseText; 166 updateDividers(); 167 sequencer.state.loaded = true; 168 for (var i = 0; i < sequencer.session.pipeline.upToDate.length; i++) { 169 sequencer.session.pipeline.upToDate.length[i] = true; 170 } 171 if (content.childNodes[0].nodeType == 3) content.removeChild(content.childNodes[0]); 166 args.push({ 167 uid: sequencer.session.pipeline.uids[i], 168 type: sequencer.session.pipeline.types[i] 169 }); 170 needsUpdating.push(new Array(i, sequencer.session.pipeline.uids[i], sequencer.session.pipeline.types[i])); 171 } 172 173 requestString = "args="+JSON.stringify(args); 174 newAjaxRequest(requestString, "returnObjectDisplay.php", function(result){ 175 content.removeChild(loadingGif); 176 insertNewObjects(result.responseText, needsUpdating); 172 177 }, true); 178 sequencer.state.loaded = true; 179 var loadingGif = document.createElement("div"); 180 loadingGif.innerHTML = "<img src='images/ui/ajax-loader-round.gif' style='float: left; margin:auto auto;' />"; 181 content.appendChild(loadingGif); 173 182 } 174 183 else { 175 // Pack together all needed updates in one request string, insert responseText.firstChild whenever sequencer.session.pipeline.upToDate[i] == false176 debugger;177 var needsUpdating = new Array();184 // This means that one or more steps are being added, not an entire pipeline's worth of them 185 needsUpdating = new Array(); 186 args = []; 178 187 // Add steps that need updating to the needsUpdating array (index, uid, type). 179 188 for (var i = 0; i < sequencer.session.pipeline.uids.length; i++) { 180 189 if (sequencer.session.pipeline.upToDate[i] == true) continue; 181 190 needsUpdating.push(new Array(i, sequencer.session.pipeline.uids[i], sequencer.session.pipeline.types[i])); 182 } 183 // Now that we have an array of the steps that need to be refreshed, we compose a requestString. 184 var requestString = "uids="; 191 args.push({ 192 uid: sequencer.session.pipeline.uids[i], 193 type: sequencer.session.pipeline.types[i] 194 }); 195 } 196 197 requestString = "args="+JSON.stringify(args); 198 newAjaxRequest(requestString, "returnObjectDisplay.php", function(result){ 199 insertNewObjects(result.responseText, needsUpdating); 200 }, true); 201 202 // Optional bit with the loading GIF 185 203 for (var i = 0; i < needsUpdating.length; i++) { 186 requestString += needsUpdating[i][1]+",";187 }188 if (requestString.slice(-1) == ",") requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas189 requestString += "&types=";190 for (var i = 0; i < needsUpdating.length; i++) {191 requestString += needsUpdating[i][2];192 }193 if (requestString.slice(-1) == ",") requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas194 195 // perform the AJAX request196 newAjaxRequest(requestString, "returnStep.php", function(result) {197 insertNewSteps(result.responseText, needsUpdating);198 }, true);199 } 200 204 var loadingDiv = document.createElement("div"); 205 loadingDiv.className = "displayStep loading"; 206 loadingDiv.innerHTML = "<img src='images/ui/ajax-loader-round.gif' />"; 207 if (needsUpdating[i][0] > sequencer.state.numSteps-1) { 208 content.appendChild(loadingDiv); 209 sequencer.state.numSteps++; 210 } 211 else { 212 content.replaceChild(loadingDiv, content.childNodes[i][0]*2); 213 } 214 } 215 updateDividers(); 216 // End optional 217 } 218 console.log(sequencer); 201 219 } 202 220 203 221 function loadSequencer() { 204 222 /* 205 206 207 208 223 * Description: 224 * Load data from hidden fields (put there by PHP), store them in the global var "sequencer" (as well as several initialization properties), 225 * then remove the hidden fields from the HTML document tree. 226 */ 209 227 210 228 // Load hidden fields and set required properties in global object var. 211 229 try { 212 230 // settings fields first 231 initEditor(); 232 233 // Content-related fields next 213 234 var fPipelineString = document.getElementById("pipelineStringField"); 214 235 var fPipelineTypes = document.getElementById("pipelineTypeField"); … … 239 260 hiddenInputs.parentNode.removeChild(hiddenInputs); 240 261 241 console.log(sequencer);242 262 // finally, run updateSequencer to refresh the visual display of the pipeline 243 263 … … 245 265 } 246 266 247 function insertNewSteps(responseText, needsUpdating) { 248 debugger; 267 function insertNewObjects(responseText, needsUpdating) { 268 var response = JSON.parse(responseText); 269 // For now I assume that only one type of element can be displayed in the editor at one time. Therefore, the type of response[0] is the type of all elements of response. 270 switch (response[0].type.toLowerCase()) { 271 case "survey": case "application": case "dashboard": 272 insertNewSteps(response, needsUpdating); 273 break; 274 case "question": 275 insertNewQuestions(response, needsUpdating); 276 break; 277 default: 278 break; 279 280 } 281 } 282 283 function insertNewSteps(response, needsUpdating) { 284 /* 285 * This is a test function displaying how to handle the visual object representation in solely javascript. 286 * Communication of relevant variables between PHP and JS happens in JSON format. 287 * PHP returns a JSON array of objects to be created by JS 288 * JS then loops through this array and creates DIVS to be inserted into the sequencer. 289 * These are inserted at the position needsUpdating gives us. 290 */ 249 291 var content = document.getElementById("seqContentWrapper"); 250 // Create a holder Div that converts the returned HTML to HTMLDivElements implicitly, so that they can be manipulated using DOM methods 251 var holderDiv = document.createElement("div"); 252 holderDiv.innerHTML = responseText; 253 // tempDiv will serve to 254 var tempDiv; 255 if (holderDiv.firstChild.nodeType == "3") holderDiv.removeChild(holderDiv.firstChild); 256 // Loop through 257 for (var i = 0; i < needsUpdating.length; i++) { 258 tempDiv = holderDiv.firstChild; 259 holderDiv.removeChild(holderDiv.firstChild); 260 if (needsUpdating[i][0] > sequencer.state.numSteps-1) { 261 // this step comes at the end of the pipeline 262 content.appendChild(tempDiv); 263 sequencer.state.numSteps++; 264 } 265 else { 266 content.replaceChild(tempDiv, content.childNodes[needsUpdating[i][0]*2]); 267 } 268 // The element is now updated, therefore set this flag in the global var 269 sequencer.session.pipeline.upToDate[needsUpdating[i][0]] = true; 270 } 271 272 // Then add or adjust dividers as needed! 273 updateDividers(); 274 } 275 276 function insertNewQuestion(responseText, needsUpdating) { 277 /* 278 * This is a test function displaying how to handle the visual object representation in solely javascript. 279 * Communication of relevant variables between PHP and JS happens in JSON format. 280 * PHP returns a JSON array of objects to be created by JS 281 * JS then loops through this array and creates DIVS to be inserted into the sequencer. 282 * These are inserted at the position needsUpdating gives us. 283 */ 284 285 var content = document.getElementById("seqContent"); 286 var response = eval(responseText); 292 // Remove optional loading images 293 for (var i = 0; i < content.childNodes.length; i++) { 294 if (hasClass(content.childNodes[i], "loading")) { 295 content.removeChild(content.childNodes[i]); 296 } 297 } 298 // End optional 287 299 288 300 for (var i = 0; i < response.length; i++) { 289 301 var tempDiv = document.createElement("div"); 290 tempDiv.id = response .id;302 tempDiv.id = response[i].uid; 291 303 tempDiv.className = "displayStep"; 304 var divImageContainer = document.createElement("div"); 305 divImageContainer.className = "displayStepIcon"; 306 divImageContainer.addEventListener("click", function(){ 307 clickStep(this.parentNode.id); 308 }, false); 292 309 var divImage = document.createElement("img"); 293 divImage.src = "./images/displayStep.png"; 294 divImage.addEventListener("Click", function(e){ 295 selectStep(this.id); 296 }, false); 297 tempDiv.appendChild(divImage); 310 divImage.src = "images/icons/"+response[i].type.toLowerCase()+".png"; 311 divImageContainer.appendChild(divImage); 312 tempDiv.appendChild(divImageContainer); 298 313 var divLabel = document.createElement("p"); 299 divLabel.innerHTML = response .title;314 divLabel.innerHTML = response[i].title; 300 315 tempDiv.appendChild(divLabel); 301 316 302 317 // This for needs to loop backwards so that the steps at the end of the pipeline are added or changed first. This keeps the childNodes index for all further steps intact. 303 for (var j = needsUpdating.length ; j >= 0; j--) {304 if (needsUpdating[j][1] != response .id) continue;318 for (var j = needsUpdating.length-1; j >= 0; j--) { 319 if (needsUpdating[j][1] != response[i].uid) continue; 305 320 if (needsUpdating[j][0] > sequencer.state.numSteps-1) { 306 321 content.appendChild(tempDiv); … … 309 324 content.replaceChild(tempDiv, content.childNodes[j][0]*2); 310 325 } 311 } 326 sequencer.session.pipeline.upToDate[needsUpdating[j][0]] = true; 327 } 328 } 329 330 updateDividers(); 331 } 332 333 function insertNewQuestions(response, needsUpdating) { 334 var content = document.getElementById("seqcContentWrapper"); 335 // Loop through returned question objects 336 for (var i = 0; i < response.length; i++) { 337 // Define the outer frame 338 var frameDiv = document.createElement("div"); 339 frameDiv.classname = "smallFrame question"; 340 frameDiv.id = response[i].uid; 341 var titleDiv = document.createElement("div"); 342 titleDiv.className = "smallTitle"; 343 var numberDiv = document.createElement("div"); 344 numberDiv.className = "listNumber"; 345 numberDiv.innerHTML = i.toString(); 346 titleDiv.appendChild(numberDiv); 347 titleDiv.innerHTML += response[i].uid; 348 frameDiv.appendChild(titleDiv); 349 350 // The frame now has a header bar 351 // On to the content frame 352 // Will use new "ce();" function, shorthand for document.createElement 353 354 var contentDiv = ce("div"); 355 contentDiv.className = "content"; 356 var questionBody = ce("p"); 357 questionBody.innerHTML = response[i].description; 358 var questionParamsDiv = ce("div"); 359 questionParamsDiv.className = "questionParamsView"; 360 questionParamsDiv.innerHTML = "Object type: "+response[i].type; 361 contentDiv.appendChild(questionBody); 362 contentDiv.appendChild(questionParamsDiv); 363 frameDiv.appendChild(contentDiv); 364 365 // And finally the controls div 366 var controlsDiv = ce("div"); 367 controlsDiv.className = "controls"; 368 var editButton = ce("input"); 369 var removeButton = ce("input"); 370 editButton.value = "Edit"; 371 removeButton.value = "Remove"; 372 editButton.className = "smallButton"; 373 removeButton.className = "smallButton"; 374 editButton.addEventListener("click", function(e){ 375 alert('Editing not yet supported!'); 376 }, false); 377 removeButton.addEventListener("click", function(e){ 378 alert('Removing not yet supported!'); 379 }, false); 380 controlsDiv.appendChild(editButton); 381 controlsDiv.appendChild(removeButton); 382 frameDiv.appendChild(controlsDiv); 383 384 // We now have a full question display DIV contained in the frameDiv variable. We should now add this to the sequencer content. 385 312 386 } 313 387 } … … 344 418 345 419 function savePipeline (confirmSave) { 420 debugger; 346 421 var answer; 347 422 if (confirmSave == true) { … … 355 430 var requestString = "uids="; 356 431 requestString += arrayToString(sequencer.session.pipeline.uids, ","); 432 requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas 357 433 requestString += "&types="; 358 434 requestString += arrayToString(sequencer.session.pipeline.types, ","); 435 requestString = requestString.slice(0, requestString.length - 1); // remove trailing commas 359 436 requestString += "&sessionUid="; 360 437 requestString += sequencer.session.uid; 361 newAjaxRequest(requestString, "savePipeline.php", function(result){ 438 console.log(requestString); 439 newAjaxRequest(requestString, "savesession.php", function(result){ 362 440 console.log(result.responseText); 363 441 }, true); … … 416 494 417 495 } 496 497 function initEditor() { 498 // load settings fields first 499 var fContentType = document.getElementById("sContentTypeField"); 500 var content = document.getElementById("seqContent"); 501 //sequencer.settings.content.contentType = fContentType.value.toLowerCase(); 502 sequencer.settings.content.contentType = "survey"; 503 504 var desiredWidth, desiredHeight; 505 506 //Then select settings from a few presets 507 switch (sequencer.settings.content.contentType) { 508 case "session": 509 sequencer.settings.content.orientation = "h"; 510 sequencer.settings.content.width = 800; 511 sequencer.settings.content.height = 125; 512 content.style.width = sequencer.settings.content.width+"px"; 513 content.style.height = sequencer.settings.content.height+"px"; 514 break; 515 case "survey": 516 sequencer.settings.content.orientation = "v"; 517 sequencer.settings.content.width = 600; 518 sequencer.settings.content.height = "auto"; 519 content.style.width = sequencer.settings.content.width+"px"; 520 content.style.height = sequencer.settings.content.height+"px"; 521 break; 522 default: 523 break; 524 } 525 }
Note: See TracChangeset
for help on using the changeset viewer.